Java8 --- 函数式接口@FunctionalInterface及default关键字

1. 关于Comparator和Comparable

既然提到了Comparator,那就大致来说一下Comparator和Comparable接口的区别。

Comparator是一种策略模式,即被比较的对象自身不需要做任何改变(实现任何排序接口),而是通过实例化一个Comparator策略来实现对象之间的排序。

Comparable支持对象自身进行改变(对象自身实现Comparable接口),从而具有排序功能。

举个例子来说,一组对象需要用Collection的sort方法进行排序,有两种方法,要么是对象实现Comparable接口,自身具有可排序属性;要么是实现一个Comparator比较器,在调用sort方法时传入。

下面再来说一说Lambda表达式。

2. Lambda表达式

我们都知道,Lambda表达式是Java里面的函数式编程,那么在使用Lambda表达式首先要满足这样一个条件:首先他的类型是interface,而且有且仅有一个抽象方法。那么下面我们先来看一个使用Lambda表达式的例子。

先看一下Java7中的表达:

public class LambdaTest {

    public static void main(String[] args) {

        Say test1 = new Say() {

            @Override

            public void saySomthing(String something) {

                System.out.println(something);

            }

        };

        test2.saySomthing("hello");

}

interface Say {

    void saySomthing(String something);

}

使用Lambda表达式后的Java8中的表达:

public class LambdaTest {

    public static void main(String[] args) {

        Say test2 = System.out::println;

        test2.saySomthing("hello");

    }

}

interface Say {

    void saySomthing(String something);

}

那么类似的,我们要实现一个Comparator比较器会这样写:

public class LambdaTest {

    public static void main(String[] args) {

       Comparator<Book> bookComparator = Comparator.comparing(Book::getPrice);

       

       Book book1 = new Book("a", 1);

       Book book2 = new Book("b", 1);

       System.out.println(bookComparator.compare(book1, book2));

    }

}

class Book {

    private String name;

    private Integer price;

    

    // 省略constructor/getter/setter

}

这样写完全OK,可是我们去看一下Comparator接口的源码,可能会觉得略微有点诧异。

可以注意到Comparator接口的源码有这样几个点:

@FunctionalInterface注解的作用

Comparator接口里有多个方法(两个抽象方法和多个default方法)

default关键字的含义

下面逐一来解释一下上面这三个点。

(1) @FunctionalInterface注解的作用

@FunctionalInterface标注在一个接口上,说明这个接口是一个函数式接口。

​那么关于函数式接口,有如下特点:

​有且只有一个抽象方法

可以有多个静态方法

可以有多个default方法(默认方法)

可以有多个Object的public的抽象方法

(2) Comparator接口里有多个方法(两个抽象方法和多个default方法)

可以看到​Comparator接口里除了有compare这个抽象方法,还有一个equals抽象方法,但是如上所说,函数式接口里允许有Object的public的抽象方法。

(3) ​default关键字的含义

default关键字修饰的接口方法可以有默认的方法体。当接口的实现类实现接口的时候,可以不去实现default关键字修饰的方法。

这样做是为了解决这样一种场景:

假设有一个接口定义如下:

interface TestInterFace {

    void doSomething();

}

在一个应用中有该接口的大量实现类,可是突然这个接口里面需要新加一个方法doAnother()。此时,我们要在应用所有实现了这个接口的类中加上doAnother()的实现,这样会导致两个问题:一是修改的幅度对比较大;二是不是所有的实现类都需要去实现doAnother()方法。

default关键字就是为了解决这样的问题。在doAnother()方法前加上default关键字,之前的接口实现类不去实现doAnother()方法也不会报错。如果新的实现类实现这个方法,就等于该实现类覆盖了这个方法,这样最终的运行结果也是符合Java的多态性的。

但是需要注意的是,default关键字也不建议随便使用。

假设有两个接口:InterfaceA和InterfaceB​,他们都有一个default void test()方法,现在又Class C同时实现InterfaceA和InterfaceB,在调用test()方法时就会出错,因为这样会引起二义性,编译器无法知道C调用的究竟是那一个test()方法。

————————————————

版权声明:本文为CSDN博主「dela_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/dela_/article/details/8379477

猜你喜欢

转载自www.cnblogs.com/lc0605/p/11771278.html
今日推荐