Lambda
Lambda 允许把函数作为一个方法的参数,一个 lambda 由 逗号分隔的参数列表、-> 符号、函数体,三部分表示
@FunctionalInterface
声明为函数式接口,有且只能由一个抽象方法
@FunctionalInterfacepublic interface Consumer<T> {void accept(T t);}Consumer<String> consumer = (t) -> {System.out.println(t);};consumer.accept("hello lambda");
方法引用
方法引用方法的参数必须与函数式接口的抽象方法的参数列表保持一致,返回值不做要求
Consumer<String> consumer1 = System.out::println;consumer1.accept("hello world");
方法引用规则
实例对象::实例方法名
// 实例方法引用// BiPredicate<String, String> b = (x, y) -> x.equals(y);BiPredicate<String, String> b = String::equals;boolean test = b.test("a", "b");System.out.println("test = " + test);
类名::静态方法名
// 静态方法引用// Function<Long, Long> f = (x)-> Math.abs(x);Function<Long, Long> f = Math::abs;Long ret = f.apply(-100L);System.out.println("ret = " + ret);
类名::实例方法名
// 构造方法引用// Function<Integer, StringBuilder> fun = (n) -> new StringBuilder(n);Function<Integer, StringBuilder> fun = StringBuilder::new;StringBuilder builder = fun.apply(10);
数组引用
// 数组引用// Function<Integer, String[]> func = (n) -> new String[n];Function<Integer, String[]> func = String[]::new;String[] arr = func.apply(10);
Optional
空指针异常是导致 Java 应用程序失败的最常见的问题,以前为了解决空指针异常,Google 公司著名的 Guava 项目引入了 Optional 类,Guava 通过使用检查空值的方式来防止代码污染,它还鼓励程序员写更干净的代码,收到 Google Guava 的启发,Optional 类已经称为 Java 8 类库的一部分。
Optional 实际上是一个容器,它可以保存类型 T 的值,或者仅仅保存 null。Optional 提供很多有用的方法,这样我们就可以不用显示的进行空值检测。
创建 Optional 对象的几个方法
- Optional.of(T value):返回一个 Optional 类的对象,value 不能为空,否则会出空指针异常
- Optional.ofNullable(T value):返回一个 Optional 类的对象,value 可以为空
- Optional.empty():代表空
其他 API
- Optional.isPresent():是否存在值(不为空)
- optional.ifPresent(Consumer<? super T> consumer):如果存在值,则执行 consumer
- optional.get():获取 value
- optional.orElse(T other):如果没有值,则返回 other
- optional.orElseGet(Supplier<? extend T> other):如果没有值,则执行 other 并返回
- optional.orElseThrow(Supplier<? extend X> exceptionSupplier):如果没有值,则执行 exceptionSupplier,并抛出异常
Stream
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的集合操作(aggregate operation),或者大批量数据操作(bulk data operation)。Stream API 借助于同样新出现的 lambda 表达式,极大的提高了编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork / join 并行方式来拆分任务和加速处理过程,通常编写并行代码很难而且容易出错,但使用 Stream API 无需编写一行多线程的代码,就可以很方便的写出高性能的并发程序,所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言 + 多核时代综合影响的产物。
在传统的 J2EE 应用中,Java 代码经常不得不依赖关系型数据库的操作,如:取平均值,取最大最小值,取汇总值,或者进行分组等等类似这样的操作。但是当今这个大数据爆炸的时代,在数据来源多样化,数据海量化的今天,很多时候不得不脱离 RDMBS,或者以底层返回数据为基础进行更上层的数据统计,而 Java 的集合 API 中,仅仅有极少量的辅助型方法,更多的时候还需要程序员用 Iterator 来遍历集合,完成相关的聚合应用逻辑。这是一种不够高效,笨拙的方法
public class Test {public static void main(String[] args) {final Collection<Student> students = Arrays.asList(new Student(1, Grade.FIRST, 60),new Student(2, Grade.SECOND, 80),new Student(3, Grade.FIRST, 100));tradition(students);stream(students);}// 传统的方式public static void tradition(Collection<Student> students) {List<Student> gradeOneStudent = new ArrayList<>();for (Student student : students) {if (Grade.FIRST.equals(student.getGrade())) {gradeOneStudent.add(student);}}Collections.sort(gradeOneStudent, (o1, o2) -> o2.getScore().compareTo(o1.getScore()));List<Integer> studentIds = new ArrayList<>();for (Student student : gradeOneStudent) {studentIds.add(student.getId());}System.out.println("studentIds = " + studentIds);}// stream 方式public static void stream(Collection<Student> students) {List<Integer> studentIds = students.stream().filter(student -> Grade.FIRST.equals(student.getGrade())).sorted(Comparator.comparingInt(Student::getScore).reversed()).map(Student::getId).collect(Collectors.toList());System.out.println("studentIds = " + studentIds);}}
构造流
// Individual valuesStream<String> stream = Stream.of("a", "b", "c");// ArraysString[] arr = new String[]{"a", "b", "c"};stream = Stream.of(arr);stream = Arrays.stream(arr);// ListList<String> list = Arrays.asList(arr);stream = list.stream();
需要注意的是,对于基本数据类型,目前有三种对应的包装类型的 Stream:
IntStream,LongStream,DoubleStream,当然我们也可以使用 Stream
