Java 8中使用"default"修饰符的最佳场景是什么?

3
在新的Java 8规范语言中,它们引入了“default”修饰符,允许在接口中定义一个方法。
我的问题是,有没有人有这个特性的最佳使用案例的好主意?

这是一个非常广泛的问题,没有具体的答案,所以我不会提供除评论之外的任何答案。但是一个很好的例子是当您想要向接口添加一个方法,但不希望破坏已经使用该接口的任何构建时。 - NESPowerGlove
默认接口方法的实现,允许添加功能而不会破坏先前的接口实现。 - Dave Newton
我认为这个的唯一真正用途是在你想要向一个接口添加新方法时,而不会破坏实现该接口的任何类中的代码。想象一下一些需要添加更多行为但不能破坏旧代码的Java核心接口。 - luizcarlosfx
我在LinkedIn上提出了一个问题,询问除了为现有接口添加功能之外是否还有其他用例。我得到了一个回复在这里。那只是一个回答者的意见,我不会背书。 - ajb
2个回答

6

避免破坏代码 - 支持API演进

一个典型的例子是在Java 8中引入了Iterable接口中的default stream()方法。这样,所有的Iterable都会自动继承一个已经实现的stream方法。这为API演进提供了支持,而不会破坏已经存在的代码。

定义合理的默认行为

假设你创建了一个新的集合框架,定义一个合理的默认行为可能是很有必要的:

interface MyCollection {
    int size();
    default boolean isEmpty() { return size() == 0; }
}

通过这样做,您可以避免在所有实现类中重新定义isEmpty所带来的痛苦,同时允许特定类在需要时以不同方式实现它。
虽然这可以在抽象类中完成,但这使您可以消除继承层次结构中的一层,并且您可以获得接口的继承灵活性:一个类可以继承多个接口,但只能继承一个抽象类。
另请参见:Java 8 中带有默认方法的接口 vs 抽象类

这里是一个不错的情景,但是虽然我们可以覆盖默认方法,为什么不使用抽象类呢? - Naili
1
@Naili 你可以使用抽象类代替:这是过去所做的!默认方法的替代方案可能会消除一个继承层次结构并帮助您摆脱抽象类层次结构 - 根据具体情况确定。 - assylias
1
@Naili 你只能从一个抽象类继承,但是你可以实现尽可能多的接口。如果两个接口都有不同的默认实现,那么就不能再使用抽象类了。 - skiwi
现在很清楚了,因为仅仅说它只是创建方法的默认实现是不够的。 - Naili

1

升级Elementary API

我认为引入此功能的主要原因是允许升级非常基本的接口-CollectionIterableComparable等,而不会对已存在的代码造成不兼容性,正如assylias在第一段中提到的。

方法链

此外,您可以通过方法链获得非常有趣的结果-这些方法返回相同的类型,并且您可以将它们链接起来调用:

// Multiples of 5
final Predicate<Integer> fives = n -> n%5==0;
// Multiples of 7
final Predicate<Integer> sevens = n -> n%7==0;
// Multiples of 3
final Predicate<Integer> threes = n -> n%3==0;

// Multiples of 5 and 7 but not 3
final Predicate<Integer> compoundPredicate = fives.and(sevens).and(threes.negate());

这是由于广泛使用默认方法而实现的:
@FunctionalInterface 
public interface Predicate<T> {
    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        return (t) -> test(t) && other.test(t);
    }
    default Predicate<T> or(Predicate<? super T> other) {
        return (t) -> test(t) || other.test(t);
    }
    default Predicate<T> negate() {
        return (t) -> !test(t);
    } 
}

摆脱人为的抽象类,为真正的继承留出空间

对于默认行为而言,这不仅会删除完全人为的抽象类层级(该层级仅为默认行为创建),还为您提供了引入真正有用的抽象类的机会,这些抽象类可以模拟实际的是一个关系。

请看以下受游戏实现启发的示例。对于大多数怪物而言,isDead()只是一种便利方法。但是,僵尸永远不会死,是吗? :)

enter image description here

enter image description here

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接