zoukankan      html  css  js  c++  java
  • Scala不使用null 而使用Option,None,Some的好处

    刚接触Scala时就很奇怪, 为什么Java已经有null了,却偏偏还要弄出个None

    后来依然我行我素在Scala里使用null, 结果就是经常被NullPointerException折磨得阴魂不散...于是终于领悟.

    WHY?

    举个例子:

    假设有一个简单的对象A, A类里有2个Int属性, a和b

    case class A(val a : Int, val b : Int)
    

      

    然后有这么一个map

    val map1 = Map(1 -> A(111, 1111), 2 -> A(222, 2222), 3 -> A(333, 3333))
    

      

    然后有这么一段业务逻辑需要从这个map中取出其中2个A,并且拿他们的a属性相加

    val key1 :Int = //其他地方给我的值,我也不知道具体是多少
    val key2 :Int = //其他地方给我的值,我也不知道具体是多少
    println(map1.getOrElse(key1, null).a + map1.getOrElse(key2, null).a) //111 + 报 NullPointerException
    

      

    那么恭喜你, 遇到了NullPointerException. 为什么? 假设别人给你的key1=1, key2=4, 那么map1.getOrElse(key2, null).a 将会报出NullPointerException

    不仅这样, 你在报错输出中得到的抛出异常的代码就是上面第3行println这句, 单从日志来看你根本无法知道别人给你有问题的是key1还是key2

    所以在Java中, 一个对象的引用, 已经被默认为可能会是null了, 但有时候敲代码时会极度容易犯错, 同时就会信心满满的认为 "这个对象怎么可能是null呢?",

    可是一旦真的是null, 只能庆幸这个报错不是出现在生产环境中了.

    HOW?

    那么我们如何在scala里避免使用null?

    很简单, scala提供的Option,和None就是个非常好的设计! 有多好? 代码撸起

    像scala List里, 如果我要查找一个list里面符合要求的元素, 不一定能找得到, 所以返回的是一个Option[元素类型]

        val list = List(1 ,2, 3, 4)[Int]
        val found : Option[Int] = list.find(_ > 5)
        found match {
          case None => //由你决定找不到怎么办
          case Some(value) =>//由你决定找到想要的value值怎么办
        }
    

      

    所以对于之前的需求,一段业务逻辑需要从这个map中取出其中2个A,并且拿他们的a属性相加

        //可以先用get, get 出来的东西是个 Option[A], 再做判断
        var finalResult = 0 //0默认值
        (map1.get(key1), map2.get(key2)) match {
          case (Some(value1), Some(value2)) =>
            //都找到了, 可以愉快的相加了
            finalResult = value1.a + value2.a
          case (None, Some(value2)) =>
            //第一个找不到, 第二个找到了怎么办的代码
          case (Some(value1), None) =>
            //第一个找到了, 第二个找不到怎么办的代码
          case _=>
            //其他情况
        }
    

      

    scala的Map可以使用get方法获取对象, 获取出来的是一个 Option[对象类型], 为什么不像java那样直接取出null? 这里就是因为要考虑到取不出来东西的情况.

    所以Option存在的意义, 就是为了在代码中注明, 让大家一看就知道: "这个东西可能是空的! 你们用的时候给我小心点" 这样的暗示.

    有了这个暗示, 你可就不能随意取出option里面的东西了, 警醒你每次使用, 都要先判断. isEmpty 或是 nonEmpty

    当然更优雅的写法就像上面那样, 使用匹配模式, 在出现多种情况之间选择做什么事情. 

    Option还提供了其他很骚的用法. 你甚至可以把Option当成是一个只能容纳1个元素的容器来看待.

    假设又有那么一个需求, 我有一个Option[A], 我不确定这个Option是否==None, 但我想要尝试取出里面的A对象的a属性, 如果没有的话就给我个0吧, 那么代码可以这么写

        val aOpt : Option[A] = //我不确定他是None, 还是Some(A)反正别人给我的
        
        //就这么简单粗暴
        val myVal1 :Int = if(aOpt.isEmpty) 0 else aOpt.get.a
        
        //也可以先把Option[A]map成Option[Int](这里是Int,因为是A的a属性的类型), 再使用getOrElse 取不到就给个自己定的默认值
        val myVal2 :Int = aOpt.map(aObj => aObj.a).getOrElse(0)
    

      

    还有另一个需求, 我想知道这个Option[A] 里的A对象的a属性是否等于100

    val has100 :Boolean = aOpt.exists(aObj => aObj.a == 100)
    

      

    Final

    已经有不少文章吐槽null的设计是多么糟糕: 传送门请看:http://www.php230.com/weixin1446428231.html

    既然scala已经考虑到并提供优雅代码的解决方式. 那以后可以少在scala里给用null了.

  • 相关阅读:
    用BAT使用FTP命令上传文件
    BAT自动复制最新插件至运行程序
    requests模块源码阅读总结
    Lucene查询语法汇总
    Ansible scp Python脚本
    4.2 rust 命令行参数
    4.1 python中调用rust程序
    冒泡排序
    Golang开发命令行工具之flag包的使用
    MySQL基于Binlog的数据恢复实战
  • 原文地址:https://www.cnblogs.com/drwong/p/8327359.html
Copyright © 2011-2022 走看看