Lambda表达式与StreamAPI
Lambda 表达式与 StreamAPI
1 JDK1.8
2 这两个的目的都是想要使得 Java 能够实现函数式编程
3 Lambada 表达式主要针对接口,函数式接口进行的优化,简化代码
4 StreamAPI 主要是针对集合的处理操作进行的优化,简化代码
5 Lambda 表达式
5.1 是一个匿名的函数,为了把方法体的实现代码当做数据一样进行传递
5.2 JDK1.8 之前,用匿名内部类完成
-
Runnable r = new Runnable(){ public void run(){ …… } }
- 目的就是传递run()方法的实现代码
-
new Thread(new Runnable(){ public void run(){ …… } }).start();
5.3 使用 Lambda 表达式
- Runnable r = () -> {….};
- new Thread(() -> {….}).start();
5.4 语法
- 格式: (形参列表) -> {Lambda 体}
5.5 四种形式
-
(1)无参无返回值
-
格式
- () -> {Lambda 体}
-
说明:
- (1)无参,()
- (2)如果 Lambda 体是多句语句,那么{}是不可以省略
- (3)如果 Lambda 体是 1 句语句,那么{}如果不省略,那么语句后面要加; ,即{;}
- (4)如果 Lambda 体是 1 句语句,那么{;}可以省略
-
代表
- Runnable r = () -> {System.out.println(“hello”);};
- Runnable r = () -> System.out.println(“hello”);
-
-
(2)有参无返回值
-
格式
- (形参列表) -> {Lambda 体}
-
说明:
- (1)如果 Lambda 体是多句语句,那么{}是不可以省略
- (2)如果 Lambda 体是 1 句语句,那么{}如果不省略,那么语句后面要加; ,即{;}
- (3)如果 Lambda 体是 1 句语句,那么{;}可以省略
- (4)如果参数列表的参数类型是可以确定的,那么类型可以省略,如果形参个数是多个,那么()不可以省略
- (5)如果参数列表的个数只有 1 个,类型可以确定,()可以省略,形参名不可以省略,但是形参名可以和接口的抽象方法的形参名不一样
-
代表
-
消费型
-
Consumer void accept(T t)
-
java.lang.Iterable
- forEach(Consumer)
- 集合对象.forEach(t -> System.out.println(t));
-
-
-
(3)无参有返回值
-
格式
-
() -> {Lambda 体}
- Lambda 体中,肯定有 return 语句
-
-
说明:
- (1)无参,()不可以省略
- (2)如果 Lambda 体是多句语句,那么{}是不可以省略,,每一个语句后面要;,并且必须有 return 返回值;的语句
- (3)如果 Lambda 体是 1 句语句,那么{}如果不省略,那么一定是{return 返回值;}的语句
- (4)如果 Lambda 体是 1 句语句,那么{;}可以省略,而且 return 要省略
-
代表
-
供给型
-
Supplier T get()
-
java.util.Optional orElseGet(Supplier)
- Optional opt = Optional.ofNullable(address);
- String address = opt.orElseGet(() -> new String(“北京”));
-
-
-
(4)有参有返回值
- 格式 - (形参列表) -> {Lambda体} - 说明: - (1)如果Lambda体是多句语句,那么{}是不可以省略,并且必须有return 返回值;的语句 - (2)如果Lambda体是1句语句,那么{}如果不省略,那么一定是{return 返回值;}的语句 - (3)如果Lambda体是1句语句,那么{;}可以省略,而且return也可以省略 - (4)参数列表,如果类型可以确定,那么类型可以省略,()不可以省略 - (5)参数列表,如果类型可以确定,并且参数个数只有一个,那么类型和()都可以省略 - 代表 - java.util.Comparator<T>: int compare(T t1, T t2) - Comparator<Student> com = (t1,t2) -> t1.getId() - t2.getId(); - Predicate<T> : boolean test(T t) - Predicate<Employee> p = t -> t.getSalary() > 10000; - Function<T,R> : R apply(T t) - 如果Employee对象的薪资低于10000,涨薪10%,并且返回新工作 - Function<Employee, Double> f = e -> { if(e.getSalary()<10000){ e.setSalary(e.getSalary()*1.1; } return e.getSalary();
}
5.6 使用的形式
-
1、给函数式接口的变量赋值:多态引用
- Comparator com = (t1,t2) -> t1.getId() - t2.getId();
-
2、给函数式接口的形参赋值:多态参数
- new TreeSet( (t1,t2) -> t1.getId() - t2.getId());
5.7 函数式接口
-
函数式接口也是接口,是个特殊的接口,SAM 型接口
-
SAM:Single Abstract Method
- 使用注解声明@FunctionInterface
-
-
在这个类接口中只有一个抽象方法,但是可以有静态方法和默认方法以及 Object 中的方法
-
只有函数式接口的变量或形参才能用 Lambda 表达式赋值
-
四个核心的函数式
-
1、消费型
-
Consumer void accept(T t)
-
还有延伸版
- BiConsumer<T,U>: void accept(T t,U u)
- 。。。。
-
-
2、供给型
- Supplier T get()
- DoubleSupplier Double get()
- ….
-
3、功能型
-
Function<T,R> R apply(T t)
-
延伸版
- BiFunction<T,U,R> R apply(T t,U u)
- BinaryOperator T apply(T t2, T t2)
- ….
-
-
4、断定型
-
Predicate : boolean test(T t)
-
延伸版
- BiPredicate<T,U> boolean test(T t ,U u)
- ….
-
-
5.8 再简化版
-
方法引用
-
条件
- (1)Lambda 体通过调用一个现成的方法来完成
- (2)Lambda 的形参列表刚好是用于这个方法的实参
-
形式有三种
-
(1)实例对象::实例方法名
- 集合对象.forEach(t -> System.out.println(t));
- 集合对象.forEach(System.out::println)
-
(2)类名::静态方法名
-
Supplier s = () -> Math.random();
- Supplier s = Math::random;
-
BiFunction<Integer,Integer,Integer> b = (a,b) -> Math.max(a,b);
- BiFunction<Integer,Integer,Integer> b = Math::max;
-
-
(3)类名::实例方法名
-
Comparator c = (t1,t2) -> t1.compareTo(t2);
- Lambda 表达式的形参的第一个作为调用方法的对象,第二个,作为这个实例方法的实参
- Comparator c = String::compareTo;
-
-
-
-
构造器引用
-
条件
- (1)Lambda 体通过调用一个构造器完成,返回这个新建的对象
- (2)Lambda 的形参列表刚好是用于这个构造器的实参
-
示例
- Fuction<String ,Employee> f = name -> new Employee(name);
- Fuction<String ,Employee> f = Employee::new;
-
-
数组构造引用
-
条件
- (1)Lambda 体通过创建一个数组对象完成,返回这个新建的数组对象
- (2)Lambda 的形参列表刚好是用于这个数组对象的创建的长度
-
示例
- Fuction<Integer ,Employee[]> f = len -> new Employee[len];
- Fuction<Integer ,Employee[]> f = Employee[]::new;
-
6 StreamAPI
6.1 作用
- Stream API ( java.util.stream) 把真正的函数式编程风格引入到 Java 中。这是目前为止对 Java 类库最好的补充,因为 Stream API 可以极大提高 Java 程序员的生产力,让程序员写出高效率、干净、简洁的代码。 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用 Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
6.2 特点
- 1、Stream 不负责存储数据
- 2、Stream 的操作不影响数据源,每次操作返回一个新的 Stream
- 3、Stream 的中间操作是一个“懒惰求值”,一直要到终结操作,才会一口气完成
6.3 步骤
-
1、创建 Stream
- 四种方式 - 1、Collection集合对象.stream() - ArrayList<String> list = new ArrayList<>();
。。。 //创建 stream Stream stream = list.stream();
- 2、Arrays.stream(数组对象) - String[] arr = {"hello","world","java","lambda","stream"};
Stream stream = Arrays.stream(arr);
- 3、Stream.of(T...) - Stream<String> stream = Stream.of("hello","world","java","lambda","stream"); - 4、无限流 - Stream.iterator(..) - 示例 @Test public void test4(){ //Interface UnaryOperator<T>是特殊的Function<T,T>: T apply(T t) Stream<Integer> stream = Stream.iterate(1, x -> x+2); //中间操作 stream = stream.limit(10);//取前面的10个 stream.forEach(System.out::println); } - Stream.generate(xx) - 示例 @Test public void test5(){ //Supplier<T> :T apply() // Stream<Double> generate = Stream.generate(() -> Math.random()); Stream<Double> stream = Stream.generate(Math::random); // stream = stream.limit(5); // stream.forEach(System.out::println); stream.limit(5).forEach(System.out::println); }
-
2、中间操作
- (1筛选与切片 - (1)筛选与切片
A:过滤:filter B:去重:distinct C:取前面的几个:limit D:跳过前面几个:skip
-
要取中间几个:skip + limit
-
(2)映射
- A:map(Function):对 Stream 中的每一个元素执行某个操作,返回值组成一个新的 Stream
-
B:返回值是特殊类型
-
mapToInt()
-
mapToLong()
-
mapToDouble() C:flatMap(Function):对 stream 的每一个元素执行某个操作,返回值是一个 stream,这些个 stream 再合成一个大的 stream
-
(3)排序
- A:sorted():自然排序
-
B:sorted(Comparator):定制排序
-
3、终结操作
- (1)遍历 - forEach(Consumer) - (2)匹配与查找 - A:allMatch(Predicate p):每一个元素是否都满足某个条件
B:anyMatch(Predicate p):是否有一个元素满足条件 C:noneMatch(Predicate p):是否所有元素都不满足
-
D:findFirst():返回第一个 E:findAny():如果是并行流,返回的结果是任意一个,如果是一个稳定的流,返回的结果是和 findFirst()一样
-
F:count():统计 G:max(Comparator) H:min(Comparator)
- (3)规约 - A:Optional<T> reduce(BinaryOperator<T> accumulator)
BinaryOperator是一个 BiFunction<T,T,T>接口: T apply(T t1, T t2) B:T reduce(T identity,BinaryOperator accumulator)
- (4)收集 - <R,A> R collect(Collector<? super T,A,R> collector) - Collector 接口中方法的实现决定了如何对流执行收集的操作
Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,例如、List,Set,Map