前言
Oracle的发布周期缩短,即以后每半年一个版本,JDK11
马上都要发布出来,但现在实验室和生成环境使用的还是JDK8
。JDK8新特性听到最多的就是Lambda
和Stream
了,为了更好的了解后续版本的特性,我们先来了解学习一下JDK8中的这两个特性。
Lambda表达式
首先要知道的是,lambda是用来简化我们的代码量的。直观上来看它可以让一个让一个表达式作为参数。如:
1 | ArrayList<Stu> data = new ArrayList<>(); |
注意上面forEach()填入了一个"s-> System.out.println(s.name+s.age)"
这样的表达式,先不管这个表达式是什么意思,但是我们知道有些方法是可以以表达式的方式作为参数进行使用。
那么就是说forEach是接受一个表达式参数的,点开发现它是接受一个叫做Consumer<? super T> action
。1
void forEach(Consumer<? super T> action);
那Consumer又是什么呢?点开发现这是一个被FunctionalInterface修饰的接口。这个jdk1.8新引入的。被这个修饰的接口称为函数式接口,里面只能有一个自定义方法。如Consumer有一个自定义方法accept()
1 |
|
那么forEach的接受的参数就是一个实现了Consumer接口的类。那我们也可以像下面这样做:1
2
3
4
5
6
7ArrayList<Stu> data = new ArrayList<>();
data.add(new Stu(18,"Job"));
data.stream().forEach(new Consumer<Stu>() {
public void accept(Stu stu) {
System.out.println(stu.name + stu.age);
}
上面的这种写法不就是很熟悉的匿名内部类实现吗!既然可以这样做,为什么还要弄成什么lambda表达式?前面也提到了,Lambda表达式就是为了简化我们代码量的。那么继续来看内部类的实现是如何变成简短的表达式的。
首先函数式接口只有一个一个自定义的方法,像上面的Consumer接口中的accept方法。new Consumer<Stu>()
这段系统肯定是帮你生成好的,所以可以不用写。既然只有一个方法,那么public void accept(Stu stu)
这段是不是没有什么必要了,因为实现的方法体也只能对应到唯一一个方法中。参数类型Stu也不需要,java内部就可以识别,所以只要一个参数名s即可。简化之后就差不多是下面的式子了。1
2(参数)-> 方法体
s-> System.out.println(s.name+s.age)
Stream
这里的Stream不是我们在IO上看到的Stream,简单来说这个是用来处理集合的。还是上面那个实例,对ArrayList进行遍历。
1 | //Jdk1.8之前遍历 |
那如果想要针对sex字段(Male,Female)值,映射成中文(男,女)forEach就做不了吧,的确是的。但是stream还提供了map这个方法,map是一个接受Function接口实现的。Function和Consumer都是1.8自带的函数式接口,这样可以减少我们自己去生成没什么作用的函数式接口。
jdk1.8已经生成了好多个函数式接口,常用有如下四个:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//接受一个类型,不返回值,那基本就是做一个输出
public interface Consumer<T> {
void accept(T t);
}
//不接受参数,直接返回一个值,可能是用来提供某个随机值。因为它没有参数
public interface Supplier<T> {
T get();
}
//接受两个参数,一个是用来计算,另一个是返回类型,可以说是一个映射,和stream中的map是一个意思
public interface Function<T, R> {
R apply(T t);
}
//根据一个参数,去判断这个参数的某个属性
public interface Predicate<T> {
boolean test(T t);
}
stream中好多方法就是接受一个如上面函数接口来实现功能,如Stream中的map接受一个Function接口的实现,Skip接受Predicate的接口实现。下面列出Stream常用的方法。
1 |
|
惰性计算
1 |
|