什么是Lambda表达式

Lambda表达式可以理解为一种匿名函数:没有名称,但有参数列表、函数体和返回类型,可能还有一个可抛出异常列表

Lambda表达式组成

  • (parameters) -> expression
  • (parameters) -> {expression;}
$$ \underbrace{(Apple \quad a1, Apple \quad a2)}_{参数列表}\quad \overbrace{->}^{箭头}\quad \underbrace{a1.getWeight()-a2.getWeight()}_{函数主体} $$

在哪里以及如何使用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字符串长度并返回List

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class FunctionDemo {
    public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
        List<R> result = new ArrayList<>();
        for (T e: list){
            result.add(f.apply(e));
        }
        return result;
    }

    public static void main(String[] args) {
        List<Integer> result = map(
        	Arrays.asList("binbean", "", "mao"), 
        	s -> s.length());
        System.out.println(result);
    }
}

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 list) ->list,isEmpty() Predicate
创建对象 () -> new Apple(10) Supplier
消费一个对象 (Apple a) -> System.out.println(a.getWeight()) Consumer
从一个对象选择/抽取 (String s) -> s.length() FunctionInteger>,
ToIntFunction
合并两个值 (int a, int b) -> a*b IntBinaryOperator
对象比较 (Apple a1, Apple a2) -> a1.getWeight() - a2.getWeight() Comparator
BiFunction
ToIntBiFunction

异常处理

1
2
3
4
5
// 接口函数
@FunctionalInterface
public interface BufferReaderProcessor {
    String process(BufferedReader b) throws IOException;
}
1
2
3
4
5
6
7
Function<BufferedReader, String> f = (BufferedReader br) -> {
        try{
            return br.readLine();
        }catch (IOException e){
            throw new RuntimeException();
        }
};

使用局部变量

局部变量必须显式声明为final

反列

1
2
3
int portNumber = 1337;
//错误:Lambda表达式引用非final声明的局部变量
Runable r = () -> System.out.println(portNumber);

方法引用

方法引用可以被看作仅仅调用特定方法的Lambda 的一种快捷写法。能提高代码可读性。

三类方法引用

  • 静态方法的方法引用,例如:Integer::parseInt
  • 实例方法的方法引用, 例如:String:length
  • 指向现有对象的实例方法的方法引用

构造函数应用

  • Supplier

    1
    2
    3
    4
    
    //public Apple(){}
    Supplier<Apple> supplier = Apple::new;
    // 返回Apple对象
    Apple apple = supplier.get();

等价于下面代码

1
2
3
Supplier<Apple> supplier = () -> new Apple();
// 返回Apple对象
Apple apple = supplier.get();
  • Function

    1
    2
    3
    
    //public Apple(Integer weight){...}
    Function<Integer, Apple> function = Apple::new;
    Apple apple1 = function.apply(10);

等价于下面代码

1
2
Function<Integer, Apple> function = weight -> new Apple(weight);
Apple apple1 = function.apply(100);
  • BiFunction

    1
    2
    3
    
    //public Apple(Integer weight, String color){...}
    BiFunction<Integer, String, Apple> biFunction = Apple::new;
    Apple apple2 = biFunction.apply(150, "green");

等价于下面代码

1
2
3
BiFunction<Integer, String, Apple> biFunction = 
                (weight, color) -> new Apple(weight, color);
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

使用函数引用实现苹果排序

1
2
3
4
5
6
7
List<Apple> inventory = Arrays.asList(
                new Apple(80, "green"),
                new Apple(155, "green"),
                new Apple(120, "red"));
//comparingInt int基本类型特殊处理,减少自动装箱/开箱的开销                
inventory.sort(Comparator.comparingInt(Apple::getWeight));
inventory.sort(Comparator.comparing(Apple::getColor));

comparingcomparingIntComparator函数式接口的默认实现。comparingIntint基础类型的特殊处理,以减少自动装箱/开箱的开销。