一、JDK8新特性:Lambda表达式
1.Lambda表达式及其使用举例
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
- Comparator
com1 =new Comparator(){ - @Override
- public int compare(Integer o1,Integer o2){
- return Integer.compare(o1,o2);
- }
- };
- Comparator
com2 = (Integer o1,Integer o2)->{ - return Integer.compare(o1,o2);
- };
(1)lambda表达式使用:
- ->:lambda操作符或箭头操作符
- ->的左边:lambda形参列表,对应着要重写的接口中的抽象方法的形参列表,由一对小括号表示
- ->的右边:lambda体,对应着接口的实现类要重写的方法的方法体,由一对中括号表示
- 形参列表中的数据类型可以省略,因为可由编译器推断得出,称为"类型推断"
- lambda表达式若只需要一个参数时形参列表的小括号可以省略
- lambda体只有一条语句时return与大括号都可以省略,两个需要同时省略
(2)lambda表达式的本质:
a.lambda表达式作为接口的实现类的对象;
b.lambda表达式是一个匿名函数
2.函数式接口:
(1)概念:如果接口中只声明一个抽象方法,则此接口称为函数式接口;因为只有给函数式接口提供实现类的对象时才可以使用lambda表达式;
(2)API中函数式接口所在的包:java.util.function
(3)4个基本的函数式接口
| 函数式接口 | 称谓 | 参数类型 | 用途 |
| Consumer | 消费型接口 | T | 对类型为T的对象应用操作,包含方法:void accpet(T t) |
| Supplier | 供给型接口 | 无 | 返回类型为T的对象,包含方法:T get() |
| Function | 函数型接口 | T | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象,包含方法:R apply(T t) |
| Predicate | 判断型接口 | T | 确定类型为T的对象是否满足某种约束,并返回boolean值,包含方法:boolean test(T t) |
(4)消费型接口:有形参,但是返回值为void
| 接口名 | 抽象方法 | 描述 |
| BiConsumer | void accept(T t,U u) | 接收两个对象用于完成功能 |
| DoubleConsumer | void accept(double value) | 接收一个double值 |
| IntConsumer | void accept(int value) | 接收一个int值 |
| LongConsumer | void accept(long value) | 接收一个long值 |
| ObjDoubleConsumer | void accept(T t,double value) | 接收一个对象和一个double值 |
| ObjIntConsumer | void accept(T t,int value) | 接收一个对象和一个int值 |
| ObjLongConsumer | void accept(T t,long value) | 接收一个对象和一个long值 |
(5)供给型接口:无形参,有返回值
| 接口名 | 抽象方法 | 描述 |
| BooleanSupplier | boolean getAsBoolean() | 返回一个boolean值 |
| DoubleSupplier | double getAsDouble() | 返回一个double值 |
| IntSupplier | int getAsInt() | 返回一个int值 |
| LongSupplier | long getAsLong() | 返回一个long值 |
(6)函数型接口:既有参数也有返回值
| 接口名 | 抽象方法 | 描述 |
| UnaryOperator | T apply(T t) | 接收一个T类型对象,返回一个T类型结果 |
| DoubleFunction | R apply(double value) | 接收一个double值,返回一个R类型结果 |
| IntFunction | R apply(int value) | 接收一个int值,返回一个R类型结果 |
| LongFunction | R apply(long value) | 接收一个long值,返回一个R类型结果 |
| ToDoubleFunction | double applyAsDouble(T value) | 接收一个T类型对象,返回一个double结果 |
| ToIntFunction | double applyAsInt(T value) | 接收一个T类型对象,返回一个int结果 |
| ToLongFunction | double applyAsLong(T value) | 接收一个T类型对象,返回一个long结果 |
| DoubleToIntFunction | int applyAsInt(double value) | 接收一个double值,返回一个int结果 |
| DoubleToLongFunction | int applyAsLong(double value) | 接收一个double值,返回一个long结果 |
| IntToDoubleFunction | int applyAsDouble(int value) | 接收一个int值,返回一个double结果 |
| LongToDoubleFunction | int applyAsDouble(long value) | 接收一个long值,返回一个double结果 |
| IntToLongFunction | int applyAsLong(int value) | 接收一个int值,返回一个long结果 |
| LongToIntFunction | int applyAsInt(long value) | 接收一个long值,返回一个int结果 |
| BinaryOperator | T apply(T t,T u) | 接收两个T类型对象,返回一个T类型对象结果 |
| ToDoubleBiFunction | double applyAsDouble(T t,U u) | 接收一个T类型和一个U类型对象,返回一个double |
| ToLongBiFunction | double applyAsLong(T t,U u) | 接收一个T类型和一个U类型对象,返回一个long |
| DoubleBinaryOperator | double applyAsDouble(double d1,double d2) | 接收两个double值,返回一个double值 |
| ToIntBiFunction | double applyAsInt(T t,U u) | 接收一个T类型和一个U类型对象,返回一个int |
| IntBinaryOperator | int applyAsInt(int i1,int i2) | 接收两个int值,返回一个int值 |
| LongBinaryOperator | long applyAsLong(long l1,long l2) | 接收两个long值,返回一个long值 |
(7)判断型接口:有形参,返回值是boolean的结果
| 接口名 | 抽象方法 | 描述 |
| BiPredicate | boolean test(T t,U u) | 接收两个对象 |
| DoublePredicate | boolean test(double value) | 接收一个double值 |
| IntPredicate | boolean test(int value) | 接收一个int值 |
| LongPredicate | boolean test(long value) | 接收一个long值 |
3.Lambda表达式的语法规则:
- ->:lambda操作符或箭头操作符
- 1.->的左边:lambda形参列表,对应着要重写的接口中的抽象方法的形参列表,由一对小括号表示
- 参数的类型都可以省略;如果形参只有一个则一对()也可以省略;
- 2.->的右边:lambda体,对应着接口的实现类要重写的方法的方法体,由一对{}表示
- 如果方法体中只有一条执行语句则{}可以省略;如果有return关键字则必须一并省略;
二、方法引用
1.方法引用的理解:
(1)方法引用可以看作是Lambda表达式的进一步刻画;
(2)当需要提供一个函数式接口的实例时可以使用lambda表达式提供此实例;
(3)当满足一定的条件的情况下还可以使用方法引用或构造器引用替换lambda表达式;
2.方法引用的本质:方法引用作为了函数式接口的实例
3.使用格式:
- 类(或对象)::方法名
- 情况1:对象名::实例方法名
- 函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值类型都相同,
- 此时可以考虑使用方法b实现对方法a的替换、覆盖;此方法b是非静态的方法、需要对象调用;
- 情况2:类名::静态方法名
- 函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都一致,
- 此时可以考虑使用方法b实现对方法a的替换、覆盖;此方法b是静态的方法、需要类调用;
- 情况3:类名::实例方法名
- 函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值类型相同;
- 同时抽象
- 方法a中有n个参数,方法b中有n-1个参数,且抽象方法a的第一个参数为方法b的调用者并且抽象方法a的后n-1个参数的类型相同或一致,此时可以考虑使用方法b实现对方法a的替换、覆盖;
- 此方法b是非静态的方法,需要对象调用,但是形式上写成对象a所属的类;
三、构造器引用
1.格式:
类名::new
2.说明:
(1)调用了类名对应的类中的某一个确定的构造器;
(2)具体调用的构造器取决于函数式接口的抽象方法的形参列表;
四、StreamAPI:
1.说明:
Stream API(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。Stream是Java8中处理集合的关键抽象概念,可以指定希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作就类似于使用 SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简言之Stream API提供了一种高效且易于使用的处理数据的方式。
2.Stream API与集合框架的对比:
(1)Stream API关注的是多个数据的计算(排序、查找、过滤、映射、遍历等)是面向CPU的,集合关注的数据的存储是面向内存的;
(2)Stream API之于集合类似于SQL之于数据表的查询;
3.注意事项:
(1)Stream自己不会存储元素
(2)Stream不会改变源对象。相反会返回一个持有结果的新Stream。
(3)Stream操作是延迟执行的。这意味着会等到需要结果的时候才执行。即一旦执行终止操作,就执行中间操作链,并产生相应的结果;
(4)Stream一旦执行了终止操作就不能再调用其它中间操作或终止操作;
4.Stream执行流程:

- 1.Stream实例化
- (1)通过集合获取Stream的实例:
- a.default Stream
stream():返回一个顺序流 - b.default Stream
parallelStream():返回一个并行流 - (2)通过数组获取Stream的实例:
- a.Arrays工具类中的方法:static
Stream stream(T[] array); - (3)通过Stream类中的静态of()方法
- 2.一系列的中间操作
- 每次处理都会返回一个持有结果的新Stream,即中间操作的方法返回值仍然是Stream类型的对象;
- 因此中间操作可以是个操作链,可对数据源的数据进行n次处理,但是在终结操作前并不会真正执行;
- (1)筛选与切片
- a.filter(Predicatep):接收Lambda,从流中排除某些元素;
- b.distinct():筛选,通过流所生成元素的hashCode()和equals()去除重复元素;
- c.limit(long maxSize):截断流,使其元素不超过给定数量;
- d.skip(long n):跳过元素,返回一个扔掉了前n个元素的流;若流中元素不足n个则返回一个空流,与limit(n)互补;
- (2)映射:
- a.map(Function f):接收一个函数作为参数,该函数会应用到每个元素并将其映射成一个新的元素;
- b.mapToDouble(ToDoubleFunction f):接收一个函数作为参数,该函数会应用到每个元素上,产生一个新的DoubleStream;
- c.mapToInt(ToIntFunction f):接收一个函数作为参数,该函数会应用到每个元素上产生一个新的IntStream;
- d.mapToLong(ToLongFunction f):接收一个函数作为参数,该函数会应用到每个元素上产生一个新的LongStream;
- e.flatMap(Function f):接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流;
- (3)排序:
- a.sorted():产生一个新流,其中按自然顺序排序;
- b.sorted(Comparator com):产生一个新流,其中按比较器顺序排序;
- 3.终止操作
- 终止操作的方法返回值类型就不再是Stream了,因此一旦执行终止操作就结束整个stream操作;
- 一旦执行终止操作就执行中间操作链,最终产生结果并结束Stream;
- (1)匹配与查找:
- a.allMatch(Predicate p):检查是否匹配所有元素
- b.anyMatch(Predicate p):检查是否至少匹配一个元素
- c.noneMatc(Predicate p):检查是否没有匹配所有元素
- d.findFirst():返回第一个元素
- e.findAny():返回当前流中的任意元素
- f.count():返回流中元素总数
- g.max(Comparator c):返回流中最大值
- h.min(Comparator c):返回流中最小值
- i.forEach(Consumer c):内部迭代(使用Collection接口需要用户去做选代,称为外部迭代.相反,Stream API使用内部迭代)
- (2)规约:
- a.reduce(T identity, BinaryOperator b):可以将流中元素反复结合起来得到一个值,返回T;
- b.reduce(Binaryoperator b):可以将流中元素反复结合起来得到一个值,返回Optional
- (3)收集:
- collect(Collector c):将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法;