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,or1 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,compose1 2 3 4 5Function<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