14.1 函数式接口
只包含一个抽象方法的接口称为函数式接口。 使用@FunctionalInterface 可以检查是否是函数式接口。Java内置了四大核心函数式接口以及一些其他接口。
| 函数式接口 | 用途 |
|---|---|
| Consumer消费型接口 | void accept(T t) |
| Supplier供给型接口 | T get() |
| Function |
R apply(T t) |
| Predicate断言型接口 | boolean test(T t) |
// 函数式接口举例@FunctionalInterfacepublic interface MyFunc<T> {public T getValue(T t);}
14.2 Lambda表达式
Lambda用于实例化函数式接口对象。以前用匿名实现类表示的现在都可以用Lambda表达式来写。
格式:(参数列表) -> {逻辑实现}
- 左侧:通过声明变量时即可推断出类型,因此可省略参数类型;若参数列表仅一个参数则可省略括号。
- 右侧:如果仅有一条语句可以省略 {}和return 。 ```java // 语法格式一:无参,无返回值 Runnable r1 = () -> { System.out.println(“Hello”); };
//语法格式二:有参数,但是没有返回值。
Consumer
//语法格式三:Lambda 若只需要一个参数时,参数的小括号可以省略
Consumer
//语法格式四:Lambda 可以有两个或以上的参数,多条执行语句,返回值
Comparator
//语法格式五:当 Lambda 体只有一条语句时,return 、{ } 都可以省略
Comparator
<a name="FhyrK"></a>## 14.3 引用<a name="tgM42"></a>### 14.3.1 方法引用当要传递给Lambda体的操作已经有实现的方法了,可以使用方法引用!这就要求实现接口抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!格式:使用操作符 “**::**” 将类(或对象) 与方法名分隔开来。```java// 等价例子1Consumer<String> con = (x) -> System.out.println(x);Consumer<String> con1 = System.out :: println;// 等价例子2Comparator<Integer> com = (x,y) -> Integer.compare(x,y);Comparator<Integer> com1 = Integer::compare;// 等价例子3BiPredicate<String, String> bp = (x, y) -> x.equals(y);BiPredicate<String, String> bp1 = String::equals;
14.3.2 构造器引用
可以把构造器引用赋值给定义的方法,要求构造器参数列表要与接口中抽象方法的参数列表一致!且方法的返回值即为构造器对应类的对象。
格式: ClassName::new
Function<Integer, MyClass> fun = (n) -> new MyClass(n);Function<Integer, MyClass> fun1 = MyClass::new;
格式:type[] :: new
Function<Integer, Integer[]> fun = (n) -> new Integer[n];Function<Integer, Integer[]> fun1 = Integer[]::new;
14.4 Stream API
Stream API 提供了一种高效且易于使用的处理集合数据的方式。
操作步骤:
- 创建Stream:一个数据源(如:集合、数组)获取一个流
- 中间操作:对数据源的数据进行处理,不执行终止操作前不执行
- 终止操作:一旦执行终止操作,就执行中间操作链,并产生结果。之后不能再使用

