zoukankan      html  css  js  c++  java
  • jdk8新特性之Lambda

    Lambda体验
    Lambda是一个匿名函数,可以理解为一段可以传递的代码。
    Lambda表达式写法,代码如下:
    借助Java 8的全新语法,上述 Runnable 接口的匿名内部类写法可以通过更简单的Lambda表达式达到相同的效果

     /**
         * 从匿名类到Lambda表达式的转变
         */
        @Test public void testLambdaHelloWorld() {
            // 匿名类01
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Hello");
                }
            }).start();
    
            // lambda01
            new Thread(() -> System.out.println("Hello")).start();
        }

     这段代码和刚才的执行效果是完全一样的,可以在JDK 8或更高的编译级别下通过。从代码的语义中可以看出:我们启动了一个线程,而线程任务的内容以一种更加简洁的形式被指定。我们只需要将要执行的代码放到一个Lambda表达式中,不需要定义类,不需要创建对象。
    Lambda的优点:简化匿名内部类的使用,语法更加简单。 

    Lambda的标准格式
    Lambda省去面向对象的条条框框,Lambda的标准格式格式由3个部分组成:

    (参数类型 参数名称) -> {
           代码体;
    }

    无参数无返回值的Lambda

        @Test
        public void test(){
            goSwimming(new Swimmable(){
                @Override
                public void swimming() {
                    System.out.println("我要游泳");
                }
            });
            goSwimming( () -> {
                System.out.println("我要游泳");
            });
    
        }
    
        // 练习无参数无返回值的Lambda
        public static void goSwimming(Swimmable s) {
            s.swimming();
        }
    /**
     * @author WGR
     * @create 2020/3/23 -- 23:29
     */
    public interface Swimmable {
        public abstract void swimming();
    }

    有参数有返回值的Lambda

        @Test
        public void test1(){
            goEatting( name ->{
                System.out.println("吃"+name);
                return 0 ;
            });
        }
    
        public static Integer goEatting(Eatable e){
            return e.eatting("饭");
        }
    /**
     * @author WGR
     * @create 2020/3/23 -- 23:29
     */
    public interface Swimmable {
        public abstract void swimming();
    }
       @Test
        public void test3(){
            ArrayList<Person> persons = new ArrayList<>();
            persons.add(new Person("刘德华", 58, 174));
            persons.add(new Person("张学友", 58, 176));
            persons.add(new Person("刘德华", 54, 171));
            persons.add(new Person("黎明", 53, 178));
    
            Collections.sort(persons, (o1, o2) -> {
                return o2.getAge() - o1.getAge(); // 降序
            });
    
            persons.forEach((t) -> {
                System.out.println(t);
           

    Lambda的实现原理
    匿名内部类的class文件

     

     Lambda表达式的断点

     关于这个方法 lambda$test$1 的命名:以lambda开头,因为是在test()函数里使用了lambda表达式,所以带有$test表示,因为是第二个,所以$01
    如何调用这个方法呢?其实Lambda在运行的时候会生成一个内部类,为了验证是否生成内部类,可以在运行时加
    -Djdk.internal.lambda.dumpProxyClasses ,加上这个参数后,运行时会将生成的内部类class码输出到一个文
    件中。使用java命令如下:

    java -Djdk.internal.lambda.dumpProxyClasses 要运行的包名.类名

    小结 :

    匿名内部类在编译的时候会一个class文件
    Lambda在程序运行的时候形成一个类
    1. 在类中新增一个方法,这个方法的方法体就是Lambda表达式中的代码
    2. 还会形成一个匿名内部类,实现接口,重写抽象方法
    3. 在接口的重写方法中会调用新生成的方法

    Lambda省略格式

     /**
         * lambda语法: 能省则省
         */
        @SuppressWarnings("unused")
        @Test public void testLambdaSyntax() {
            // 语法
            BinaryOperator<Integer> bo = (Integer x, Integer y) -> {
                return x+y;
            };
    
            // 简化1: 由于类型推断(编译器javac根据上下文环境推断出类型), 可以省略参数的类型
            bo = (x,y) -> {
                return x+y;
            };
    
            // 简化2: 当Lambda体只有一条语句的时候可以省略return和大括号{}
            bo = (x,y) -> x + y;
    
            // 简化3: 当参数只有一个时, 可以省略小括号
            Consumer<String> fun = args -> System.out.println(args);
    
            // 简化4: 当参数个数为零时, 使用()即可
            Runnable r1 = () -> System.out.println("Hello Lambda");
    
            // 简化5: 方法引用(下个新特性)
            Consumer<String> fun02 = System.out::println;
        }

    Lambda的前提条件
    Lambda的语法非常简洁,但是Lambda表达式不是随便使用的,使用时有几个条件要特别注意:
    1. 方法的参数或局部变量类型必须为接口才能使用Lambda
    2. 接口中有且仅有一个抽象方法

    /**
     * @author WGR
     * @create 2020/3/24 -- 0:11
     */
    public class LambdaCondition {
        public static void main(String[] args) {
            // 方法的参数或局部变量类型必须为接口才能使用Lambda
            test(() -> {
            });
    
            Flyable f = () -> {
                System.out.println("我会飞啦");
            };
        }
    
        public static void test(Flyable a) {
            new Person() {
    
            };
        }
    
    }
    
    // 只有一个抽象方法的接口称为函数式接口,我们就能使用Lambda
    @FunctionalInterface // 检测这个接口是不是只有一个抽象方法
    interface Flyable {
        // 接口中有且仅有一个抽象方法
        public abstract void eat();
        // public abstract void eat2();
    }
  • 相关阅读:
    win10下python环境变量设置
    c++ primer第15章这几个例子中的构造函数形式不太理解
    ++与*
    C++符号优先级
    56-Remove Linked List Elements
    55. Binary Tree Preorder Traversal
    54. Flatten Binary Tree to Linked List
    野指针--内存泄漏--缓存区溢出--栈溢出
    数组指针和指针数组的区别
    53-Linked List Cycle II
  • 原文地址:https://www.cnblogs.com/dalianpai/p/12556322.html
Copyright © 2011-2022 走看看