• 19.lambda表达式


    Lambda表达式

    lambda表达式体现的是函数编程思想

    需求: 启动一个线程, 在控制台输出一句话: 多线程程序启动了

    方式一:

    • 定义MyRunnable类实现Runnable接口, 重写run方法
    • 创建Thread类, 将MyRunable的对象作为构造参数
    • 启动线程

    方式二:

    • 匿名内部类的方式改进

    方式三:

    • Lambda表达式的方式改进

    MyRunnable

    package myLambda;
    
    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("多线程启动了");
        }
    }
    
    

    LambdaDemo

    package myLambda;
    
    public class LambdaDemo {
        public static void main(String[] args) {
            // 实现类的方式实现需求
            /*
            MyRunnable my = new MyRunnable();
            Thread t = new Thread(my);
            t.start();
             */
    
            // 匿名内部类
            /*
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("多线程启动了");
                }
            }).start();
             */
    
            // Lambda表达式方式改进
            new Thread(() -> {
                System.out.println("多线程启动了");
            }).start();
        }
    }
    

    Lambda表达式标准格式

    匿名内部类重写run方法的代码分析

    • 方法形式参数为空, 说明调用方法时不需要传递参数
    • 方法返回值类型为void, 说明方法执行没有结果返回
    • 方法体重的内容, 使我们具体要做的事情

    Lambda表达式的代码分析

    • (): 里面没有内容, 可以看成是方法形式参数为空

    • ->: 箭头指向后面要做的事情

    • {}: 包含一段代码, 称之为代码块, 可以看成是方法体中的内容

    组成lambda表达式三要素: 形式参数, 箭头, 代码块

    lambda表达式格式

    • 格式: (形式参数) -> {代码块}
    • 形式参数: 如果有多个参数, 参数之间用逗号隔开; 如果没有参数, 留空即可
    • ->: 由英文中画线和大于符号组成, 固定写法,
    • 代码块: 是具体要做的事情, 也就是以前我们写的方法体内容

    练习

    不带参数

    Eatable

    package myLambda.demo;
    
    public interface Eatable {
        void eat();
    }
    
    

    EatableImpl

    package myLambda.demo;
    
    public class EatableImpl implements Eatable {
        @Override
        public void eat() {
            System.out.println("一天一苹果");
        }
    }
    
    

    EatableDemo

    package myLambda.demo;
    
    public class EatableDemo {
        public static void main(String[] args) {
            // 调用useEatable方法
            Eatable e = new EatableImpl();
            useEatable(e);
            // 匿名内部类
            useEatable(new Eatable() {
                @Override
                public void eat() {
                    System.out.println("一天一苹果");
                }
            });
    
            // lambda表达式 不带参数
            useEatable(() -> {
                System.out.println("一天一苹果");
            });
        }
        private static void useEatable(Eatable e) {
            e.eat();
        }
    }
    
    

    带参数

    Flyable

    package myLambda.demo2;
    
    public interface Flyable {
        void fly(String s);
    }
    
    

    FlyableDemo

    package myLambda.demo2;
    
    public class FlyableDemo {
        public static void main(String[] args) {
            // 匿名内部类
            useFlyable(new Flyable() {
                @Override
                public void fly(String s) {
                    System.out.println(s);
                    System.out.println("飞机自驾游");
                }
            });
    
            // lambda表达式带参数
            useFlyable((String s) -> {
                System.out.println(s);
                System.out.println("飞机自驾游");
            });
        }
        private static void useFlyable(Flyable f) {
            f.fly("风和日丽");
        }
    }
    
    

    多个参数

    Addable

    package myLambda.demo3;
    
    public interface Addable {
        int add(int x, int y);
    }
    
    

    AddableDemo

    package myLambda.demo3;
    
    public class AddableDemo {
        public static void main(String[] args) {
            // lambda表达式实现, 多参数
            useAddable((int x, int y) -> {
                // return x + y;
                return x - y;  // 这里是方法add的具体实现代码块
            });
        }
    
        private static void useAddable(Addable a) {
            int sum = a.add(10, 20);
            System.out.println(sum);
        }
    }
    
    

    lambda省略模式

    省略规则

    • 参数类型可以省略, 多个参数类型不能单独省略一个
    • 如果参数仅有一个, 小括号可以省略
    • 如果代码块只有一句, 可以省略大括号和分号, 甚至是return

    Addable

    package myLambda.demo4;
    
    public interface Addable {
        int add(int x, int y);
    }
    
    

    Flyable

    package myLambda.demo4;
    
    public interface Flyable {
        void fly(String s);
    }
    
    

    LambdaDemo

    package myLambda.demo4;
    
    public class LambdaDemo {
        public static void main(String[] args) {
            /*
            useAddable((int x, int y) -> {
                return x + y;
            });
             */
            // 省略模式一: 参数类型可以省略
            useAddable((x, y) -> {
                return x + y;
            });
    
            // 有多个参数时, 不能单独省略一个, 要么都省略,要么都不省略
    
            /*
            useFlyable((String s) -> {
                System.out.println(s);
            });
             */
    
            useFlyable((s) -> {
                System.out.println(s);
            });
    
            // 省略模式二: 如果参数只有一个, 可以省略小括号
            useFlyable(s -> {
                System.out.println(s);
            });
    
            // 省略模式三: 如果代码块语句只有一条, 可以省略大括号和分号
            useFlyable(s -> System.out.println(s));
    
        }
    
        private static void useFlyable(Flyable f) {
            f.fly("晴空万里");
        }
    
        private static void useAddable(Addable a) {
            int sum = a.add(10, 20);
            System.out.println(sum);
        }
    }
    
    

    lambda表达式注意事项

    注意:

    • 使用Lambda必须要有接口, 并且接口中有且仅有一个抽象方法
    • 必须有上下文环境, 才能推导出Lambda对应的接口
      • 根据局部变量赋值得知lambda对应接口: Runnable r = () -> System.out.println("lambda表达式");
      • 根据调用方法的参数得知lambda对应接口: new Thread(() -> System.out.println("lambda表达式")).start();

    Inter

    package myLambda.demo5;
    
    public interface Inter {
        void show();
        // void method();
    }
    

    LambdaDemo

    package myLambda.demo5;
    
    public class LambdaDemo {
        public static void main(String[] args) {
            /*
            useInter(() -> {
                System.out.println("好好学习, 天天向上");
            });
             */
    
            // lambda表达式前提: 必须有接口, 并且接口中有且只有一个抽象方法
            useInter(() -> System.out.println("好好学习, 天天向上"));
    
            // 使用lambda, 必须有上下文环境, 才能推导出lambda对应的接口
            /*
            new Thread((new Runnable() {
                @Override
                public void run() {
                    System.out.println("匿名内部类");
                }
            })).start();
    
            Runnable r = () -> System.out.println("lambda表达式");
            new Thread(r).start();
             */
    
            new Thread(() -> System.out.println("lambda表达式")).start();
        }
    
        private static void useInter(Inter i) {
            i.show();
        }
    }
    
    

    lambda表达式和匿名内部类区别

    所需类型不同:

    • 匿名内部类: 可以是接口, 也可以是抽象类, 还可以是具体类
    • lambda表达式: 只能是接口

    使用限制不同:

    • 如果接口中仅有一个抽象方法, 可以使用lambda表达式, 也可以使用匿名内部类
    • 如果接口中多余一个抽象方法, 只能使用匿名内部类, 而不能使用lambda表达式

    实现原理不同:

    • 匿名内部类: 编译之后, 会产生单独的.class字节码文件
    • lambda表达式: 编译之后, 没有一个单独的.class字节码文件. 字节码文件会在运行时动态生成

    Animal

    package myLambda.demo6;
    
    public abstract class Animal {
        public abstract void method();
    }
    

    Inter

    package myLambda.demo6;
    
    public interface Inter {
        void show();
        // void show2();
    }
    

    Student

    package myLambda.demo6;
    
    public class Student {
        public void study() {
            System.out.println("热爱生活!");
        }
    }
    

    Demo

    package myLambda.demo6;
    
    public class Demo {
        public static void main(String[] args) {
            // 匿名内部类
            useInter(new Inter() {
                @Override
                public void show() {
                    System.out.println("接口");
                }
            });
    
            useAnimal(new Animal() {
                @Override
                public void method() {
                    System.out.println("抽象类");
                }
            });
    
            useStudent(new Student(){
                @Override
                public void study() {
                    System.out.println("具体类");
                }
            });
    
            // lambda方式
            // useInter(() -> System.out.println("接口"));
    
            // useAnimal(() -> System.out.println("抽象类"));  // lambda必须是一个接口
            // useStudent(() -> System.out.println("具体类"));  // lambda必须是一个接口
    
            // 接口中有多个抽象方法
            /*
            useInter(new Inter() {
                @Override
                public void show() {
                    System.out.println("show");
                }
    
                @Override
                public void show2() {
                    System.out.println("show2");
                }
            });
             */
        }
    
        private static void useStudent(Student s) {
            s.study();
        }
    
        private static void useAnimal(Animal a) {
            a.method();
        }
    
        private static void useInter(Inter i) {
            i.show();
        }
    }
    
  • 相关阅读:
    Windows 2012 安装 SQL Server 2012,.Net Framework 3.5安装不成的解决办法
    HTML+CSS 对于英文单词强制换行但不截断单词的解决办法
    删除N天前的文件(夹)与拷贝文件到共享盘的批处理
    npm 常用命令
    使用scrapy crawl name启动一个爬虫时出现的问题
    anaconda和pycharm环境交叉的现象
    list和range()函数中使用反向索引的方法
    关于一些术语的解释
    关于assert和de-assert的解释
    搭建eclipse4.6(neon) + Pydev5.8.0 + python3.6(小版本3.6.1)
  • 原文地址:https://www.cnblogs.com/ryxiong-blog/p/13890477.html
Copyright © 2020-2023  润新知