读书笔记,《Java 8实战》,第三章,Lambda表达式

第一节,Lambda管中窥豹
   能够把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式,它没有名称,但它有参数列表、函数主题和返回值。
   本节介绍了Lambda表达式的语法,它包括参数列表、箭头、Lambda的主体,其中Lambda主体能够包括多行,这个时候必须用大括号把它括起来。
   本节的最后做者给出了Lambda语法的几个例子,让咱们来辨别什么是合法的Lambda表达式语法,其中在没有大括号的时候用return是不对的,带有大括号的时候用单行的表达式也是不对的。
 
第二节,在哪里以及如何使用Lambda
   咱们能够在函数式接口上使用Lambda表达式,那么本节中做者也提出了什么是函数式接口?函数式接口就是只有一个抽象方法的接口,好比传统Java里面的Comparator, Runnable, EventListener,Callable, PrivilegedAction。
   而后这里做者又提出了默认方法的概念。所谓的默认方法就是在类没有对接口方法进行实现的时候,在接口主体也为方法提供了默认实现的方法,哪怕有不少默然方法,只要接口只有一个抽象方法,那它就仍然是一个函数式接口。
   做者在这里给了几个让咱们辨认什么是函数式接口的例子,有两个错误的例子,一个是里面一个借口都没有定义的,另一个里面虽然自定义一个接口,可是他还从父接口中继承了一个抽象接口。
   函数式接口的抽象方法的签名,基本上就是Lambda表达式的签名,咱们将这种抽象方法叫作函数描述符。好比Runnnable接口能够看作一个什么也不接受,什么也不返回的函数的签名。
   关于能够在哪里使用Lambda,其实有不少,好比能够做为函数的入参、做为函数的返回值、又或者把它赋值给一个局部变量。后做者提到了一个叫作@FunctionalInterface的注解
 
第三节,把Lambda付诸实践,环绕执行模式。
   所谓的环绕执行模式其实就相似于之前咱们学到的模版方法模式,这里使用的是try...catch的例子。固然在模板方法中,咱们通常是经过在子类重写抽象方法的形式来让模板方法具备不一样的行为,在本节中,咱们能够经过表达式的方式直接把代码传递给方法,从而实现不一样的行为。
 
第四节,使用函数式接口
   函数式接口颇有用,由于抽象方法的签名能够描述Lambda表达式的签名,函数式接口的抽象方法的签名称为函数描述符,因此为了运用不一样的表达式,你须要一套可以描述常见描述函数描述符的函数式借口。在Java的API中已经有了几个函数式的接口。好比Comparable, Runnable ,Callable, 在Java8中,设计师在java.util.funtion包又添加了几个新的函数是接口,好比Predicate ,Consumer ,Funtion。
   而后做者又提到了这种函数式接口对于基本类型的特化,为何要特化呢,由于对于原始类型的装箱和拆箱性能比较低。有了特化以后就能够避免这种装箱拆箱的操做。
   而后再在p46页中给出了一个表格,其中列出了在Java8中的经常使用的函数式接口。主要就是断言、消费者、函数,以及它们的单参数、多参数、基本类型特化的各类变体。
   在这里做者提到了任意函数式接口都不容许抛出受检异常,若是你须要Lambda表达式来抛出异常,有两种方法:第一种是定义一个本身的函数是接口,并申明受检异常;第二,把Lambda包在一个try catch块中。
 
第五节,类型检查,类型推断以及限制
   Lambda的类型是从使用Lambda的上下文中推断出来的。上下文中Lambda表达式须要的类型称为目标类型有了目标类型的概念,那么同一个Lambda表达式就能够与不一样的函数式接口联系起来,只要他们的抽象方法签名可以兼容就行。你们可能还记得在Java7中就已经引入的菱形运算符,利用泛型推断从上下文中推断类型的思想。
   这里还有一个特殊的void 的兼容规则, 也就是说,若是一个Lambda的主体是一个语句表达式,他就和一个返回void 的函数描述符兼容。
   第四小节,使用局部变量
   咱们迄今为止所介绍的全部Lambda表达式都只用到了其主体里面的参数,可是人们仍是也容许使用自由变量,就像匿名类同样。所谓自由变量,就是在外层做用域中定义的变量虽然它可使用自由变量,但实际上是有一些限制的。Lambda能够没有限制的使用实例变量和静态变量,可是局部变量必须显示的声明为final。换句话说就是lambda表达式,只能捕获指派给他们的局部变量一次之因此会有这种限制,是由于局部变量是分配在栈上的,而实例变量和静态变量是分配在堆栈的。基于java中对于自由变量的这种限制,因此它实际上不具备JS中的那种闭包的概念。
 
第六节,方法引用
   方法应用能够被看做仅仅调用特定方法的Lambda的一种快捷写法,它的基本思想是,若是Lambda表明的只是直接调用这个方法,那最好仍是用名称来调用它,而不是去描述如何调用它。由于显示的指定方法的名称,你的代码的可读性会更好。
 
   在这里,做者给出了,三种类型的方法引用:
   第一种,指向静态方法的方法应用,好比integer的parseInt方法。
   第二种,只想问你类型实例方法的方法已有,好比String的 length方法。
   第三种,指向现有对象的实例方法的方法应用,这个所谓的现有对象,不是表达式的入参,而是上文提到的那种自由变量,用就是外层做用域中的变量。
   第二小节,构造函数引用
   也就是说对于一个现有的构造函数,你能够利用它的名称和关键字new,来建立它的一个引用,像这样Classname::new 可是这个方法应用建立好以后赋值给谁就有点讲究了,这主要是根据这个构造函数的参数的多少而有所不一样,好比说没有参数、一个参数、两个参数等等,分别能够给Supplier, Function ,BiFunction,。
   构造函数应用的一个典型应用就是用来构造简单工厂方法,直接把每个类的构造函数注册到工厂的字典里面去。
 
第七节,lambda和方法应用实战
   这一节惟一要注意的就是Comparator的那个看comparing 静态辅助方法。他能够接受一个function来提取comparable键值 ,并生成一个Comparator 对象,他的实现代码以下:
 public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); }

 

 
第八节,复合Lambda 表达式的有用方法
   这一节主要列出了Java8新提供的几个函数式接口:Comparator, Function, Predicate新提供的默认方法来做为复合方法。有了复合方法以后,就意味着你能够把多个简单的Lambda复合成复杂的表达式。好比你可让两个谓词作一个or操做,组合成一个更大的谓词,并且你还可让一个函数的结果成为另外一个函数的输入,你可能会想函数式接口怎么可能有更多的方法呢?窍门在于咱们即将介绍的方法都是默认方法,也就是说它们不是抽象方法。而后做者详细地给出了,比较器复合,谓词复合 、函数复合。具体都包含哪些复合函数就要本身去看了。这些复合函数组合起来还确实是挺神奇的。
相关文章
相关标签/搜索