编辑
2023-03-07
Java
0
请注意,本文编写于 676 天前,最后修改于 676 天前,其中某些信息可能已经过时。

目录

一、Lambda表达式简介
二、Lambda表达式写法
1 基本写法
2 简化原则
3 特点
三、Java函数式接口
四、函数式编程的运用
1 Stream
1.1 stream介绍
1.2 创建stream
1.3 stream常见中间操作
1.4 stream常见终端操作
2 Optional
2.1 Optional介绍
2.2 Optional创建
2.3 Optional常用功能

一、Lambda表达式简介

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。 和匿名内部类相似,可以简化匿名内部类的写法,只作用于只有一个抽象方法的接口;

二、Lambda表达式写法

1 基本写法

java
Comparator<Integer> comparator = (Integer a, Integer b) -> { return a - b; }; //可根据Lambda的简化原则,进行简化 Comparator<Integer> comparator = (a, b) -> a - b;

2 简化原则

  • 可选类型声明: 不需要声明参数类型,编译器会根据接口中的抽象方法的参数判断类型,因此参数个数要对应。
  • 可选的参数圆括号: 一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号: 如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字: 如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

3 特点

  • lambda表达式只能用于创建接口对象,并且该接口只能有一个抽象方法;
  • lambda表达式中使用外部的局部变量,会默认添加final,不能二次赋值;

三、Java函数式接口

所谓函数式接口,指的是只有一个抽象方法的接口。 函数式接口可以被隐式转换为Lambda表达式。 函数式接口可以用@FunctionalInterface**注解标识。

  • Consumer

消费,只有输入没有输出。

java
Consumer<String> c1 = n -> System.out.print("<"+n+">"); Consumer<String> c2 = n -> System.out.print("["+n+"]"); c1.accept("test01"); //打印 <test01> //andThen(c2):按Consumer顺序连续消费 c1.andThen(c2).accept("test01"); //打印<test01>[test01]
  • Function

函数,既有输入也有输出。

java
Function<String, String> f1 = s -> s + "+"; Function<String, String> f2 = s -> s + "-"; System.out.println(f1.apply("test01")); //打印:test01+ //连续调用,将f1处理的结果给f2调用 System.out.println(f1.andThen(f2).apply("test01")); //打印:test01+- //连续调用(反向),将f2处理的结果给f1调用 System.out.println(f1.compose(f2).apply("test01")); //打印:test01-+ //identity():返回一个将输入原样返回的Function System.out.println(Function.identity().apply("test01")); //打印:test01
  • Predicate

判断,有输入返回值为boolean

java
Predicate<String> p1 = o -> o.equals("test"); Predicate<String> p2 = o -> o.startsWith("t"); System.out.println(p1.test("test01")); //打印:false //取反 System.out.println(p1.negate().test("test01")); //打印:true //与运算 System.out.println(p1.and(p2).test("test01")); //打印:false //或运算 System.out.println(p1.or(p2).test("test01")); //打印:true //判断是否相等 System.out.println(Predicate.isEqual("test01").test("test01")); //打印:true
  • Supplier

供应,没有输入但有输出

java
//引用了Date构造器;特点是没有参数 Supplier<Date> supplier = Date::new; //调用了get(),相当于调用了new Date(),返回新对象 Date date = supplier.get(); System.out.println(date);

四、函数式编程的运用

1 Stream

1.1 stream介绍

Stream可以对多个元素进行一系列的操作,也可以支持对某些操作进行并发处理。

1.2 创建stream

java
//空的Stream Stream<Integer> st1 = Stream.empty(); //根据元素创建 Stream<Integer> st2 = Stream.of(1, 3, 5, 7, 9); //根据集合创建 List<Integer> list = Arrays.asList(1, 3, 5, 7, 9); Stream<Integer> st3 = list.stream(); //串行,单线程处理 Stream<Integer> st4 = list.parallelStream(); //并行,多线程处理 //生成数据创建,这里是随机生成10个[0,99)的数; Stream<Integer> st5 = Stream.generate(() -> (int) (Math.random() * 100)).limit(10);

1.3 stream常见中间操作

java
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5); integerList.stream().filter(n -> n%2 == 0).forEach(System.out::println); //筛选 integerList.stream().distinct().forEach(System.out::println); //去重 integerList.stream().limit(3).forEach(System.out::println); //只要前n个 integerList.stream().skip(2).forEach(System.out::println); //舍去前n个 integerList.stream().sorted().forEach(System.out::println); //排序 //对每个元素进行同一处理,将每个的处理结果作为新的stream integerList.stream().map(n -> n*2).forEach(System.out::println); //返回值与map()不同,返回一个Stream,将所有返回的stream合成一个新的stream integerList.stream().flatMap(n -> Stream.of(n-1,n, n+1)).forEach(System.out::println);

