您的位置:首页 > 编程语言 > Java开发

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

2017-01-09 00:14 555 查看
看《Java 8 in Action》,并将体会记录下来,方便后面查阅。

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

1. 新特性

lambda表达式

stream api

函数式编程

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

Optional<T>

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<Apple> heavyApples = inventory.stream().filter((Apple a) -> a.getWeight() > 150).collect(toList());


使用并行:

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


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

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

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

default void sort(Comparator<? super E> 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>T -> booleanIntPredicate, LongPredicate, DoublePredicate
Consumer<T>T -> voidIntConsumer, LongConsumer, DoubleConsumer
Function<T, R>T -> RIntFunction<R>, IntToDoubleFunction, IntToLongFunction,

LongFunction<R>, LongToDoubleFunction,

LongToIntFunction, DoubleFunction<R>, ToIntFunction<T>,

ToDoubleFunction<T>, ToLongFunction<T>
Supplier<T>() -> TBooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier
UnaryOperator<T>T -> TIntUnaryOperator, LongUnaryOperator,

DoubleUnaryOperator
BinaryOperator<T>(T, T) -> TIntBinaryOperator, LongBinaryOperator,

DoubleBinaryOperator
BiPredicate<L, R>(L, R) -> boolean 
BiConsumer<T, U>(T, U) -> voidObjIntConsumer<T>, ObjLongConsumer<T>,

ObjDoubleConsumer<T>
BiFunction<T, U, R>(T, U) -> RToIntBiFunction<T, U>, ToLongBiFunction<T, U>,

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

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

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

8. @FunctionalInterface

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

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

9. lambda表达式的类型省略

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

List<Apple> greenApples = filter(inventory, a -> "green".equals(a.getColor()));
Comparator<Apple> 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)是上下文中已有的对象。



12. 构造方法引用

构造方法使用关键字new。

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

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

2个参数的构造方法Apple(Integer weight, String color),适用于BiFunction<Integer, String, Apple>,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)))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java8 java