JDK8新特性之Lambda表达式的基本使用

  • 函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。
  • 2014年3月Oracle所发布的java8(jdk1.8)中加入了Lambda表达式,是一个十分重要的新特性。

以Runnable接口的实现为例

Lambda表达式

由三部分组成:一些参数、一个箭头和一段代码,格式如下:

说明:

  • 参数列表就是抽象方法中的参数列表,没有就空着
  • 箭头表示把参数传递给后面的方法体
  • 大括号里是重写抽象方法的方法体
  • Lambda的整体就和匿名内部类的整体一样,返回的是一个实现类或者子类对象,相当于:
    • 省去一个实现类,用匿名内部类来完成重写,整体返回一个实现类或者子类对象
    • 再省去了匿名内部类,就要用Lambda表达式来完成重写,整体也是返回一个实现类或者子类对象

有个疑惑:匿名内部类后面可以相当于实现类或者子类对象调用方法使用,但是Lambda表达式就不支持

我的理解:毕竟单独的一个Lambda根本就看不出到底是重写了哪个类的方法,所以Lambda表达式需要在特定环境中才能知道到底属于哪个对象,才能调用相应的方法。

Lambda表达式通常用来简化匿名内部类。带参带返回值的Lambda也一样:

比方说这里,只有特定的环境才知道这个Lambda表达式重写的是Comparator接口。

Lambda的省略格式

凡是根据上下文推导出来的内容,都可以省略书写(可推导即可省略)

可省略的内容有:

  • 参数列表的数据类型
  • 如果只有一个参数,括号也可省略
  • 代码中的大括号、分号以及return关键字(这三个要省略必须一起省略,要么就别省略)

省略格式的使用前提:【必须具有接口(无论是内置接口还是自定义接口),且接口中有且仅有一个抽象方法(要满足可推导性)】,也就是必须要唯一确定。

函数式接口

  • jdk8之后出现的新特性
  • 函数式接口在Java中是指:有且仅有一个抽象方法的接口。
  • 函数式接口中可以有其它方法包括默认、静态、私有等方法,但抽象方法只能有一个。
  • 在Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。

可以为接口提供一个注解:@FunctionalInterface,用来检测该接口是否是一个函数式接口。

如果是,编译成功;

如果编译失败,则说明这不是一个函数式接口。

这就不是一个函数式接口,所以报错,去掉一个抽象方法就可以啦。

函数式接口的使用

两种使用方式:

  • 作为方法的参数,只要参数是一个函数式接口,就可以传递Lambda表达式
public class MyFunctionalInterfaceTest {
    public static void main(String[] args) {

        //传递实现类对象
        show(new MyFunctionalInterfaceImpl());
        System.out.println("=============================");

        //直接使用匿名内部类
        show(new MyFunctionalInterface() {
            @Override
            public void method() {
                System.out.println("我是函数式接口的匿名内部类");
            }
        });
        System.out.println("=============================");
        //使用Lambda表达式简化匿名内部类
        show(() -> {
            System.out.println("我是函数式接口的Lambda表达式");
        });
        System.out.println("=============================");
        //使用Lambda表达式简化形式
        show(() -> System.out.println("我是函数式接口的Lambda表达式的简化格式"));

    }

    //函数式接口作为方法的参数
    public static void show(MyFunctionalInterface myinter){
        myinter.method();
    }
}
  • 作为方法的返回值类型。如果一个方法的返回值类型是一个函数式接口,那么可以直接返回一个Lambda表达式
public class LambdaPractice02 {
    public static void main(String[] args) {

        String[] str = {"aaa","bb","ccccccc","d"};
        System.out.println(Arrays.toString(str));

        //调用排序方法sort,传递返回的Lambda表达式
        Arrays.sort(str,getCompartor());
        System.out.println(Arrays.toString(str));
    }

    public static Comparator<String> getCompartor(){
       /* //返回一个匿名内部类
        return new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.length() - o1.length();
            }
        };*/

        /*//也可以直接返回一个Lambda表达式
        return (String o1, String o2) -> {
            return o2.length() - o1.length();
        };*/

        //也继续简化Lambda表达式
        return (o1, o2) ->o2.length() - o1.length()
    }
}

既然知道了Lambda表达式的使用需要函数式接口,那么问题就来了,在开发过程中哪来那么多的函数式接口来给我们用呢?有哪些接口是函数式接口呢?这个问题似乎让Lambda表达式看起来没有什么用武之地……

老实讲,虽然JDK8提供了多个函数式接口

比如:生产型Supplier<T>接口、消费型Consumer<T>接口等、判断型Predicate<T>接口、类型转换Function<T,R>接口等

但是,我在用他们的时候觉得很绕,与其用它们来处理数据,还不如直接定义一个方法来处理。比如利用Supplier接口求数组元素最大值:

我完全可以直接定义个方法来处理,而且代码可读性更好,上面使用Lambda式让代码读起来更杂乱。

晕……那Lambda表达式有啥用???????我觉得比较好的地方在于可以简化匿名内部类,有些地方确实是会使用匿名内部类,此时就可以用Lambda表达式来替换。还是感觉用处不是很大的样子………………

还有个方法引用可以了解下,自行百度……

发布了70 篇原创文章 · 获赞 1 · 访问量 2263

猜你喜欢

转载自blog.csdn.net/caozp913/article/details/103547982