首页 > 其他分享 >Scala学习之旅-对Option友好的flatMap

Scala学习之旅-对Option友好的flatMap

时间:2024-09-16 09:55:33浏览次数:13  
标签:flatMap Option Scala Some Person println name

聊点什么

  • Option
  • flatMap vs. Option

Option的作用

在 Java/Scala中, Optional/Option(本文还是以scala代码为例) 是用来表示某个对象存在或者不存在,也就是说, Option是某个类型 T的 Wrapper,

  • 如果 T != null, Option(T).isDefined == true
  • 如果 T == null, Option(T).isEmpty == true

有了Option这层金刚罩, null被包裹住了,应用代码不必直接处理它,也就极大避免了 NullPointerException出现的可能性。Java 11 document 如下:

the purpose of Optional is to provide a return type that can represent the absence of value in scenarios where returning null might cause unexpected errors, like the infamous NullPointerException.

为什么有了Option就能避免了NullPointerException? 且看

Option vs. null

在没有Option之前,代码如果要表示某个值不存在,一般不得不返回null, 但是应用对null的检查,是必要的, 但不是必须的, 所以稍有不慎,就会有NullPointerException发生。

有了Option之后, 是在编译期显示要求去 get Option内的 value, 这就给了应用处理不存在的机会. 请看如下示例:


private val optionSeq = Seq(
  Person("Apple", Some(1)),
  Person("Boy"),
  Person("Carlo", Some(2)),
  Person("Doggy"),
  Person("Egg"),
  Person("Frog", Some(3))
)

  /**
   * Option vs. null
   */
  private def findPersonByNameWithNull(name: String): Person = {
    for (p <- optionSeq) {
      if (p.name == name)
        return p
    }
    null
  }

  private def findPersonByNameWithOption(name: String): Option[Person] = {
    for (p <- optionSeq) {
      if (p.name == name)
        return Some(p)
    }
    None
  }

  try {
    findPersonByNameWithNull("NoName").name
  } catch {
    case e: NullPointerException => println(s"Got NullPointerException: ${e.getMessage}")
    case ex: Exception => println(ex)
  } // Got NullPointerException: Cannot invoke "ddu.scala.articles.FlatMapTips$Person.name()" because the return value of "ddu.scala.articles.FlatMapTips$.findPersonByNameWithNull(String)" is null

  println(findPersonByNameWithOption("NoName").getOrElse(Person(name = "NotFound")).name) // NotFound

在上面的例子中我们可以看到, 在应用调用 findPersonByNameWithOption("NoName")得到Option之后,应用有机会处理OptiongetOrElse(Person(name = "NotFound"))来赋予默认值。

flatMap vs. Option

在Scala中, 特别是在流式编程中, Option被用的越来越多了, Option虽然可以避免NullPointerException,但是由于需要应用代码显示处理,大量的match ... case... or get ... else...
也是非常繁琐。让我们看看Scala的flatMap是如果友好得处理Option的吧。

  private val optionSeq = Seq(
    Person("Apple", Some(1)),
    Person("Boy"),
    Person("Carlo", Some(2)),
    Person("Doggy"),
    Person("Egg"),
    Person("Frog", Some(3))
  )

  /**
   * Tip.1 flatMap 会忽略掉 None
   *
   * 下面两段代码是等价的都输出 123
   *  显然用 flatMap 更加简洁
   */

  optionSeq
    .flatMap(_.age)
    .foreach(println)

  optionSeq
    .map(_.age)
    .filter(_.isDefined)
    .map(_.get)
    .foreach(println)


  /**
   * Tip.2 flatMap 对 Option 对象相当于 match case
   *
   * 输出示例:
   * flatMapName: GOD, matchCaseName: GOD
   * flatMapName: NO_NAME, matchCaseName: NO_NAME
   *
   */

  private def theName(name: Option[String]): Unit = {
    val flatMapName = name.flatMap(name => Some(name.toUpperCase())).getOrElse("NO_NAME")
    val matchCaseName = name match {
      case Some(name) => name.toUpperCase
      case _ => "NO_NAME"
    }
    println(s"flatMapName: $flatMapName, matchCaseName: $matchCaseName")
  }

  theName(Some("God"))
  theName(None)

完整示例代码


package ddu.scala.articles

object FlatMapTips extends App {

  case class Person(name: String, age: Option[Int] = None)

  private val optionSeq = Seq(
    Person("Apple", Some(1)),
    Person("Boy"),
    Person("Carlo", Some(2)),
    Person("Doggy"),
    Person("Egg"),
    Person("Frog", Some(3))
  )

  /**
   * Tip.1 flatMap 会忽略掉 None
   *
   * 下面两段代码是等价的都输出 123
   *  显然用 flatMap 更加简洁
   */

  optionSeq
    .flatMap(_.age)
    .foreach(println)

  optionSeq
    .map(_.age)
    .filter(_.isDefined)
    .map(_.get)
    .foreach(println)


  /**
   * Tip.2 flatMap 对 Option 对象相当于 match case
   *
   * 输出示例:
   * flatMapName: GOD, matchCaseName: GOD
   * flatMapName: NO_NAME, matchCaseName: NO_NAME
   *
   */

