Java8学习二 Lambda表达式
文章目录
什么是Lambda表达式
Lambda表达式可以理解为一种匿名函数:没有名称,但有参数列表、函数体和返回类型,可能还有一个可抛出异常列表
Lambda表达式组成
- (parameters) -> expression
- (parameters) -> {expression;}
在哪里以及如何使用Lambda表达式
在函数式接口上使用Lambda表达式。
函数式接口
只定义了一个抽象方法的接口(Java8中接口有默认方法)
函数描述符
函数式接口的抽象方法签名,即接受什么参数,返回什么值类型。
例如:
() -> void
,没有参数也没有返回值,这正是Runable接口的代表。
@FunctionalInterface
这个标注用于表示该接口会设计成一个函数式接口。 如果你用@FunctionalInterface定义了一个接口, 而它却不是函数式接口的话, 编译器将返回一个提示原因的错误。 例如,错误消息可能是“ Multiple non- overriding abstract methods found in interface Foo”。
使用函数式接口
Java8提供,在java.util.function
包中
- Predicate
接口: (T) -> boolean
1 2 3 |
@FunctionalInterface public interface Predicate< T>{ boolean test( T t); } |
使用示例:过滤空字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class PredicateDemo { public static <T>List<T> filter(List<T> list, Predicate<T> p) { List<T> result = new ArrayList<>(); for (T e : list){ if (p.test(e)){ result.add(e); } } return result; } public static void main(String[] args) { Predicate<String> noEmtpyString = s -> !s.isEmpty(); List<String> result = filter( Arrays.asList("11", "", "23"), noEmtpyString); System.out.println(result); } } |
- Consumer
接口: (T) -> void
1 2 3 4 |
@FunctionalInterface public interface Consumer<T>{ void accept( T t); } |
使用示例:循环打印List数据
1 2 3 4 5 6 7 8 9 10 11 12 |
public class CousumerDemo { public static <T> void forEach(List<T> list, Consumer<T> c){ for (T e : list){ c.accept(e); } } public static void main(String[] args) { forEach(Arrays.asList(1, 2, 3, 4), integer -> System.out.println(integer)); } } |
- Function
接口: (T) -> R
1 2 3 4 |
@FunctionalInterface public interface Function< T, R>{ R apply( T t); } |
使用示例:计算List
|
|
Java8中的常用函数式接口
函数式接口 | 函数描述符 | 原始类型特化 |
---|---|---|
Predicate |
T->boolean | IntPredicate,LongPredicate DoublePredicate |
Consumer |
T->void | IntConsumer,LongConsumer DoubleConsumer |
Function |
T->R | IntFunction IntToDoubleFunction, IntToLongFunction, LongFunction LongToDoubleFunction, LongToIntFunction, DoubleFunction ToIntFunction ToDoubleFunction ToLongFunction |
Supplier |
()->T | BooleanSupplier,IntSupplier, LongSupplier,DoubleSupplier |
UnaryOperator |
T->T | IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator |
BinaryOperator |
(T,T)->T | IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator |
BiPredicate |
(L,R)->boolean | |
BiConsumer |
(T,U)->void | ObjIntConsumer ObjLongConsumer ObjDoubleConsumer |
BiFunction |
(T,U)->R | ToIntBiFunction ToLongBiFunction ToDoubleBiFunction |
使用示例
使用案例 | Lambda | 对应函数接口 |
---|---|---|
返回布尔值 | (List |
Predicate |
创建对象 | () -> new Apple(10) | Supplier |
消费一个对象 | (Apple a) -> System.out.println(a.getWeight()) | Consumer |
从一个对象选择/抽取 | (String s) -> s.length() | Function ToIntFunction |
合并两个值 | (int a, int b) -> a*b | IntBinaryOperator |
对象比较 | (Apple a1, Apple a2) -> a1.getWeight() - a2.getWeight() | Comparator BiFunction ToIntBiFunction |
异常处理
|
|
|
|
使用局部变量
局部变量必须显式声明为final
反列
|
|
方法引用
方法引用可以被看作仅仅调用特定方法的Lambda 的一种快捷写法。能提高代码可读性。
三类方法引用
- 静态方法的方法引用,例如:
Integer::parseInt
- 实例方法的方法引用, 例如:
String:length
- 指向现有对象的实例方法的方法引用
构造函数应用
Supplier
1 2 3 4
//public Apple(){} Supplier<Apple> supplier = Apple::new; // 返回Apple对象 Apple apple = supplier.get();
等价于下面代码
|
|
Function
1 2 3
//public Apple(Integer weight){...} Function<Integer, Apple> function = Apple::new; Apple apple1 = function.apply(10);
等价于下面代码
|
|
BiFunction
1 2 3
//public Apple(Integer weight, String color){...} BiFunction<Integer, String, Apple> biFunction = Apple::new; Apple apple2 = biFunction.apply(150, "green");
等价于下面代码
|
|
复合Lambda表达式用法
比较器复合
1 2 3 4 5 6 7
//逆序 list.sort(Comparator.comparingInt(Apple::getWeight).reversed()); //比较链 list.sort(Comparator.comparingInt(Apple::getWeight) .reversed() .thenComparing(Apple::getColor));
谓词复合:
negate
,and
,or
1 2 3 4 5 6 7 8 9 10 11 12
//红🍎 Predicate<Apple> redApple = apple -> "red".equals(apple.getColor()); // negate:非红🍎 Predicate<Apple> notRedApple = redApple.negate(); //and: 红🍎并且重的(大于150g) Predicate<Apple> redAndHeavyApple = redApple.and( apple -> apple.getWeight() > 150); //and, or: 红🍎并且重的(大于150g)或绿🍎 Predicate<Apple> redAndHeavyOrGreenApple = //redAndHeavyApple.or(apple -> "green".equals(apple.getColor())); redApple.and(apple -> apple.getWeight() > 150) .or(apple -> "green".equals(apple.getColor()));
函数复合:
andThen
,compose
1 2 3 4 5
Function<Integer, Integer> f = x -> x + 1; // 4 == (x + 1) *2 == g(f(x)) int result = f.andThen(x -> x * 2).apply(1); //3 == x * 2 + 1 == f(g(x)) int result2 = f.compose((Integer x) -> x * 2).apply(1);
One more thing
使用函数引用实现苹果排序
|
|
comparing
和comparingInt
是Comparator
函数式接口的默认实现。comparingInt
为int
基础类型的特殊处理,以减少自动装箱/开箱的开销。
文章作者 binbin wen
上次更新 2018-08-30