为什么要引入 Lambda 表达式

函数式编程的演化历程

/**
 * Sku选择谓词接口
 */
public interface SkuPredicate {
    /**
     * 选择判断标准
     * @param sku
     * @return
     */
    boolean test(Sku sku);
}
/**
 * 对Sku的总价是否超出2000作为判断标准
 */
public class SkuTotalPricePredicate implements SkuPredicate {
    @Override
    public boolean test(Sku sku) {
        return sku.getTotalPrice() > 2000;
    }
}
    /**
     * Version 4.0.0
     * 根据不同的Sku判断标准,对Sku列表进行过滤
     * @param cartSkuList
     * @param predicate   - 不同的Sku判断标准策略
     * @return
     */
    public static List<Sku> filterSkus(
            List<Sku> cartSkuList, SkuPredicate predicate) {

        List<Sku> result = new ArrayList<Sku>();
        for (Sku sku : cartSkuList) {
            // 根据不同的Sku判断标准策略,对Sku进行判断
            if (predicate.test(sku)) {
                result.add(sku);
            }
        }
        return result;
    }
    
    @Test
    public void filterSkus2() {
        List<Sku> cartSkuList = CartService.getCartSkuList();

        // 过滤商品总价大于2000的商品
        List<Sku> result = CartService.filterSkus(
                cartSkuList, new SkuTotalPricePredicate());

        System.out.println(JSON.toJSONString(
                result, true));
    }

		@Test
    public void filterSkus3() {
        List<Sku> cartSkuList = CartService.getCartSkuList();

        // 过滤商品单价大于1000的商品
        List<Sku> result = CartService.filterSkus(
                cartSkuList, new SkuPredicate() {
                    @Override
                    public boolean test(Sku sku) {
                        return sku.getSkuPrice() > 1000;
                    }
                });

        System.out.println(JSON.toJSONString(
                result, true));
    }

    @Test
    public void filterSkus4() {
        List<Sku> cartSkuList = CartService.getCartSkuList();

        // 过滤商品单价大于1000的商品
        List<Sku> result = CartService.filterSkus(
                cartSkuList,
                (Sku sku) -> sku.getSkuPrice() > 1000);

        System.out.println(JSON.toJSONString(
                result, true));
    }

利用设计模式中的策略模式,将行为的具体实现通过参数的形式传递到方法中。

Lambda 简单介绍

Java 8 引入函数式编程的风格

函数式编程是一种编程的范式、一种编程的风格和思想。在Java8中函数也是可以作为变量、参数、返回值进行传递的。Lambda 表达式可以代替面向对象风格下的匿名函数, 以前是基于类或匿名类对行为进行传递的,现在是基于函数的, 直接将方法作为入参进行传递。

Lambda 表达式的表现形式

Lambda 表达式特点:可选的类型声明,可以不声明参数类型,可选的参数圆括号,一个参数时不需要写圆括号。没有参数或者多个参数需要写圆括号,可选的大括号,如果主体只包含一个语句时不需要大括号,包含多条语句需要大括号。可选的返回关键字,如果主体只有一个语句返回值,会自动返回,

形式一 没有参数,没有返回值
    () -> System.out.println("Hello world")
    
    @Test
    public void test1(){
        Runnable runnable = () -> System.out.println("Hello world");
        runnable.run();
    }
形式二 一个参数,没有返回值
    (name) -> System.out.println(name) 
     name -> System.out.println(name)
    
    @Test
    public void test2(){
        Consumer consumer = (name) -> System.out.println(name);
        consumer.accept("yuhao");
    }
形式三 没有参数,但主体有多条语句,没有返回值
    () -> {
            System.out.print("Hello");
            System.out.print("world");
        };

		@Test
    public void test3() {
        Runnable runnable = () -> {
            System.out.print("Hello");
            System.out.print("world");
        };
        runnable.run();
    }
形式四 两个参数,有返回值
    @Test
    public void test4() {
        IntBinaryOperator operator = (x, y) -> x + y;
        int sum = operator.applyAsInt(1, 2);
        System.out.println(sum);
    }

以上4个例子都是使用的 JDK 内置的4个函数式接口,如何定义函数式接口才能符合 Lambda 规范?

要求:

JDK 常用的函数式接口

接口 参数 返回值 描述 类型
Predicate T boolean 用于判断一个对象 判断
Consumer T void 用于接收一个对象并处理,但是没有返回值。 消费
Function T R 用于将一个对象转换为另一个对象。 函数
Supplier T 提供一个对象 供给
UnaryOperator T T 接收一个类型对象并返回一个同类型的对象 -
BinaryOperator (T,T) T 接收两个同类型的对象并返回一个原类型的对象 -

方法引用

一种简写的 Lambda 表达式

目标引用 :: 方法名

如 Sku::getSkuPrice

指向静态方法的方法引用

    (args) -> ClassName.staticMethod(args);
		ClassName::staticMethod;
		@Test
    public void test5() {
        Consumer<String> consumer = str -> Integer.parseInt(str);
        consumer.accept("100");
        Consumer<String> consumer1 = Integer::parseInt;
        consumer1.accept("100");
    }

指向实例方法的方法引用

	  //(args) -> args.instanceMethod();
    //ClassName::instanceMethod;
    @Test
    public void test6() {
        Consumer<Integer> consumer = integer -> integer.intValue();
        consumer.accept(new Integer(100));
        Consumer<Integer>  consumer1 = Integer::intValue;
        consumer1.accept(new Integer(100));
    }

指向现有对象实例方法的方法引用

    @Test
    public void test7() {
        //(args) -> instance.instanceMethod();
        //instance::instanceMethod;
        StringBuilder builder = new StringBuilder();
        Consumer<String> consumer = str -> builder.append(str);
        consumer.accept("100");
        Consumer<String> consumer1 = builder::append;
        consumer1.accept("100");
    }