音乐: Artist:创作音乐的个人或团队 name:艺术家名字 members:乐队成员 origin:乐队来自哪里 Track:(专辑中的一支曲目) name:曲目名称 Album:专辑 name:专辑名称 tracks:专辑上曲目列表 musicans:参与创作本专辑的艺术家列表

    :::info lambda表达式表现形式
    image.png

    1. 表达式不包含参数,使用空括号()表示没有参数
    2. 表达式包含一个参数,可以省略参数的括号
    3. 表达式的主体不仅可以是一个表达式,而且也可以是一段代码块,使用大括号{}将代码块括起来。
    4. 表达式也可以包含多个参数的方法
    5. 表达式的参数类型由编译器推断出来,当然不错,但为了更高的可读性,建议显示声明

    lambda表达式 无法使用非终态(非final)类型的变量。强行使用编译器会报错。

    :::

    集合上的数据过滤

    filter : :::success image.png
    filter刻画出了Stream,但没有产生新的集合,向filter这样只描述Stream不产生新集合的方法被称为惰性求值方法。
    image.png
    而像count最终会从Stream产生值的方法叫作及早求值方法。 :::

    :::warning 及早求值与惰性求值判断:
    只需要看返回值,如果返回值是Stream则为惰性求值,如果返回值是另一个值或者为null则为及早求值。
    为什么要区分及早求值与惰性求值:
    只有在对需要什么样的结果和操作有更多的了解,才能更有效的进行计算。 :::

    常用的流操作

    • collect(toList()) 由Stream里的值生成一个列表,是及早求值
      • Stream的of方法使用一组初始值生成新的Stream
    • map 是一个将一种类型值转换成另外一种类型的函数。可以理解成一种映射,而不是常见的key-value的数据结构。
      • 传给map的lambda表达式只接受一个参数,参数和返回值不必属于同一种类型,但lambda表达式必须是Function接口的一个实例。如图3-4所示,Function接口是只包含一个参数的函数接口。
      • image.pngimage.png
    • filter 遍历数据并检查其中的元素。

      该模式的核心思想是保留Stream中的一些元素而过滤掉其他元素。和map很像,filter同样接收一个函数「方法」作为参数,该函数用lambda表达式表示,也即是Predicate接口。由于此方法与if语句的功能相同,因此其返回值只有true或false。返回的true的元素被保留。

      • image.pngimage.png
    • flatmap 可用Stream替换值,然后将多个Stream连接成一个Stream
      • image.png

        实例参考 image.png 调用stream方法,将每个list转为stream对象,剩下的交给flatMap处理。flatMap方法相关函数接口和map一样,都是Function接口,只是方法返回值限定为stream

    • max和min 求最大值和最小值
      • 空Stream的max方法,返回Optional对象,它代表一个可能存在也可能不存在的值,如果Stream为空,那么该值不存在;如果不为空,则该值存在。
    • reduce
      • reduce操作可以实现从一组值生成一个值
      • image.png
    • 整合操作 :::info image.png
      1.Album类有个getMusicians方法,该方法返回一个Stream对象,包含整张专辑中所有的表演者;
      2.使用filter方法对表演者进行过滤,只保留乐队;
      3.使用map方法将乐队映射为其所属国家;
      4.使用collect(Collectors.toList())方法将国籍放入一个列表。

    实例:从专辑中获取音乐时长大于一分钟的曲目名称
    image.png :::

    • 高阶函数 :::info 高阶函数:指接受另外一个函数作为参数,或返回一个函数的函数。
      如何辨认:看函数签名,如果函数参数列表中包含函数接口,或该函数返回一个函数接口。比如map函数就是高阶函数。 :::

    :::success 为了减少基本类型与对象类型的装箱、拆箱的性能消耗,Stream类的某些方法对基本类型和装箱类型做了区分:

    在java8中,只对整型、长整型、双浮点数做了特殊处理(因为这三种类型在计算方面用的最多,特殊处理后性能提高最明显)

    对基本类型做特殊处理的方法在命名上有明确的规范。如果方法返回类型为基本类型,则在基本类型上加To,例如:图4-1:ToLongFunction
    image.png
    如果参数是基本类型,则不需要加前缀,只需要类型名称即可,如图4-2LongFunction:
    image.png
    如果是高阶函数,则操作后+To+基本类型,如mapToLong
    这些基本类型都有与之对应的Stream,以基本类型为前缀,如LongStream

    :::

    Lambda表达式作为参数时,其类型由他的目标类型推导得出,推导过程遵循如下规则:

    • 如果只有一个可能的目标类型,由相应函数接口里的参数类型推导得出。
    • 如果有多个可能的目标类型,由最具体的类型推导得出。
    • 如果有多个可能的类型且最具体的类型不明确,则需要人为指定类型。

    FunctionalInterface接口

    每个用作函数接口的接口都应该添加该注解。 java中有些接口虽然只有一个方法,但并不是为了使用lambda表达式来实现。可能纯属巧合,比如Comparable或Serializable。 但与Comparable和Serializable不同,为了提高Stream对象可操作性引入的各种新接口都需要有lambda表达式可以实现它,他们的意义在于将代码块作为数据打包起来。而且该注解会强制javac检查一个接口是否符合函数接口的标准。如果注解在枚举类型、类、或另个注解上,以及接口包含不止一个抽象方法,javac就会报错。

    多重继承

    接口允许多重继承,因此有可能碰到两个接口包含签名相同的默认方法的情况,那么他该继承哪个呢? 如果子类没有明确的指定实现哪个接口或者没有重写该接口,则javac在编译时会报错(解决方式:明确指定继承接口;重载实现接口方法)

    三定律 :::info

    • 类胜于接口。如果在继承链中有方法体或者抽象的方法声明,那么就忽略接口中定义的方法
    • 子类胜于父类。如果一个接口继承了另一个接口,切两个接口都定义了一个默认方法,那么子类中定义的方法胜出。
    • 没有规则三。如果上面两条规则不适用,子类要么需要实现该方法,要么将该方法声明为抽象方法。 :::

    Optional
    Optional是为核心类库新设计的一个数据类型,用来替换null值。
    使用Option对象有两个目的:

    • Optional对象鼓励成天你许愿适时检查变量是否为空,以避免代码缺陷
    • 它将一个类的API中可能为null的值文档化,这比阅读实现代码要简单很多。

    高级集合类和收集器