Lambda表达式的类型
注意:
使用Lamda表达式的,必须是一个函数式接口。Java8之后,接口定义中允许使用默认方法和静态方法。
函数式接口
只有一个抽象方法的接口。例如:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
还有一种情况,包含默认方法/静态方法,但是只有一个抽象方法的接口。
@FunctionalInterface
public interface Predicate<T> {
//只有一个抽象方法
boolean test(T t);
//默认方法
default Predicate<T> and(Predicate<? super T> other) {...}
//静态方法
static <T> Predicate<T> isEqual(Object targetRef) {...}
}
总结
Lambda 表达式需要的类型必须为函数式接口,函数式接口里只有一个抽象方法。
Java8四大内置函数式接口
//有入参,没有返回值
Consumer< T >con 消费性 接口: void accept(T t);
//没有入参,有返回值
Supplier< T >sup供给型接口 : T get();
//有入参,有返回值
Function< T , R >fun 函数式接口 : R apply (T t);
//有入参,返回boolean值
Predicate< T >: 断言形接口 : boolean test(T t);
Lambda表达式的使用
Lamda表达式的使用就是实现一个方法。这个方法就是函数式接口里面的抽象方法。
Lambda表达式的语法
参数块:就是函数式接口中抽象方法的参数。
小箭头:就是->这个符号。
代码块:就是函数式接口中抽象方法的实现。
方法没有入参,这种情况下参数块括号就不能省略。
方法只有一个入参,这种情况下参数块括号就可以省略。
方法体只有一条语句,,这种情况下代码块大括号可以省略。
举例使用
例如:Runnable接口:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
使用Lamda:
Runnable r = () -> System.out.println("run test Lamda");
我们可以新建一个线程,并启动线程:
new Thread(() -> System.out.println("run test Lamda")).start();
多参数的,只需要在()中填写对应的参数即可。
方法引用
语法格式(一) 对象::实例方法名
当方法体中只有一个方法调用时,就可以作这样的简化。有个前提是:方法体中调用的方法的入参和返回值和函数式接口定义的要一致
。
举例如下:
public void test1(){
//普通写法
PrintStream ps = System.out;
Consumer<String>con = (x) -> ps.println(x);
con.accept("hello !");
System.out.println("----------------------");
//简写
Consumer<String>con1 = ps::println;
con1.accept("hello ! ");
}
这个里面println方法的入参和返回值与Consumer接口中定义的accept方法一致。
语法格式(二) 类名::静态方法
public void test2(){
Comparator<Integer>com = (x,y) -> Integer.compare(x,y);
Comparator<Integer>com2 = Integer::compare;
}
Comparator接口中定义的方法:
两个相同类型的参数,返回int类型。
int compare(T o1,T o2);
Integer类中的compare方法为:
两个int类型的入参,返回也是int类型。
public static int compare(int x,int y){
......
}
符合简写的要求。可以使用:类名::静态方法。简化Lambda表达式。
语法格式(三)类名:实例方法
如果,Lambda表达式的参数中,第一个参数是方法体中方法的调用者,第二个参数为方法体中方法调用的参数。可以使用**类名:实例方法**
进行简化。
public void test3(){
BiPredicate<String,String>bp = (x,y) -> x.equals(y);
BiPredicate<String,String>bp2 = String::equals;
}
Stream
Stream可以将需要处理的集合元素看做是流操作
。是对集合对象的一个增强。
Stream的特点
不是数据结构,不会保存数据。
所有Stream的操作必须以lambda表达式为参数。
-
如何使用stream?
通过Stream接口的静态方法(jdk8中接口可以带静态方法)
通过Collection接口的默认方法(jdk8中接口可以带默认方法)-stream(),将一个Collection对象转换成Stream。一般情况,我们通过Collection接口的Stream方法得到Stream
。 -
常见的
中间方法
①Filter(过滤)
//过滤18岁以上的人
List persons = …
Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);
②Map(对元素进行操作)
//把person转成Adult
Stream map = persons.stream().filter(p -> p.getAge() > 18).map(person -> new Adult(person));
③limit(截断)
对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素
④distinct(去重)
对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素
-
常见的
终点方法
①count(统计)
count方法是一个流的终点方法,可使流的结果最终统计,返回int。
②Collect(收集流的结果)
Collect是终点方法,可收集最终的结果。 -
Stream的顺序流和并行流
每个Stream都有两种模式:顺序执行
和并行执行
。
//顺序流:
List <Person> people = list.getStream.collect(Collectors.toList());
//并行流:
List <Person> people = list.getStream.parallel().collect(Collectors.toList());
//可以看出,要使用并行流,只需要.parallel()即可
顾名思义,当使用顺序方式遍历时,每个item读完后再读下一个item
。
使用并行去遍历时,数组会被分成多个段
,其中每一个都在不同的线程中处理,然后将结果一起输出
。