• Java8之lambda表达式


    简介

    Lambda 表达式是 Java 1.8 跟 Stream 机制一同推出的。Lambda 表达式极大地减少了代码量,增加了代码的可读性。
    引入 Lambda 表达式之后,Java 开始支持把函数作为参数传递

    前置条件

    使用 Lambda 表达式的前置条件,作为参数的接口必须是函数式接口

    1. 首先类型必须是接口 interface,不能是类 class。比如,抽象类就不可以。
    2. 函数式接口有且仅有一个未被覆写的抽象方法

    举例:

    • Object 中方法不算
    // MyRunnable 仍然算是一个“函数式接口”
    public interface MyRunnable extends Runnable {
        String toString();
        boolean equals(Object obj);
        int hashCode();
    }
    
    • 接口中的 default 方法不算
    // MyRunnable2 仍然算是一个“函数式接口”
    public interface MyRunnable2 extends Runnable {
        default void run2() {}
    }
    

    FunctionalInterface 注解

    @FunctionalInterface 可以帮助我们在编译期识别出一个接口是否是“函数式接口”:

    Not Functional Interface

    参数的传递

    假如我们有一个如下含义的“函数式接口”:

    @FunctionalInterface
    public interface Formatter {
        void format(String name, int age);
    }
    

    我们可以构造一个测试:

    public class LambdaTest {
    
        public static void main(String[] args) {
            print((String name, int age)-> System.out.println(String.format("name:%s age:%d", name, age)), "ziyu", 18);
        }
    
        public static void print(Formatter formatter, String name, int age) {
            formatter.format(name, age);
        }
    }
    

    多个参数

    当有多个参数时,可以选择省略所有参数类型声明:
    lambda-params
    注意:
    不能省略一部分保留一部分。(String name, age) -> System.out.println(name); 这是不合法的!

    单个参数

    lambda-param
    当只有一个参数时,除了可以省略参数类型,还可以进一步省略掉括号。

    编写方式

    没有返回值

    Runnable 就是一个常用的“函数式接口”,它的抽象方法 run() “没有返回值”, 刚好适合用于此处的演示。测试例子如下:

    public class LambdaTest2 {
        public static void main(String[] args) {
            runIt(()->{
                System.out.println("123");
            });
        }
    
        static void runIt(Runnable runnable) {
            new Thread(runnable).start();
        }
    }
    

    return-void

    • 如果写成多行表达式,那么需要 {} 来表示代码块,且每一行代码结束时需要书写 ; 表示语句的结束。
    • 如果代码块中只有一条语句,那么可以通过省略 {}; 来简写为单行表达式

    有返回值

    我们定义一个 IdFactory 接口来做演示:

    public interface IdFactory {
        String generateId();
    }
    

    我们的示例代码如下:

    import java.util.UUID;
    
    public class LambdaTest3 {
    
        public static void main(String[] args) {
            String name = getId(()-> UUID.randomUUID() + "");
            System.out.println(name);
        }
    
        static String getId(IdFactory factory) {
            return factory.generateId();
        }
    
    }
    

    return-string

    • 如果写成多行表达式,除了需要 {} 来表示代码块,和每一行代码结束时需要书写 ; 表示语句的结束以外,还应该在需要返回值的方法用 return 来返回值。
    • 如果代码块中只有一条语句,那么可以通过省略 {}; 以及 return 来简写为单行表达式

    方法引用

    比如我们要写一段代码,用来打印出完整的加法表达式 a + b = c,并且要求根据 a 和 b 求出 c 作为函数返回值。
    首先我们定一个“计算器”接口:

    public interface Calculator {
        int compute(int a, int b);
    }
    

    接着我们写一个测试用例:

    public class LambdaTest3 {
    
        public static void main(String[] args) {
            int a = 10;
            int b = 20;
            // 这里不能用 (a, b), 那样的话会产生歧义,使得编译器报错
            runIt((x, y)->{
                System.out.print(x);
                System.out.print(" + ");
                System.out.print(y);
                System.out.print(" = ");
                System.out.println(x + y);
                return x + y;
            }, a, b);
        }
    
        static void runIt(Calculator calculator, int a, int b) {
            calculator.compute(a, b);
        }
    }
    

    静态方法引用

    static-method-reference

    • 在 LambdaTest2 中定一个静态方法 sum
    • 使用静态方法引用 LambdaTest2::sum
    • 这样在运行静态方法 runIt 中的第一行 calculator.compute(a, b) 时,ab 会通过静态方法引用传递给静态方法 sum

    通过这种方式,即简化了参数的传递,也把“多行表达式”简化为了“单行表达式”

    成员方法引用

    member-method-reference

    • new LambdaTest2()::sum: 先新建对象 LambdaTest2,并且通过该对象来使用成员变量引用
      小贴士:
      如果先声明变量 obj,再使用 obj::sum 也是合法的。
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        LambdaTest2 obj = new LambdaTest2();
        runIt(obj::sum, a, b);
    }
    

    总结

    • Lambda表达式的前置条件:必须是“函数式接口”
    • 单个参数传递时,可以省略参数两端的括号。参数的类型可以一起省略。
    • 编写的方式主要包括单行表达式和多行表达式
    • 可以使用方法引用来把多行表达式写成单行表达式。方法引用又包括了静态方法引用和动态方法引用。
  • 相关阅读:
    Entity Framework 学习中级篇3—存储过程(中)
    Entity Framework 学习高级篇1—改善EF代码的方法(上)
    Entity Framework 学习中级篇2—存储过程(上)
    Entity Framework 学习初级篇7基本操作:增加、更新、删除、事务
    Entity Framework 学习中级篇4—存储过程(下)
    Entity Framework 学习初级篇5ObjectQuery查询及方法
    LINQ之路 9:LINQ to SQL 和 Entity Framework(上)
    在List创建的时候自动加上Rating功能
    利用Feature receiver自动注册/卸载Http Module
    使用SharePoint Web Service(1):创建子站点
  • 原文地址:https://www.cnblogs.com/kendoziyu/p/java8-lambda-expression.html
Copyright © 2020-2023  润新知