BinaryCompatibleDefaultMethods
From APIDesign
Line 13: | Line 13: | ||
private final char[] chars; | private final char[] chars; | ||
- | CharArrayLike(char | + | CharArrayLike(char... chars) { |
this.chars = chars; | this.chars = chars; | ||
} | } | ||
Line 31: | Line 31: | ||
return new String(chars, start, end); | return new String(chars, start, end); | ||
} | } | ||
- | + | ||
- | + | public static void main(String... args) { | |
+ | boolean empty = new CharArrayLike('E', 'r', 'r', 'o', 'r', '!').isEmpty(); | ||
+ | System.err.println("not empty: " + empty); | ||
+ | } | ||
} | } | ||
</source> | </source> |
Revision as of 06:20, 28 September 2020
DefaultMethods are useful when one desperately needs to add a method into an existing interface. However, they decrease clarity of a ProviderAPI (no, you can't disagree!). As such, don't overuse. Morever it has been recently demonstrated that adding DefaultMethods can even compromise BinaryCompatibility. Recently Emilian Bold asked me to participate in a tweeting about binary incompatibility caused by adding CharSequence.isEmpty in JDK15. An interesting case. Following code compiles on JDK8 to JDK14:
interface ArrayLike { int length(); default boolean isEmpty() { return length() == 0; } } final class CharArrayLike implements CharSequence, ArrayLike { private final char[] chars; CharArrayLike(char... chars) { this.chars = chars; } @Override public int length() { return chars.length; } @Override public char charAt(int index) { return chars[index]; } @Override public CharSequence subSequence(int start, int end) { return new String(chars, start, end); } public static void main(String... args) { boolean empty = new CharArrayLike('E', 'r', 'r', 'o', 'r', '!').isEmpty(); System.err.println("not empty: " + empty); } }
While the code compiles find with JDK14 and older, it no longer compiles on JDK15. It results in:
$ /jdk-14/bin/javac ArrayLike.java $ /jdk-15/bin/javac ArrayLike.java ArrayLike.java:9: error: types CharSequence and ArrayLike are incompatible; final class CharArrayLike implements CharSequence, ArrayLike { ^ class CharArrayLike inherits unrelated defaults for isEmpty() from types CharSequence and ArrayLike 1 error
Why? Since JDK15 there is CharSequence.isEmpty() default method. As such, when javac processes the CharArrayLike class it doesn't know whether to select the ArrayLike.isEmpty() or the newly added method.