// 通过集合创建流:Collection 提供了两个获取流的方法default Stream<E> stream() // 返回一个顺序流default Stream<E> parallelStream() // 返回一个并行流// 通过数组创建流: Arrays 的静态方法 stream() 可以获取数组流static <T> Stream<T> stream(T[] array)// 通过Stream的静态方法of()创建流public static<T> Stream<T> of(T... values)// 创建无限流(无限个数据对应的Stream,主要用于造数据)public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) // 迭代public static<T> Stream<T> generate(Supplier<T> s) // 生成// 创建无限流的例子// 从0开始,每次加2的流;中间操作为取前十个数据,终止操作为输出Stream<Integer> stream = Stream.iterate(0, x -> x + 2);stream.limit(10).forEach(System.out::println);// 生成随机数的流;中间操作为取前十个数据,终止操作为输出Stream<Double> stream1 = Stream.generate(Math::random);stream1.limit(10).forEach(System.out::println);
// 1-筛选与切片filter(Predicate p) // 接收 Lambda, 从流中排除某些元素distinct() // 通过流元素的 hashCode() 和 equals() 去重limit(long maxSize) // 截断流,使其元素不超过给定数量skip(long n) // 返回扔掉前 n 个元素的流。若流中元素不足 n 个,则返回个空流// 2-映射map(Function f) // 将函数应用到流中每个元素上flatMap(Function f) // 将流中的每个值都换成另一个流,然后把所有流连接成一个流。该方法用于处理集合套集合的情况。例如[1,2,3,[2,3,4]]此种类型的集合,使用map处理完之后集合中有4个元素,而使用floatMap处理完之后,集合中有6个元素// 3-排序sorted() // 产生一个新流,按自然顺序排序sorted(Comparator com) // 产生一个新流,按比较器顺序排序
终止操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。 流执行了终止操作后,将不能再次使用。
// 1-匹配与查找allMatch(Predicate p) // 检查是否匹配所有元素anyMatch(Predicate p) // 检查是否至少匹配一个元素noneMatch(Predicate p) // 检查是否没有匹配所有元素findFirst() // 返回第一个元素findAny() // 返回当前流中的任意元素count() // 返回流中元素总数max(Comparator c) // 返回流中最大值min(Comparator c) // 返回流中最小值forEach(Consumer c) // 数据迭代// 2-归约reduce(T iden, BinaryOperator b) // 在初始情况为iden的情况下,使用BinaryOperator反复操作合计并累计起来,返回一个值// 例子:计算1-10的自然数的和List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);Integer sum1 = list.stream().reduce(0, Integer::sum);Integer sum2 = list.stream().reduce(10, (x, y) -> x + y);System.out.println(sum1 + " " + sum2);// 55 65// 3-收集collect(Collector c) // 将Collector 接口中方法的实现决定了如何对流执行收集的操作(如收集到 List、Set、Map)。
Collectors 类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法如下:
// toList List<T> 把流中元素收集到ListList<Employee> emps= list.stream().collect(Collectors.toList());// toSet Set<T> 把流中元素收集到SetSet<Employee> emps= list.stream().collect(Collectors.toSet());// counting Long 计算流中元素的个数long count = list.stream().collect(Collectors.counting());// summingInt Integer 对流中元素的整数属性求和int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));// averagingInt Double 计算流中元素Integer属性的平均值double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary));// joining String 连接流中每个字符串String str= list.stream().map(Employee::getName).collect(Collectors.joining());// maxBy Optional<T> 根据比较器选择最大值Optional<Emp>max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));// groupingBy Map<K, List<T>> 根据某属性值对流分组,属性为K,结果为VMap<Emp.Status, List<Emp>> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));// partitioningBy Map<Boolean, List<T>> 根据true或false进行分区Map<Boolean,List<Emp>> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage));
14.5 Optional类
Optional 类是一个容器类,它仅保存一个类型T的值,代表这个值存在,或者保存null,表示这个值不存在。可以避免空指针异常。
// 创建Optional类Optional.of(T t) // 创建一个 Optional 实例,t必须非空;Optional.empty() // 创建一个空的 Optional 实例Optional.ofNullable(T t) // t可以为null// 判断Optional容器是否包含对象:boolean isPresent() : // 判断是否包含对象void ifPresent(Consumer<? super T> consumer) // 如果有值,就执行Consumer接口的实现代码// 获取Optional容器包含的对象:T get() // 包含则返回该值,否则抛异常// 通过下述方法可以保证不会返回nullT orElse(T other) // 如果有值则将其返回,否则返回指定的other对象。T orElseGet(Supplier<? extends T> other) // 如果有值则将其返回,否则返回由Supplier接口实现提供的对象。T orElseThrow(Supplier<? extends X> exceptionSupplier) // 如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
下面展示一些使用Optional类避免空指针异常的情况。
public void test1() {Boy b = new Boy("张三");Optional<Girl> opt = Optional.ofNullable(b.getGrilFriend()); // getGrilFriend可能返回null// 如果女朋友存在就打印女朋友的信息opt.ifPresent(System.out::println);// 如果有女朋友就返回他的女朋友,否则只能欣赏“嫦娥”了Girl girl = opt.orElse(new Girl("嫦娥"));System.out.println("他的女朋友是:" + girl.getName());}public void test2{Optional<Employee> opt = Optional.of(new Employee("张三", 8888));//判断opt中员工对象是否满足条件,如果满足就保留,否则返回空Optional<Employee> emp = opt.filter(e -> e.getSalary()>10000);System.out.println(emp);}
