Java8学习笔记(一)——lambda表达式和方法引用

看《Java 8 in Action》,并将体会记录下来,方便后面查阅。

可能比较零散,都后面有时间和精力再分类整理,暂时先分条列出。


1. 新特性

lambda表达式

stream api

函数式编程

接口可以定义默认实现的方法

Optional


2. 方法引用

方法引用“::”,可作为方法的参数。

在java 8之前,如果需要获取隐藏的文件,可能需要这么写:

File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
    public boolean accept(File file) {
        return file..isHidden();
    }
});

而java 8,可以这么写:

File[] hiddenFiles = new File(".").listFiles(File::isHidden);

同时还支持匿名函数,比如要获取非隐藏文件,可以这么写:

File[] notHiddenFiles= new File(".").listFiles((File f) -> !f.isHidden());


3. java 8的stream api使多核和并行处理更加自然

不使用并行:

import static java.util.stream.Collectors.toList;
List heavyApples = inventory.stream().filter((Apple a) -> a.getWeight() > 150).collect(toList());

使用并行:

import static java.util.stream.Collectors.toList;
List heavyApples = inventory.parallelStream().filter((Apple a) -> a.getWeight() > 150).collect(toList());


4. 接口可以定义默认实现的方法

想想这么一个场景,一个对外使用的接口,某次升级需要增加一个方法,这个方法对大部分应用来说只需使用默认的实现即可,但是这个接口使用非常广泛(比如java.util.List),那么如果升级api,所有实现该接口的类都需要去实现下这个方法,可想而知有多崩溃。

java 8支持了给接口方法指定默认的实现,从而解决了这个问题,关键字是default,写法如下:

default void sort(Comparator c) {
    Collections.sort(this, c);
}

由于java支持实现多接口,那如果多接口都有同名的默认方法实现,可能会有一些问题,如何避免或解决的后面看到了再补充。


5. Behavior parameterization

行为参数化?

为了适应不断变化的需求。


6. lambda语法

(parameters) -> expression

(parameters) -> {statements;}

其中parameters可以为空。

expression不需要写return,隐式返回;而statements中需要(如果有返回值)。


7. 功能接口(functional interface)

只有一个抽象方法的接口称作功能接口。如Comparator、Runnable等。

即使包含多个默认实现的方法,只要保证只有一个抽象接口,还是可以叫做功能接口。

对于功能接口,可以使用lambda表达式简化书写,如:

Runnable r = new Runnable() {
    public void run() {
        System.out.println("run");
    }
}

可以简写成:

Runnable r = () -> System.out.println("run");

常用的功能接口:

功能接口 功能描述符 基本类型专用
Predicate T -> boolean IntPredicate, LongPredicate, DoublePredicate
Consumer T -> void IntConsumer, LongConsumer, DoubleConsumer
Function T -> R IntFunction, IntToDoubleFunction, IntToLongFunction,
LongFunction, LongToDoubleFunction,
LongToIntFunction, DoubleFunction, ToIntFunction,
ToDoubleFunction, ToLongFunction
Supplier () -> T BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier
UnaryOperator T -> T IntUnaryOperator, LongUnaryOperator,
DoubleUnaryOperator
BinaryOperator (T, T) -> T IntBinaryOperator, LongBinaryOperator,
DoubleBinaryOperator
BiPredicate (L, R) -> boolean  
BiConsumer (T, U) -> void ObjIntConsumer, ObjLongConsumer,
ObjDoubleConsumer
BiFunction (T, U) -> R ToIntBiFunction, ToLongBiFunction,
ToDoubleFunction

可以看到每种功能接口都基本提供了一些支持基本类型的专用接口。

由于泛型的特性,不支持基本类型,java提供了自动装箱机制,可以自动转换成对应的包装类型(如int与Integer),但是这种转换会消耗性能(装箱的对象会放到堆中)。

于是java提供了泛型对应的专用接口,使输入或输出直接对应基本类型,避免了自动装箱。


8. @FunctionalInterface

如果要编写的一个接口是功能接口,可以加上这个注解。

当实现并非是功能接口时,编译的时候会报错。


9. lambda表达式的类型省略

由于参数的类型可以从泛型定义中获取,所以在书写lambda表达式的时候,参数类型可以省略(当只有一个参数的时候,括号也可以省略),如:

List greenApples = filter(inventory, a -> "green".equals(a.getColor()));
Comparator c = (a1, a2) -> a1.getWeight().compareTo(a2.getWeight());

有时候带上类型定义更易读,而有时候省略更易读。

什么时候带上什么时候省略,根据情况而定,或者团队进行约定。


10. lambda使用本地变量

lambda可以访问本地变量,但是不能修改本地变量。

需要将本地变量声明为final或事实上的final(即没有声明final,但是表现出了final的特点)。

实例变量不受此限制。

实例变量是放在堆上的,而本地变量是在栈上的,如果允许修改本地变量,当lambda放到线程中时,可能存在已被回收的资源的情况。


11. 方法引用

方法引用可以复用已有的方法,就像lambda表达式一样作为方法的参数。

可以将方法引用看成是lambda表达式的语法糖, 功能相同但是书写更简短,在某些场景下可读性提高。

三种写法:

1)静态方法引用,如Integer::parseInt;

2)实例方法引用,任意类型,如String::length;

3)实例方法引用,已有对象,如存在一个对象xxx,有一个getValue方法,则可以xxx::getValue。

2)与3)的区别可以理解为,2)是lambda函数定义的参数,3)是上下文中已有的对象。

Java8学习笔记(一)——lambda表达式和方法引用_第1张图片


12. 构造方法引用

构造方法使用关键字new。

无参构造方法Apple(),Apple::new;

1个参数的构造方法Apple(Integer weight),适用于Function,Apple::new + apply;

2个参数的构造方法Apple(Integer weight, String color),适用于BiFunction,Apple::new + apply。


13. lambda表达式的组合

功能接口和一些常用的工具类中一般都有默认方法,方便对lambda表达式进行组合。

Comparator反序:

inventory.sort(comparing(Apple::getWeight).reversed());

Comparator连接:

inventory.sort(comparing(Apple::getWeight).thenComparing(Apple::getColor));

Predicate:

negate、and、or。

优先级从左到右,如a.or(b).and(c)等同于(a || b) && c。

Function:

andThen(f.andThen(g) == g(f(x)))

compose(f.compose(g) == f(g(x)))

你可能感兴趣的:(java)