可比接口是功能性接口吗?

时间:2019-06-30 20:05:51

标签: java

当我看Comparable时,我正在使用反编译器工具,它只有一种抽象方法,没有FunctionalInterface批注

public interface Comparable<T> {
    int compareTo(T var1);
}

与Comparator相似,但是比较器具有FunctionalInterface批注

    @FunctionalInterface
    public interface Comparator<T> {
    int compare(T var1, T var2);
    ... 
}

5 个答案:

答案 0 :(得分:4)

FunctionalInterface吗?否。Comparable没有该注释。

功能界面吗?是。根据{{​​3}}中的定义:

  

功能接口是仅具有一种抽象方法的接口(除对象的方法之外)

将其视为FunctionalInterface吗? language spec

  

但是,无论接口声明中是否存在FunctionalInterface注释,编译器都会将满足功能接口定义的任何接口视为功能接口。

在逻辑上是功能上的接口吗?否:Comparable不代表函数。它更像是对象的特征。 “可以比较这件事”,而不是“可以比较这件事”。

作为功能接口有实际用途吗?我会声称没有明显的用处,因为事实是,您很少(如果有的话)看到Comparable<Something>被用作变量,参数或字段的类型;仅在extendsimplements子句中以及类型变量的范围内。

答案 1 :(得分:2)

我在Java Book Chapter 3 [144 page]

中找到了答案

enter image description here

Is Comparable a Functional Interface?
     

我们说比较器是一个功能接口,因为它具有一个   单一抽象方法。可比也是功能接口   因为它也只有一个抽象方法。但是,使用lambda   对于可比来说将是愚蠢的。可比的重点是实现   将其放入要比较的对象中。

答案 2 :(得分:1)

可比对象是可以与其他对象进行比较的对象; compareTo()应该比较this的值。

将其实现为lambda毫无意义。

答案 3 :(得分:1)

从字面上看,private static final int NUM_ROW = 2; private static final int NUM_COL = 3; private TableLayout table; @Override protected void onCreate(Bundle savedInstanceState) { ... table = findViewById(R.id.tableForButtons); table.post(new Runnable() { @Override public void run() { populateTable(); } }); } private void populateTable() { int tableLayoutWidth = table.getMeasuredWidth(); int cellWidth = tableLayoutWidth / NUM_COL; for (int row = 0; row < NUM_ROW; row++) { TableRow tableRow = new TableRow(this); tableRow.setLayoutParams(new TableLayout.LayoutParams( TableLayout.LayoutParams.MATCH_PARENT, cellWidth )); for (int col = 0; col < NUM_COL; col++) { ImageButton button = new ImageButton(this); button.setLayoutParams(new TableRow.LayoutParams( cellWidth, cellWidth )); button.setBackgroundResource(R.mipmap.single_case); button.setPadding(0, 0, 0, 0); button.setScaleType(ImageView.ScaleType.FIT_XY); tableRow.addView(button); } table.addView(tableRow); } } 是一个功能接口,因为它声明了一个并且只有一个抽象方法。
但是用Comparable对其进行注释将意味着它已被证明可以用作功能接口,而事实并非如此。
JLS指出:

  

9.6.4.9。 @FunctionalInterface

     

由于某些接口偶然起作用,所以不是   功能接口的所有声明都是必需或可取的   用@FunctionalInterface注释。

当然,您可以通过依赖外部@FunctionalInterface实例而不是像我们在Foo实现中通常使用的this那样在lambda中使用它:

compareTo()

但这是不希望的,因为滥用了Foo one = new Foo(...); Comparable<Foo> comparableForOne = other -> one.getX().compareTo(other.getX())); Foo anotherFoo = new Foo(...); int result = comparableForOne.compareTo(anotherFoo); 接口,该接口被设计用于类的任何实例而不是特定实例。

答案 4 :(得分:0)

要完全回答这个问题,我们应该看一下Java的内幕,看看什么是lambda(至少到目前为止):用一种方法实现接口的语法糖。让我们以Comparator<T>(可以很好地由lambda实现)的示例进行说明,然后转到Comparable<T>(可以由lambda实现,但没有意义)。 / p>

假设有人给了我们(编译的)

public class Car {
    private final int horsePowers;
    private final int topSpeed;
    private final int numDoors;
    private final String color;
    // Setters omitted for brevity
}

我们无法修改此类,但是我们想按颜色对汽车进行分类。传统方法是调用Collections.sort(List<T> list, Comparator<? super T> c)。由于我们作为开发人员经常很懒惰(否则,我们将不使用Copy-Paste-Programming),因此我们经常在anonymous class中实现这种功能:

...
List<Car> cars = ...;
Collections.sort(cars, new Comparator<Car> {
    @Override
    public int compare(final Car lhs, final Car rhs) {
        return lhs.getColor.compareTo(rhs.getColor());
    }
});

这很丑。首先,它漫长而又漫长,阅读起来很尴尬。但是幸运的是,Java之神用lambda expressions祝福了我们,所以我们写了 1

...
List<Car> cars = ...;
Collections.sort(cars, (lhs, rhs) -> lhs.getColor().compareTo(rhs.getColor()));

这看起来更好,不是吗?它简短,全面且易于阅读(至少,如果您已经看过一百遍了)。但实际上,它仍然是一个古老的匿名类。没有其他的。某些限制确实适用于lambda。首先,lambda没有任何状态(实例变量)。其次,从lambda外部使用的所有引用(局部变量或周围方法/类的属性)必须为final或有效地为final(不允许lambda更改值)。这将在下面变得更加重要。

现在,我们来看看Comparable<T>Comparator<T>定义了如何将两个T相互比较的同时,Comparable<T>说“此类与T(通常是本身)具有可比性,这是如何将其与T进行比较”。让我们想象一下,我们上面的Car类实际上是这样实现Comparable<Car>的:

public class Car implements Comparable<Car> {
    ...
    public int CompareTo(final Car that) {
        int diff = this.getHorsePowers() - that.getHorsePowers();
        if (diff == 0) {
            diff = this.getTopSpeed() - that.getTopSpeed();
        }
        if (diff == 0) {
            diff = this.getNumDoors() - that.getNumDoors();
        }
        if (diff == 0) {
            diff = this.getColor().compareTo(that.getColor()); 
        }
        return diff;
    }
}

实质上,它首先将Car与它们的horsePowers比较。如果它们相等,则通过它们的topSpeed比较它们。如果它们再次相等,则将其与门数进行比较,依此类推。

现在让我们来回顾一下:Lambda是仅使用一种方法即可实现接口的语法糖,Comparable<T>描述了如何将类与T进行比较。现在回想一下我之前对Lambda和州所说的话:Lambda没有任何州。因此,在大多数情况下将它们与任何事物进行比较都是毫无意义的(没有状态-没有可比较的事物;我说“大部分时间”,因为在某些情况下这种事情可能是可行的)。因此,几乎没有理由用lambda实现Comparable<T>

总而言之,我们可以说,虽然可以用lambda实现Comparable<T>,但这很少有用。


1 我知道比较lambda通常写为Comparator.comparing(Car::getColor),但这不是我要强调的重点。