Java8的lambda表达式学习记录—Lambda的方法引用以及Stream流介绍
一,Lambda中的方法引用
若Lambda表达体中的内容已经有方法实现了,我们可以使用方法引用
(可以将方法引用理解为Lambda中的另一种表现形式)
主要有三种语法格式:1. 对象 :: 实例方法名
;2. 类 :: 静态方法名
;3. 类 :: 实例方法名
注意:Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值的类型保持一致!
//对象 :: 实例方法名
@Test
public void test1(){
Consumer<String> s1 = (e) -> System.out.println(e);//后面接方法,该方法可以被其他的方法实现
//System.out.println()方法是实例方法,采用语法格式1
Consumer<String> s2 = System.out::println;
PrintStream ps = System.out;
Consumer<String> s3 = ps::println;
//s1中Lambda体的方法已经被PrintStream对象实现了,所以直接使用方法引用的形式调用即可,可以简写为s2
//采用方法引用时,方法的参数和返回值类型要相同,这里的返回值类型就是Consumer<T>消费者函数型接口指定的泛型
s1.accept("我是s1");
s2.accept("我是s2");
s3.accept("我是s3");
Employee emp = new Employee();//Employee是自己写的实体类
Supplier<String> sup1 = () -> emp.getName();//Supplier供给型接口,无参数有返回值
Supplier<Integer> sup2 = emp::getAge;//简写为对象+实例方法名
System.out.println(sup1.get() + sup2.get());
}
//类 :: 静态方法名
@Test
public void test2(){
Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);//可以加简写为com2
Comparator<Integer> com2 = Integer::compare;//compare方法是Integer类中的静态方法
}
//类 :: 实例方法名
@Test
public void test3(){
BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);//equals这个方法已经被String类自己实现了,所以可以简写为bp2
BiPredicate<String, String> bp2 = String::equals;
/*
调用实例方法,按理说只能使用 对象::实例方法名 的型式,但是这里可以直接使用 类::实例方法名,
原因在于,如果Lambda体中要实现的方法,参数列表中第一个参数作为方法的调用者,第二个参数作为该实例方法的参数,在这种情况下就可以简写为 类名::实例方法名
*/
System.out.println(bp1.test("abc", "abc"));
System.out.println(bp2.test("abc", "abc"));
}
二,Lambda中的构造器引用
构造器引用,相当于新建一个对象。语法格式为ClassName :: new
,注意:需要调用的构造器的参数列表要与函数式接口中的参数列表保持一致!
@Test
public void test4(){//构造器引用 ClassName::new
Supplier<Employee> sup1 = () -> new Employee();//Supplier供给型接口,无参数有返回值,返回一个新建的Employee对象,可以简写为sup2,采用构造器引用的方式
Supplier<Employee> sup2 = Employee::new;
/*
此时,Employee类中有两个构造函数,一个是无参的,一个是有参的,sup2创建的对象走的是哪个方法,取决于调用的参数列表
*/
System.out.println(sup2.get());//调用无参的构造方法
Function<String, Employee> f1 = (e) -> new Employee(e);
Function<String, Employee> f2 = Employee::new;
/*
此时Function方法中有一个参数e,类型为String,所以 Employee::new 会调用有一个参数的构造器
*/
System.out.println(f2.apply("张三"));//调用有参的构造方法
}
三,Lambda中的数组引用
语法格式:Type :: new
@Test
public void test5(){//数组引用 Type::new
Function<Integer, String[]> f1 = e -> new String[e];//
System.out.println(f1.apply(10).length);
Function<Integer, String[]> f2 = String[]::new;
System.out.println(f2.apply(10).length);
}
四,Stream介绍
Stream(流),是数据通道,用于操作数据(集合、数组等),所生成的元素序列,集合指的是数据,流讲的是计算。
注意:
- Stream 自己不会存储元素;
- Stream 不会改变源对象,相反的,他们会返回一个持有结果的新Stream;
- Stream 操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。
Stream的操作步骤:
- 创建 Stream;
- 中间操作,对数据进行处理;
- 终止操作,执行中间操作链,并产生结果。
注意:Stream流只会在执行终止操作时,才会去执行中间操作,称为惰性求值。
@Test
public void test1(){//创建Stream
//1,可以通过 Collection 系统集合提供的 stream() 或 parallelStream
List<String> list = new ArrayList<>();
Stream<String> s1 = list.stream();
//2,可以通过 Arrays 中的静态方法 stream() 获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> s2 = Arrays.stream(emps);
//3,可以通过 Stream 类中的静态方法 .of()
Stream<String> s3 = Stream.of("a", "b", "c");
//4,创建无限流
Stream<Integer> s4 = Stream.iterate(0, (e) -> e+2);//迭代
s4.limit(10).forEach(System.out::println);
Stream<Double> s5 = Stream.generate(() -> Math.random());//生成
s5.limit(10).forEach(System.out::println);
}