  private def theName(name: Option[String]): Unit = {
    val flatMapName = name.flatMap(name => Some(name.toUpperCase())).getOrElse("NO_NAME")
    val matchCaseName = name match {
      case Some(name) => name.toUpperCase
      case _ => "NO_NAME"
    }
    println(s"flatMapName: $flatMapName, matchCaseName: $matchCaseName")
  }

  theName(Some("God"))
  theName(None)

  /**
   * Option vs. null
   */
  private def findPersonByNameWithNull(name: String): Person = {
    for (p <- optionSeq) {
      if (p.name == name)
        return p
    }
    null
  }

  private def findPersonByNameWithOption(name: String): Option[Person] = {
    for (p <- optionSeq) {
      if (p.name == name)
        return Some(p)
    }
    None
  }

  try {
    findPersonByNameWithNull("NoName").name
  } catch {
    case e: NullPointerException => println(s"Got NullPointerException: ${e.getMessage}")
    case ex: Exception => println(ex)
  } // Got NullPointerException: Cannot invoke "ddu.scala.articles.FlatMapTips$Person.name()" because the return value of "ddu.scala.articles.FlatMapTips$.findPersonByNameWithNull(String)" is null

  println(findPersonByNameWithOption("NoName").getOrElse(Person(name = "NotFound")).name) // NotFound
  println(findPersonByNameWithOption("NoName").get.name) // NotFound
}

标签:flatMap,Option,Scala,Some,Person,println,name
From: https://blog.csdn.net/robbywt/article/details/142251853

相关文章

  • Scala学习之旅-Class Constructor
    在生活和学习中,懂得拿捏对象是非常重要的!本篇我们用Scala和Java来定义一个类,一起来看看Scala在搞定对象方面有啥厉害的地方。ScalaclassclassPerson(valname:String,varage:Int){overridedeftoString:String={s"$name'sageis$age"}defappl......
  • 【Scala入门学习】Scala的方法和函数
    1.方法在scala中的操作符都被当成方法存在,比如说+、-、*、/1+2就是1.+(2)的调用,2.0是doule类型,强调用Int类型的写法为1.+(2:Int)1.1方法的声明和使用定义方法的语法:def方法名([变量:变量类型,变量:变量类型]):返回值类型={方法体}其中:在scala中,方法里面的最后一个表......
  • 【Scala入门学习】基本数据类型和变量声明
    1.基本数据类型scala的基本类型有9种:Byte、Char、Short、Int、Long、Float、Double、Boolean、UnitScala中没有基本数据类型的概念,所有的类型都是对象。AnyVal:代表所有基本类型。AnyRef:代表所以引用类型,包括Scalaclass和Javaclass。Any:是所有类的超类。如果不知......
  • scala语言是什么?
    Scala是一种基于Java虚拟机(JVM)的编程语言。 它融合了面向对象编程和函数式编程的特点。在面向对象方面,它有着完善的类、对象等概念体系;在函数式编程方面,函数可以像数据一样被传递和操作。 Scala具有以下特点: 代码简洁性方面 -支持类型推断,减少了代码中类型声明的......
  • Options
    usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.DependencyInjection.Extensions;usingMicrosoft.Extensions.Options;usingMicrosoft.Extensions.Primitives;usingSystem.Diagnostics.CodeAnalysis;usingSystem.Reflection;namespac......
  • C++17新特性探索:拥抱std::optional,让代码更优雅、更安全
    std::optional背景在编程时,我们经常会遇到可能会返回/传递/使用一个确定类型对象的场景。也就是说,这个对象可能有一个确定类型的值也可能没有任何值。因此,我们需要一种方法来模拟类似指针的语义:指针可以通过nullptr来表示没有值。解决方法是定义该对象的同时再定义一个附加的......
  • Scala
    浮点数精度问题的解决 Scala的if语句   Scala的IDEA环境搭建   ......
  • Why system logging "kernel: tcp_parse_options: Illegal window scaling value 15 >
    环境Linux问题在var/log/messages文件中发现以下日志。Oct621:01:05mplttaxsx101kernel:tcp_parse_options:Illegalwindowscalingvalue15>14received.Oct621:01:05mplttaxsx101kernel:tcp_parse_options:Illegalwindowscalingvalue15>14......
  • Scala的数据类型与运算的应用
    在Scala中,数据类型和运算的应用非常广泛,它们是构建程序的基础。以下是关于这些内容的详细介绍: 基本数据类型:Scala提供了八种基本数据类型,包括Byte、Char、Short、Int、Long、Float、Double和Boolean。这些类型涵盖了数值、字符、布尔值等不同的数据类型。例如,使用vali=1......
  • 在IDEA中安装Scala插件
    先打开IDEA[文件]右键,[设置] 点击[插件],输入Scala并搜索,点击[安装]安装完成后点击[重启IDE]  重启后,[文件]右键,[新建],[项目] 点击[创建]点击[此窗口]或[新窗口]  [文件]右键,点击[项目结构]点击[全局库],点击[+]号  选择[ScalaSDK] 选择第一个,点击[......