1.4 stream常见终端操作

java
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); //统计 System.out.println( stream.count() ); //计数 System.out.println( stream.max((a, b) -> a - b).get() ); //最大值 System.out.println( stream.min((a, b) -> a - b).get() ); //最小值 System.out.println( stream.reduce((a, b) -> a + b).get() ); //将每次操作的返回值和下一个元素进行操作,这里等同于求和 //对stream的数据进行汇总 IntSummaryStatistics stat = stream.mapToInt(n -> n).summaryStatistics(); System.out.println( stat.getSum() ); System.out.println( stat.getMax() ); System.out.println( stat.getMin() ); System.out.println( stat.getAverage() ); //判断 System.out.println( stream.anyMatch(n -> n > 10) ); //满足任何一个就返回true System.out.println( stream.allMatch(n -> n > 10) ); //全部满足才返回true System.out.println( stream.noneMatch(n -> n > 10) ); //全部不满足才返回true //转换 int[] ints = stream.mapToInt(n -> n).toArray(); //转int数组 //通过切换Collectors的静态方法,可实现不同类型的转换 List<Integer> list = stream.collect(Collectors.toList()); //转list Set<Integer> set = stream.collect(Collectors.toSet()); //转set Map<Integer, Integer> map = stream.collect(Collectors.toMap(n -> n, n -> n)); //转map //连接字符串,必须是Stream<String> String str = stream.map(String::valueOf).collect(Collectors.joining()); //Integer集合和String集合的互转,其他类型的转化只需要换.map的函数即可 List<String> stringList = stream.map(String::valueOf).collect(Collectors.toList()); List<Integer> collect = stringList.stream().map(Integer::parseInt).collect(Collectors.toList());

分组排序,根据某个属性值(日期、字符串等)进行分组,若分组前进行了排序,则分组后每个组中的元素也是有序的;

java
@Data @NoArgsConstructor @AllArgsConstructor private static class User { private String name; private Integer age; private String position; } public static void main(String[] args) { User zs = new User("张三", 30, "老板"); User ls = new User("李四", 21, "员工"); User wr = new User("王二", 22, "员工"); Stream<User> stream = Stream.of(zs, ls, wr); LinkedHashMap<String, List<User>> groupUser = stream.sorted(Comparator.comparingInt(User::getAge)) .collect(Collectors.groupingBy(User::getPosition, LinkedHashMap::new, Collectors.toList())); groupUser.forEach((k, v) -> { System.out.println(k); v.forEach(System.out::println); }); } //打印: //员工 //DateUtilTest.User(name=李四, age=21, position=员工) //DateUtilTest.User(name=王二, age=22, position=员工) //老板 //DateUtilTest.User(name=张三, age=30, position=老板)

2 Optional

2.1 Optional介绍

在函数式编程时,空指针异常非常容易犯,Optional就主要解决这个问题。

2.2 Optional创建

java
//of()不会检查传入的对象是否为空;而ofNullable()会检测是否为null,若为null,会创建一个空的Optional Optional<String[]> o1 = Optional.empty(); //创建空的Optional Optional<String[]> o2 = Optional.of(args); Optional<String[]> o3 = Optional.ofNullable(args);

2.3 Optional常用功能

java
optional.isPresent(); //判断值是否为空 optional.ifPresent(System.out::println); //若optional不为空,则进行消费,比如添加到集合等; Optional<Integer> o1 = optional.map(n -> n * 2); //若optional不为空,则将执行函数后的返回值封装为Optional返回,否则返回Optional.empty(); Optional<Integer> o2 = optional.filter(n -> n > 5); //空的optional和判断为false都返回Optional.empty(),判断为true则返回this; Integer i1 = optional.get(); //获取值,若optional为空,则抛出异常; Integer i2 = optional.orElse(4); //若optional不为空,则返回它的值,否则返回传入的值; Integer i3 = optional.orElseGet(() -> new Random().nextInt(10)); //默认值从传入的函数中获取,既动态的默认值; Integer i4 = optional.orElseThrow(() -> new NullPointerException()); //若为空则抛出指定的异常

本文作者:牟相波

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!