zoukankan      html  css  js  c++  java
  • Java8 之 lambda 表达式、方法引用、函数式接口、默认方式、静态方法

    今天我来聊聊 Java8 的一些新的特性,确实 Java8 的新特性的出现,给开发者带来了非常大的便利,可能刚刚开始的时候会有点不习惯的这种写法,但是,当你真正的熟悉了之后,你一定会爱上这些新的特性的,这篇文章就来聊聊这些新特性。

    lambda 表达式

    lambda 表达式在项目中也是用到了,这种新的语法的加入,对于使用 Java 多年的我,我觉得是如虎添翼的感觉哈,这种新的语法,大大的改善了以前的 Java 的代码,变得更加的简洁,我觉得这也是为什么 Java8 能够很快的流行起来的原因吧。

    这里我们用几个以前的经典的 Java 的写法和用 lambda 表达式的方式进行对比。

    线程的用法

    原始的线程用法

    //使用匿名内部类的方式启动多线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("这是使用匿名内部类的方式。。。");
                }
            }).start();
    

    lambda 表达式

    //使用lambda表达式方式
            new Thread(() -> {
                System.out.println("这是使用lambda表达式的方式。。。");
            }).start();
    

    你会发现,用 lambda 表达式的方式能够写更少的代码,看起来也会更加的舒服和简洁。

    这里没有使用参数,只是一个简单的例子。

    我们再看一个例子。

    遍历方式

    原始方式

    //原始方式
            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
            for (int i : list) {
                System.out.println(i);
            }
    

    lambda 表达式方式

    //使用lambda表达式代替foreach循环
            Stream.of(1, 2, 3, 4, 5).forEach((x) -> {
                System.out.println(x);
            });
    

    在原始的方式中,我们一般使用 foreach 的方式进行遍历,有了 Java8 的方式之后,我们可以用 forEach 方法,然后,再用 lambda 表达式的方式进行遍历,也让原来的方式变得更加的简洁。

    在这个例子中,我们加了一个参数,在()中间我们加了一个 x ,代表的意思其实是:通过 forEach 方法,我们把一个元素已经赋值到 x 中了,拿到这个 x ,我们就可以输出结果。

    总结

    lambda 的使用方式其实很简单,可以总结为下面的方法。

    ([参数可选,...]) -> {
    }
    

    方法引用

    方法引用其实是 lambda 表达式的部分的简化,也就是为了简化 lambda 表达式而存在的感觉,下面我们还讲讲怎么使用方法引用

    /**
         * @return void
         * @Author ouyangsihai
         * @Description 方法引用测试
         * @Date 10:23 2019/5/14
         * @Param []
         **/
        @Test
        public void test_method_reference() {
            //使用lambda表达式
            Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
                    .map(s -> s.length()) //lambda
                    .forEach((x) -> {
                        System.out.println(x);
                    });
    
            //使用静态方法引用
            Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
                    .map(String::length) //静态方法引用
                    .forEach((x) -> {
                        System.out.println(x);
                    });
    
            //使用实例方法引用
            Stream.of(
                    new ClassMate("1", "欧阳思海"),
                    new ClassMate("2", "sihai")
            ).map(ClassMate::getName)//实例方法引用
                    .forEach(x -> {
                        System.out.println(x);
                    });
    
        }
    

    在第一个测试中,我们用的是 lambda 表达式来获取每个字符串的长度

    s -> s.length()
    

    在第二个测试中,我们使用的是静态方法引用来获取每个字符串的长度

    String::length
    

    在第三个测试中,我们使用的是实例方法引用。

    ClassMate::getName
    

    解释
    ① map 方法是映射的意思。
    ② forEach 方式是遍历每一个元素。
    ③ ClassMate 是一个包含 id 和 name 的简单 po 类。

    通过上面这个例子,基本上我们就知道怎么使用方法引用了。下面我们进行一个小的总结。

    总结
    ① 使用方法

    类名::方法名
    

    ② 方法可以是:静态方法,实例方法

    构造函数引用

    在上面我们讲了方法引用的基本使用方法,其实除了方法引用以外,还有构造函数引用,回想一下,以前我们创建对象是怎么做?是不是需要 new 一个对象呢,那么现在用构造函数引用又是怎么做的呢?

    下面我们用一个例子讲解一下,在这个例子中,对象还是使用上面的 ClassMate

    /**
         * @return void
         * @Author ouyangsihai
         * @Description 构造函数引用测试
         * @Date 10:23 2019/5/14
         * @Param []
         **/
        @Test
        public void test_method_reference2() {
            //使用lambda表达式
            Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
                    .map(s -> new ClassMate(s)) //lambda
                    .collect(Collectors.toList());
    
            //使用构造函数引用
            Stream.of("A", "BB", "CCC", "DDDD", "FFFFF")
                    .map(ClassMate::new) //构造函数引用,由上下文决定用哪一个构造函数
                    .collect(Collectors.toList());
        }
    

    ① 第一个我们使用的是 lambda 表达式进行创建对象的 s -> new ClassMate(s)
    ② 第二个我们使用的是构造函数引用创建对象的 ClassMate::new
    ③ 我们发现构造函数引用:类名::new ,然后对于使用哪一个构造函数是由上下文决定的,比如有一个参数和两个参数和无参数的构造函数,会自动确定用哪一个。

    接口

    在 Java 8 之前的接口是不能有实现的,只能定义抽象方法,然而,在 Java 8 以后,增加了一个新的功能,可以添加实现,可以定义默认方法,可以定义静态方法

    函数式接口

    什么是函数式接口呢?

    这个名词在 Java 中以前是很少听到的,但是正是有了 Java 8 的横空出世,函数式编程也变得熟悉了。

    在一个接口中我们以 @FunctionalInterface 注解声明一个接口,并且接口中只有一个抽象方法,那么我们就叫做这是一个函数式接口

    /**
     * @ClassName FunctionalInterfaceTest
     * @Description
     * @Author 欧阳思海
     * @Date 2019/5/14 10:39
     * @Version 1.0
     **/
    @FunctionalInterface
    public interface FunctionalInterfaceTest {
        //继承接口后,又加了新的抽象方法,这个接口就不再是函数式接口
        void test(String s);
    }
    

    ① 上面的接口中只有一个抽象方法,所以这是一个函数式接口。
    ② 如果上面接口中再加一个抽象方法,那么就不是函数式接口了。

    下面,我们再通过继承来继承这个接口。

    /**
     * @ClassName FunctionalTest
     * @Description
     * @Author 欧阳思海
     * @Date 2019/5/17 17:26
     * @Version 1.0
     **/
    public interface FunctionalTest extends FunctionalInterfaceTest{
    
        int test2();
    }
    

    ① 我们继承了上面的接口,并且加了一个 test2 方法。
    ② 这里注意,如果一个接口集成现有的函数式接口后,又加了其他的抽象方法,这个接口就不是函数式接口了。

    默认方法

    默认方法很简单,用 default 声明即可。

    /**
     * @ClassName FunctionalInterfaceTest
     * @Description
     * @Author 欧阳思海
     * @Date 2019/5/14 10:39
     * @Version 1.0
     **/
    @FunctionalInterface
    public interface FunctionalInterfaceTest {
        //继承接口后,又加了新的抽象方法,这个接口就不再是函数式接口
        void test(String s);
    
        //默认方法
        default String getStr(){
            return null;
        }
    }
    
    

    ① 在接口中添加了一个默认方法。并且实现了方法。

    静态方法

    默认方法很简单,用 static 声明即可。

    /**
     * @ClassName FunctionalInterfaceTest
     * @Description
     * @Author 欧阳思海
     * @Date 2019/5/14 10:39
     * @Version 1.0
     **/
    @FunctionalInterface
    public interface FunctionalInterfaceTest {
        //继承接口后,又加了新的抽象方法,这个接口就不再是函数式接口
        void test(String s);
    
        //静态方法
        static String getStr2(){
            return null;
        }
    
        //错误用法
        default static String getStr3(){
            return null;
        }
    }
    
    

    ① 实现的静态方法,用 static 声明。
    ② 注意不能同时使用 default 和 static 声明。

    总结

    在这篇文章中,我们讲了 lambda 表达式、方法引用、函数式接口、接口中的静态方法、接口中的默认方法的使用。

  • 相关阅读:
    P3916 图的遍历 dfs
    P4568 [JLOI2011]飞行路线 分层图最短路
    P1948 [USACO08JAN]电话线Telephone Lines spfa 二分答案
    P1849 [USACO12MAR]拖拉机Tractor bfs
    P1730 最小密度路径 floyed
    P1661 扩散 二分答案 并查集
    使用unittest和Django搭配写一个接口测试平台
    AJAX解决跨域的几种方式
    Django
    基于pytest框架自动化测试脚本的编写
  • 原文地址:https://www.cnblogs.com/SIHAIloveYAN/p/10988533.html
Copyright © 2011-2022 走看看