programing

Java 8 기본 메소드가 소스 호환성을 중단합니까?

javaba 2021. 1. 15. 19:10
반응형

Java 8 기본 메소드가 소스 호환성을 중단합니까?


일반적으로 Java 소스 코드가 순방향 호환이 가능한 경우입니다. 내가 아는 한 Java 8까지는 컴파일 된 클래스 소스가 모두 최신 JDK / JVM 릴리스와 호환되었습니다. [업데이트 : 정확하지 않습니다. 아래의 'enum'주석 등을 참조하십시오.] 그러나 Java 8에 기본 메소드가 추가됨에 따라 더 이상 그렇지 않은 것으로 보입니다.

예를 들어, 내가 사용하고있는 라이브러리 java.util.List에는 List<V> sort(). 이 메서드는 정렬 된 목록 내용의 복사본을 반환합니다. jar 파일 종속성으로 배포 된이 라이브러리는 JDK 1.8을 사용하여 빌드중인 프로젝트에서 잘 작동했습니다.

그러나 나중에 JDK 1.8을 사용하여 라이브러리 자체를 다시 컴파일 할 기회가 있었고 라이브러리가 더 이상 컴파일되지 않음을 발견 List했습니다. 자체 sort()메서드가 있는 -implementing 클래스가 이제 Java 8 java.util.List.sort()기본 메서드 와 충돌합니다 . Java 8 sort()기본 메소드는 목록을 제자리에 정렬합니다 (을 반환합니다 void). 내 라이브러리의 sort()메서드는 새 정렬 된 목록을 반환하므로 호환되지 않는 서명이 있습니다.

그래서 내 기본적인 질문은 다음과 같습니다.

  • JDK 1.8은 기본 메소드로 인해 Java 소스 코드에 대한 순방향 비 호환성을 도입하지 않습니까?

또한:

  • 이것이 첫 번째 순방향 비 호환 변경입니까?
  • 이것이 기본 방법이 설계되고 구현 될 때 고려되거나 논의 되었습니까? 어디에나 문서화되어 있습니까?
  • (분명히 작은) 불편 함이 혜택에 비해 할인 되었습니까?

다음은 1.7에서 컴파일 및 실행되고 1.8에서 실행되지만 1.8에서는 컴파일되지 않는 일부 코드의 예입니다.

import java.util.*;

public final class Sort8 {

    public static void main(String[] args) {
        SortableList<String> l = new SortableList<String>(Arrays.asList(args));
        System.out.println("unsorted: "+l);
        SortableList<String> s = l.sort(Collections.reverseOrder());
        System.out.println("sorted  : "+s);
    }

    public static class SortableList<V> extends ArrayList<V> {

        public SortableList() { super(); }
        public SortableList(Collection<? extends V> col) { super(col); }

        public SortableList<V> sort(Comparator<? super V> cmp) {
            SortableList<V> l = new SortableList<V>();
            l.addAll(this);
            Collections.sort(l, cmp);
            return l;
        }

    }

}

다음은이 코드가 컴파일 (또는 실패)되고 실행되는 것을 보여줍니다.

> c:\tools\jdk1.7.0_10\bin\javac Sort8.java

> c:\tools\jdk1.7.0_10\bin\java Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> c:\tools\jdk1.8.0_05\bin\java Sort8 this is a test
unsorted: [this, is, a, test]
sorted  : [this, test, is, a]

> del Sort8*.class

