一、lambda表达式
它是一种相对简练的写法,代替函数式接口(该接口只有一个抽象方法,但可以有多个default或者静态方法(jdk1.8对接口进行了扩展,可以有default和静态方法))
二、方法的引用
可代替lambda表达式,且更加简洁,主要是类或接口里有合适的方法就ok
这些方法都没有写括号,因为不是调用,而只是引用
1.构造器方法引用
格式:Class::new,调用默认构造器。(比如,如果接口中需要实现的方法需要两个参数,那么如果Class的构造函数也有两个参数且类型一样,就可以用Class::new)
2.类静态方法引用(这里注意,接口的静态方法也是可以的,类似interface::static_method)
格式:Class::static_method
3.类普通方法引用
格式:Class::method
4.实例方法引用
格式:instance::method
对于1、2、4比较简单,只有注意参数和返回值与接口方法对应上即可,其实就是把整个method放到接口的函数体中去调用。3比较麻烦,需要满足特定的条件才能调用:
public class Test1 {
public void a(Integer param1,int param2){
}
public static void main(String[] args) {
MyInter m = (j,k,l)->j.a(k, l); //lambda形式
MyInter m1 = Test1::a;//第三种方法形式
//第一个参数为方法目标,其余参数为参数
}
}
@FunctionalInterface
interface MyInter {
public void d(Test1 d,int param1,int param2);
}
条件:接口方法的第一个参数恰巧是一个类或者是一个接口,这是可以用Test1加::引用Test1里的非静态方法(该方法的返回值与接口的抽象方法一致,参数的话,除了第一个参数,也就是从抽象方法的第二个参数算起,必须与被引用的非静态方法的参数一致)。这里Test1::a 的Test1可以是一个类或者也可以一个接口,而d(Test1 d,int param1,int param2);里的Test1可以是Test1,也可以是Test1的子类或子接口(如果Test1::a中的Test1是接口的话),这里比较好的例子是jdk8 Collectors中的
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
三、Stream
例:
List<Integer> arrayList=Arrays.asList(1,2,3).stream().map(i->i+1).map(i->i+2).filter(i->i>1).collect(Collectors.toList());
像这样的一个stream的链式表达式,有几点需要说明:
stream是惰性求值,也就是collect前的这些中间动作都不会实际执行,stream只是把他们每个操作都包成对象,然后以链的形式保存起来,等执行到collect的时候开始根据之前的链中保存的对象逐一执行。
上面这个表达式的执行流程是,从list里先取出第一个元素,然后对其进行链式记录的操作,也就是1+1 =2 , 2+2 =4 ,4>1为true,然后放到list里,然后在取出第二个元素,以此类推。
如果链式表达式中有类似sorted需要状态的函数,这时就不能到collect在统一进行计算了,这时就得到sorted就开始计算了,修改一个list后再进行sorted操作,然后再进行collect操作
对于并行流,其实就是把集合分片,然后利用多线程,一个线程负责一片,并行计算,每个线程计算的方式就是和前面单线程一样,最后再合一起,利用的forkjoin,如果并行流里有 sorted之类的需要状态的函数,那在它之前进行多线程计算合并,形成一个list后再调用各个集合自带的并行sorted方法,得到一个排序后的list后,如果sorted后还有其他计算,就可以接着讲list分片,弄多线程搞。