Java8新特性之Lambda表达式学习一

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/super_YC/article/details/81259981

       刚毕业入职新工作,在职岗位培训时,老师在操作集合老使用Lambda表达式。这使一个之前完全没有接触过Lambda表达式的少年甚是苦恼,看不懂,闲余时间决定搞一搞Lambda表达式到底是啥东西?底层原理怎么实现的,接下来我将我的学习成果一起分享给大家......

一、Lambda表达式的简介:

       Lambda表达式首先不是一种新的知识点,而是Java8推出来的一种新的语法。这种新的语法背后仍然是接口、方法、参数、返回值、匿名内部类等。并且这种语法方便程序员编写,但是JVM在编译时,会自动还原以前我们自己写的代码。

例1:对其学生分数进行升序排序: 

public class Test {
    class User{
        private String name;
        private Integer score;

        public User(String name, Integer score) {
            this.name = name;
            this.score = score;
        }

        @Override
        public String toString() {
            return this.name + this.score;
        }
    }

    /**
     * 传统的写法
     */
    public void testOldUse(){
        User[] users = new User[]{new User("张三",80),new User("李四",81),new User("王五",82)};
        //对User数组按照score排序
        Arrays.sort(users, new Comparator<User>() {
            public int compare(User o1, User o2) {
                //有可能两个数相减,超出int范围,所以我们借用Integer中的compare()方法
                //return o1.score - o2.score;
                return Integer.compare(o1.score, o2.score);
            }
        });
        System.out.println(Arrays.toString(users));
    }

    /**
     * 使用lambda表达式
     */
    @Test
    public void testNewUse(){
        User[] users = new User[]{new User("张三",83),new User("李四",84),new User("王五",85)};
        //对User数组按照score排序new Comparator<User>() {
        //Lambda表达式 (切记三个一定)
        /*  第一:Arrays.sort()这个方法的第二参数一定是实现了Comparator接口;
         *  第二:实现Comparator接口,一定要重写compare()方法;
         *  第三:方法compare()执行完毕,一定会返回一个int类型的值;
         *  这些JVM在编译的时候,会自动的帮助我们添加这些所缺的内容;
         */
        Arrays.sort(users, (User o1, User o2) -> {
                return Integer.compare(o1.score,o2.score);
            }
        );
        System.out.println(Arrays.toString(users));
    }

    /**
     * 再次简化lambda表达式
     */
    @Test
    public void testNewUse2(){
        User[] users = new User[]{new User("张三",86),new User("李四",87),new User("王五",88)};

        /* Lambda表达式
         * 第一:Integer.compare()这个方法会返回一个int值;
         * 第二:Comparetor这个接口的compare()方法也会返回一个int值;
         * 第三:JVM会自动推导出Integer.compare()这个方法返回的int值即为compare()所要返回的值,所以return可以省略;
         */
        Arrays.sort(users, (User o1, User o2) -> Integer.compare(o1.score,o2.score));
        System.out.println(Arrays.toString(users));
    }

    /**
     * 最终简化lambda表达式
     */
    @Test
    public void testNewUse3(){
        User[] users = new User[]{new User("张三",89),new User("李四",90),new User("王五",91)};

        /* Lambda表达式
         * 第一:如果代码块中只有一行代码,
         * 第二:Integer.compare()这个方法会返回一个int值;
         * 第三:compare()这个方法也会返回一个int值,JVM会自动推导出Integer.compare()这个方法返回的值为compare()的值,所以return可以省略;
         * 第四:compare()这个方法的参数类型一定是User类型,所以JVM会推导出要比较两个参数的类型,可以省略User
         */
        Arrays.sort(users, (o1,o2) -> Integer.compare(o1.score,o2.score));
        System.out.println(Arrays.toString(users));
    }
}

实践:大家可以自行实现lambda表达式代替匿名内部类,创建Runnable接口实例,并重写run()方法,然后启动线程!

二、Lambda表达式之变量:(Lambda表达式俗称闭包)

(1) 接口的方法参数:Lambda表达式中()圆括号中的参数变量;

(2) 局部变量:Lambda表达式代码块中声明的变量;

(3) 自由变量:不是参数,也不是局部变量,是外部方法的参数变量;

例2:匿名内部类使用外部变量,该变量一定是final修改的,不可改变

    //content、times即为自由变量
    public void repeatprint(String content,int times) {
        // 第一:匿名内部类若使用外部的变量,该变量一定是使用final修饰;
        Runnable runnable = () -> {   //若run()方法中有参数,即为接口的方法参数
            int i = 0;        //声明一个局部变量
            for (; i <= times; i++) {
                //content = "not update";    //该变量自动被final修饰,不能修改
                System.out.println(content);
            }
            //this指向的是外部类的实例,而不是内部类本身
            System.out.println(this);
        };
        new Thread(run).start();
    }

注意1:匿名内部类中的this指代匿名内部类本身,而Lambda表达式中的this指代的外部类实例,即为创建Lambda表表达式方法中的this(就是外部类本身);

注意2:Lambda表达式中访问自由变量(创建Lambda表达式方法的参数),final修饰,不可修改! 

三、Lambda表达式之参数列表

(1) 如果Lambda表达式没有参数,直接使用()来表示,()不能省略;

例3:启动线程

//Lambda表达式没有参数时,()不能省略,否则编译出错
public void testTread(){
        new Thread(() -> System.out.println("Hello lambda")).start();
}

(2) 如果Lambda表达式只有一个参数,若没写了参数类型,参数外可不加();若写了参数类型,则参数外必须加();

例4:借用Frame中的Button组件添加事件处理:

        Frame f = new Frame();
        f.setSize(100,100);
        Button btn = new Button("lambda");
        //原始方式,匿名内部类创建
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Hello lambda");
            }
        });
        /* lambda表达式只有一个参数
         * 第一:addActionListener()这个方法的参数一定是ActionListener接口的实现类实例;
         * 第二:实现ActionListener接口一定要重写actionPerformed()方法;
         * 第三:重写actionPerformed()方法,参数一定是ActionEvent类型;
         * JVM会自动的帮助我们推导出来
         */
        /* 第一种方式:btn.addActionListener((ActionEvent e) ->                     System.out.println("Hello lambda"));
         * 第二种方式:btn.addActionListener(event -> System.out.pringln("Hello lambda"));
         */
        f.add(btn);
        f.setVisible(true);

(3) 如果有两个参数或多个参数,不管是否写参数类型,一定要加();若参数要加修饰符,一定要添加完整的类型。

例5:将其字符串数组中升序排序

    /**
     * Lambda表达式有两个参数
     */
    public void testLambda(){
        String[] strs = new String[]{"Android","IOS","Java","OS"};
        Arrays.sort(strs,(s1,s2) -> Integer.compare(s1.length(), s2.length()));
        /* 如果参数要加修饰符或者标签(例如:final、static关键字),参数一定要加完整的类型;
         * Arrays.sort(strs,(final String s1,final String s2) -> Integer.compare(s1.length(), s2.length()));
         */
        System.out.println(Arrays.toString(strs));
    }

虽然例子简单,但想理解Lambda表达式如何从匿名内部类转变而来的原理,底层实现等,需要大家揣摩和思考。继续欢迎大家参考:Java8新特性之Lambda表达式学习二

猜你喜欢

转载自blog.csdn.net/super_YC/article/details/81259981