Lambda 精简总结

114 阅读4分钟

Lambda 表达式可简化创建匿名内部类对象;

Lambda 表达式=匿名方法;

Lambda 表达式用于实现抽象方法的方法体;

Lambda 表达式三部分:

形参列表:形参列表允许省略类型;如果形参列表中只有一个参数,可以省略形参列表括号

箭头:(->)

代码块:代码块只有一条语句可省略花括号;代码块只有一条 return 语句可以省略 return
class LambdaQs {

    public void eat(Eating e) {
        System.out.println(e);
        e.taste();
    }

    public void fly(Flying f) {
        System.out.println(f);
        f.fly("Sunny");
    }

    public void calc(Adding add) {
        System.out.println("5 + 3 = " + add.add(5, 3));
    }

    public static void main(String[] args) {
        LambdaQs lq = new LambdaQs();

        // Lambda 表达式的代码块只有一句,因此省略了花括号
        lq.eat(() -> System.out.println("Taste great"));

        // Lambda 表达式的形参只有一个参数,因此省略了圆括号
        lq.fly(weather -> {
            // 对接口中抽象方法 fly 的重写
            System.out.println("Weather today is " + weather);
            System.out.println("Everything well!");
        });

        // Lambda 表达式只有一条语句,即使该表达式需要返回值,也可以省略 return
        lq.calc((a, b) -> a + b);
        // 如果不用 Lambda 表达式,就需要如下匿名类的方式去重写抽象方法
        lq.calc(new Adding() {
            @Override
            public int add(int a, int b) {
                return a + b;
            }
        });
    }
}

Lambda 表达式的目标类型必须是函数式接口:

函数式接口代表只包含一个抽象方法的接口;

函数式接口可以包含多个默认方法、类方法,但仅能声明一个抽象方法。

Lambda 表达式目标类型强制转换为函数式接口:

Lambda 表达式赋值给函数式接口类型的变量;

Lambda 表达式作为函数式接口类型的参数传给某个方法;

使用函数式接口对 Lambda 表达式进行强制类型转换。
interface Runnable {
    void run();
}

class Running{
    Runnable r = () -> {
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    };
    // False
    Object obj = () -> {
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    };
}

interface Runnable {
    void run();
}

class Running{
    Runnable r = () -> {
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    };
    // Right
    Object obj1 = (Runnable)() -> {
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    };
}

1. 消费型接口:Consumer< T> void accept(T t)有参数,无返回值的抽象方法;

2. 供给型接口:Supplier < T> T get() 无参有返回值的抽象方法;

3. 断定型接口: Predicate< T> boolean test(T t):有参,但是返回值类型是固定的boolean

4. 函数型接口: Function< T,R> R apply(T t)有参有返回值的抽象方法;

Lambda 表达式的代码块只有一条代码,可以在代码中使用方法引用和构造器引用使 Lambda 表达式的代码块更加简洁。方法引用和构造器引用都需要使用两个英文冒号 ::。

种类示例说明对应的 Lambda 表达式
类名::类方法全部参数传给该类方法作为参数(a,b,...) -> 类名.类方法(a,b,...)
特定对象的实例特定对象::实例方法全部参数传给该方法作为参数(a,b,...) -> 特定对象.实例方法(a,b,...)
某类对象的实例类名::实例方法第一个参数作为调用者后面的参数全部传给该方法作为参数(a,b,...) -> a.实例方法(b,...)
构造器类名::new全部参数传给该构造器作为参数(a,b,...) -> new 类名(a,b,...)
------
public class LambdaDemo {
    public static void main(String[] args){

        // 1.引用类方法
        Converter converter1 = from -> Integer.valueOf(from);
        Integer val1 = converter1.convert("111");
        System.out.println(val1);
        // 全部参数传给类方法作为参数
        Converter converter2 = Integer::valueOf;
        Integer val2 = converter2.convert("222");
        System.out.println(val2);

        // 2.引用特定对象的实例方法
        Converter converter3 = from -> "hello world".indexOf(from);
        Integer val3 = converter3.convert("h");
        System.out.println(val3);
        // 调用 "hello world"::indexOf() 实例方法
        // 全部参数传给该方法作为参数
        Converter converter4 = "hello world"::indexOf;
        Integer val4 = converter4.convert("l");
        System.out.println(val4);

        // 3.引用某类对象的实例方法
        MyTest mt1 = (a, b, c) -> a.substring(b, c);
        String str1 = mt1.test("Hello world", 1, 3);
        System.out.println(str1);
        // 第一个参数作为调用者
        // 后面的参数全部传给该方法作为参数
        MyTest mt2 = String::substring;
        String str2 = mt2.test("Hello world", 1, 3);
        System.out.println(str2);

        // 4.引用构造器
        YourTest yt1 = a -> new JFrame(a);
        JFrame jf1 = yt1.win("Windows");
        // 使用引用构造器进行替换
        // 全部参数传给该构造器作为参数
        YourTest yt2 = JFrame::new;
        JFrame jf2 = yt2.win("Windows");

    }
}

Lambda 表达式调用Arrays的类方法

class LambdaArrays {
    public static void main(String[] args) {
        String[] arr1 = new String[]{"java", "python", "rust", "go"};
        Arrays.parallelSort(arr1, (o1, o2) -> o1.length() - o2.length());
        System.out.println(Arrays.toString(arr1));
        int[] arr2 = {3, -4, 25, 16, 30, 18};
        // left 代表数组中前一个索引处的元素,计算第一个元素时,left 为 1;
        // right 代表数组中的当前索引处的元素
        Arrays.parallelPrefix(arr2, (left, right) -> left * right);
        System.out.println(Arrays.toString(arr2));
        long[] arr3 = new long[5];
        // a 代表正在计算的元素索引
        Arrays.parallelSetAll(arr3, a -> a * 5);
        System.out.println(Arrays.toString(arr3));

        // 等价于用匿名内部类重写 applyAsLong 抽象方法
        Arrays.parallelSetAll(arr3, new IntToLongFunction() {
            @Override
            public long applyAsLong(int value) {
                return value * 5;
            }
        });
        System.out.println(Arrays.toString(arr3));
    }
}

Lambda 表达式类型

class TestLambda {
    public static void main(String[] args) {

        // 无参无返回值
        new Thread(() -> System.out.println("Hello"));

        // 有参无返回值
        ArrayList<String> list = new ArrayList<>();
        list.add("AAAAA");
        list.add("BBBBB");
        list.add("CCCCC");
        list.add("DDDDD");
        // 形参的类型是确定的,可省略;只有一个形参,()可以省略;
        list.forEach(t -> System.out.print(t + "\t"));
        // 更简洁
        list.forEach(System.out::println);

        // 有参有返回值
        Collator collator = Collator.getInstance();
        TreeSet<Student> set = new TreeSet<>((s1, s2) -> collator.compare(s1.getName(),s2.getName()));
        set.add(new Student(10,"AAAAA"));
        set.add(new Student(3,"BBBBB"));
        set.add(new Student(1,"CCCCC"));
        set.forEach(student -> System.out.println(student));

    }
}

class Student{
    private int id;
    private String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public int setId(int id) {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}