三.方法引用与构造器引用
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用 ! 方法引用可以看作是Lambda表达式深层次的表达,换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例
,通过方法名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
语法:
使用操作符 “::” 将类(或对象)与方法名分割开来。
要求:实现接口的抽象方法的参数和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
案例:
- 格式:对象 : : 非静态方法
@Test public void test(){ //Lambda表达式写法 Consumer<String> consumer = str ->System.out.println(str); consumer.accept("Lambda表达式"); //方法引用写法 Consumer<String> fConsumer = System.out::println; fConsumer.accept("方法引用"); }
- 格式:类 : : 静态方法
public class LambdaTest { @Test public void test(){ //Lambda表达式写法 比较两个数大小 Comparator<Integer> comparator =(t1,t2) -> Integer.compare(t1,t2); System.out.println(comparator.compare(10,20)); //方法引用写法 Comparator<Integer> fComparator = Integer::compare; System.out.println(fComparator.compare(20,10)); } }
格式:类 : : 非静态方法
public class LambdaTest { @Test public void test(){ //Lambda表达式写法 Comparator<String> comparator=(s1,s2) -> s1.compareTo(s2); System.out.println(comparator.compare("abc","abd")); //方法引用写法 Comparator<String> fComparator = String::compareTo; System.out.println(fComparator.compare("www","www")); } }
正常来说comparator.compare("abc","abd")有两个参数,而s1.compareTo(s2)只有一个参数并不满足上述所说的方法引用的要求。但是为什么能用呢?因为这种情况下,第一个参数作为方法的调用者出现((s1,s2) -> s1.compareTo(s2)),这种情况下也存在方法引用。只不过这时候我们不是拿具体的对象写,而是拿它的类写(Comparator<String> fComparator = String::compareTo;)
构造器引用
调用的构造器会根据实现的函数接口的抽象方法的参数列表来确定,如果抽象方法为无参的,则调用的构造器也是无参的。
语法:
ClassName :: new
案例
public class Student { public Student() { System.out.println("Student 无参构造已执行"); } public Student(Integer id) { System.out.println("Student 有参构造,一个参数.为:"+id); } public Student(Integer id, String name, char sex) { this.id = id; this.name = name; this.sex = sex; } private Integer id; private String name; private char sex; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public char getsex() { return sex; } public void setsex(char sex) { this.sex = sex; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", sex=" + sex + '}'; } }
- 通过无参构造器引用(创建对象)
public class LambdaTest { @Test public void test(){ //原始写法 Supplier<Student> supplier =new Supplier<Student>() { @Override public Student get() { return new Student(); } }; supplier.get(); //lambda表达式写法 Supplier<Student> lSupplier =()-> new Student(); lSupplier.get(); //构造器引用写法 Supplier<Student> gSupplier = Student::new; gSupplier.get(); } }
- 通过有参构造器引用(一个参数,创建对象)
@Test public void test(){ //原始写法 Function<Integer,Student> function =new Function<Integer, Student>() { @Override public Student apply(Integer integer) { return new Student(integer); } }; function.apply(1); //lambda表达式写法 Function<Integer,Student> lFunction = id -> new Student(id); lFunction.apply(2); //构造器引用写法 Function<Integer,Student> gFunction = Student::new; gFunction.apply(3); }
数组引用
大家可以把数组看做是一个特殊的类,写法与构造器引用一致。
public class LambdaTest { @Test public void test(){ //原始写法 Function<Integer,String[]> function =new Function<Integer, String[]>() { @Override public String[] apply(Integer integer) { return new String[integer]; } }; System.out.println(Arrays.toString(function.apply(10))); //lambda表达式写法 Function<Integer,String[]> lFunction= length -> new String[length]; System.out.println(Arrays.toString(lFunction.apply(20))); //构造器引用写法 Function<Integer,String[]> gFunction = String[] :: new; System.out.println(Arrays.toString(gFunction.apply(30))); } }
四.Stream API
Java8中有两大最为重要的改变。第一个是Lambda表达式;另外一个则是Stream API。
Stream API(java.util.Stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API 可以极大提供Java程序员的生产力,让程序员写出高效率,干净,简洁的代码。
(Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。)
Strema到底是什么呢?
是数据渠道,用于操作数据源(集合,数组等) 所生成的元素序列。
“集合将的是数据,Stream讲的是计算!”
语法
集合或数组.stream().过滤().映射().终止操作
Stream 操作的三个步骤
创建 Stream
一个数据源(集合,数组),获取一个流中间操作
一个中间操作链,对数据源的数据进行处理终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
注意:
- Stream 自已不会存储元素
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
案例(围绕以上三点进行操作)
首先我们先来了解两个概念
并行流(parallelStream):多个线程同时运行
顺序流(stream):使用主线程,单线程
- Stream 实例化
- 创建 Stream 方式一:通过集合创建
public class LambdaTest { @Test public void test(){ List<Student> students= StudentData.getStudent(); //返回一个顺序流 Stream<Student> stream = students.stream(); //返回一个并行流 Stream<Student> parallelStream = students.parallelStream(); } }
创建 Stream 方式二:通过数组创建(Java8中的Arrays的静态方法 Stream()可以获取数组流)
public class LambdaTest { @Test public void test(){ int[] arr =new int[]{1,2,3,4,5}; //通过泛型识明你的类型 放进去的是一个int类型的数组,返回的也是int类型的流 IntStream stream = Arrays.stream(arr); } }
创建 Stream 方式三:通过Stream的of()
public class LambdaTest { @Test public void test(){ Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6); } }
创建 Stream方式四:创建无限流 (了解)
public class LambdaTest { @Test public void test(){ /** * 例子:遍历前10个偶数并打印出来 * iterate(): 迭代 * seed:种子 * UnaryOperator:函数式接口 * 注意:无限流不加对应的中间操作会无限的进行迭代 limit(10):前10个 */ Stream.iterate(0, t -> t+2).limit(10).forEach(System.out::println); } }