> c:\tools\jdk1.8.0_05\bin\javac Sort8.java
Sort8.java:46: error: sort(Comparator<? super V>) in SortableList cannot implement sort(Comparator<? super E>) in List
                public SortableList<V> sort(Comparator<? super V> cmp) {
                                       ^
  return type SortableList<V> is not compatible with void
  where V,E are type-variables:
    V extends Object declared in class SortableList
    E extends Object declared in interface List
1 error

JDK 1.8은 기본 메소드로 인해 Java 소스 코드에 대한 순방향 비 호환성을 도입하지 않습니까?

수퍼 클래스 또는 인터페이스의 새 메소드는 호환성을 손상시킬 수 있습니다. 기본 메서드를 사용 하면 인터페이스 변경으로 인해 호환성이 깨질 가능성줄어 듭니다 . 기본 메서드가 인터페이스에 메서드를 추가 할 수있는 문을 열어 준다는 점에서 기본 메서드가 호환성이 깨지는 원인이 될 수 있습니다.

이것이 첫 번째 순방향 비 호환 변경입니까?

Java 1.0 이후로 표준 라이브러리에서 클래스를 서브 클래 싱했기 때문에 거의 확실하지 않습니다.

Was this considered or discussed when default methods were designed and implemented? Is it documented anywhere?

Yes, it was considered. See Brian Goetz's August 2010 paper "Interface evolution via “public defender” methods":

  1. Source compatibility

It is possible that this scheme could introduce source incompatibilities to the extent that library interfaces are modified to insert new methods that are incompatible with methods in existing classes. (For example, if a class has a float-valued xyz() method and implements Collection, and we add an int-valued xyz() method to Collection, the existing class will no longer compile.)

Was the (admittedly small) inconvenience discounted versus the benefits?

Before, changing an interface would definitely break compatibility. Now, it might. Going from 'definitely' to 'might' can be seen either positively or negatively. On the one hand, it makes it feasible to add methods to interfaces. On the other hand, it opens the door to the kind of incompatibility you saw, not just with classes, but with interfaces too.

The benefits are larger than the inconveniences, though, as cited at the top of Goetz's paper:

  1. Problem statement

Once published, it is impossible to add methods to an interface without breaking existing implementations. The longer the time since a library has been published, the more likely it is that this restriction will cause grief for its maintainers.

The addition of closures to the Java language in JDK 7 place additional stress on the aging Collection interfaces; one of the most significant benefits of closures is that it enables the development of more powerful libraries. It would be disappointing to add a language feature that enables better libraries while at the same time not extending the core libraries to take advantage of that feature.


Doesn't JDK 1.8 introduce a forward incompatibility for Java source code due to default methods?

Yes as you've seen your self.

Is this the first such forward incompatible change?

No. Java 5 enumkeyword was also breaking because before that you could have variables named that which would no longer compile in Java 5 +

Was this considered or discussed when default methods where designed and implemented? Is it documented anywhere?

Yes Orcale Java 8 source incompatibility description

Was the (admittedly small) inconvenience discounted versus the benefits?

Yes


We can draw a parallel with abstract class. An abstract class is intended to be subclassed so that the abstract methods can be implemented. The abstract class itself contains concrete methods that invoke the abstract methods. The abstract class is free to evolve by adding more concrete methods; and this practice may break subclasses.

Therefore the exact problem you described existed even before Java8. The problem is much more manifested on Collection APIs because there are a lot of subclasses out in the wild.

While the leading motivation of default method was to add some useful methods to existing Collection APIs without breaking subclasses, they had to exercise great self-control of doing it too much, for fear of breaking subclasses. A default method is added only if it's absolutely necessary. The real question here is, why List.sort is considered absolutely necessary. I think that is debatable.

Regardless of why default method was introduced in the 1st place, it is now a great tool for API designers, and we ought to treat it the same as concrete methods in abstract classes - they need to be designed carefully up front; and new ones must be introduced with great caution.


Ironically default methods in interfaces were introduced to allow existing libraries using those interfaces not to break, while introducing massive new functionality in the interfaces. (backward compatibility.)

Conflicts like that sort method might arise. Something to pay for the extra functionality. In your case also something to investigate (should new functionality be used instead?).

Java forward compatibility breaks are little, more in its typing system, which was constantly enlarged. First with generic types and now with inferred types from functional interfaces. From version to version and from compiler to compiler there were slight differences.


Reading this issue, I was thinking of its solution.
Default methods have solved the backward compatibility problems but forward compatibility issues will exist.
I think instead of extending existing classes, in such cases, we can have our application specific interfaces to add some desired behaviour to our class. We can implement this application specific interface and use it.

ReferenceURL : https://stackoverflow.com/questions/31188231/do-java-8-default-methods-break-source-compatibility

반응형

'programing' 카테고리의 다른 글

세트 멤버의 TTL  (0) 2021.01.15
WebAPI와 WebAPI 2의 차이점은 무엇입니까?  (0) 2021.01.15
Android Jar 라이브러리  (0) 2021.01.15
R의 데이터 프레임에 열 추가  (0) 2021.01.15
0.0.0.0이 유효한 IP 주소입니까?  (0) 2021.01.15