2015-10-14 19 views
5

Pytanie z książki:Java 8 - domyślne metody - obaw o starszych kod

w przeszłości (pre-Java 8), to powiedziano nam, że jest to zła forma dodać metody do interfejsu ponieważ złamie istniejący kod. Teraz powiedziano ci, że możesz dodawać nowe metody, pod warunkiem, że dostarczysz domyślną implementację.

  1. Jak to jest bezpieczne? Opisz scenariusz, w którym nowa metoda stream interfejsu Collection powoduje kompilację starszego kodu.
  2. Co ze zgodnością binarną? Będzie dziedzictwo kod z pliku JAR nadal działać?”

moje odpowiedzi są następujące, ale nie jestem pewien, o nich.

  1. Jest bezpieczny tylko wtedy, gdy kod starszego typu nie przewiduje metodę o tej samej nazwie stream i tym samym podpisem (np. w starszej klasie, która implementuje Collection) W przeciwnym razie ten stary kod starszego oprogramowania nie powiedzie się kompilacji
  2. Myślę, że zgodność binarna jest zachowana, stary kod ze starego pliku JAR nadal będzie działał Ale nie mam żadnych wyraźnych argumentów na ten temat s.

Czy ktoś mógłby potwierdzić lub odrzucić te odpowiedzi, lub po prostu dodać więcej argumentów, odniesień lub jasności do tych odpowiedzi?

+0

[Powiązane] (http://stackoverflow.com/a/22618640/335858). – dasblinkenlight

+1

Postępowanie z zachowaniem zgodności binarnej było główną motywacją dodawania domyślnych metod do języka.Dodanie wartości domyślnej do istniejącej metody jest zgodne z binariami i źródłami; dodanie nowej metody z domyślną jest zgodna z binariami i źródłami (interakcje modulo ze sposobami zderzeń w podklasach - ma to identyczną charakterystykę kompatybilności co dodanie nowej metody do klasy nieostatecznej). –

+1

Podczas gdy kompatybilność binarna jest zachowywana, może nadal pojawiają się problemy, gdy wchodzą w interakcję z zachowaniem biblioteki JRE, jak w [tym scenariuszu] (http://stackoverflow.com/q/26816650/2711488). Możesz także wziąć pod uwagę, że metoda może mieć zgodny * podpis *, dlatego zaczyna zastępować nową 'domyślną' metodę bez zamiaru jej ... – Holger

Odpowiedz

8
  1. Nowa metoda stream() domyślne Collection zwraca Stream<E>, także nowy typ kodu w Javie 8. Legacy zawiedzie kompilację jeśli zawiera stream() metodę z tym samym podpisem, ale wracając coś innego, co w rezultacie daje zderzenie typów zwrotów.

  2. Starsza wersja kodu będzie działać tak długo, jak długo nie zostanie zrekompilowana.

pierwsze, 1,7, skonfiguruj następujące:

public interface MyCollection { 
    public void foo(); 
} 

public class Legacy implements MyCollection { 
    @Override 
    public void foo() { 
     System.out.println("foo"); 
    } 

    public void stream() { 
     System.out.println("Legacy"); 
    } 
} 

public class Main { 
    public static void main(String args[]) { 
     Legacy l = new Legacy(); 
     l.foo(); 
     l.stream(); 
    } 
} 

Z -source 1.7 -target 1.7, to kompiluje i działa:

$ javac -target 1.7 -source 1.7 Legacy.java MyCollection.java Main.java 
$ java Main 
foo 
Legacy 

Teraz w 1,8, dodamy metodę strumienia MyCollection .

public interface MyCollection 
{ 
    public void foo(); 
    public default Stream<String> stream() { 
     return null; 
    } 
} 

Kompilujemy tylko MyCollection w wersji 1.8.

$ javac MyCollection.java 
$ java Main 
foo 
Legacy 

Oczywiście nie możemy ponownie skompilować Legacy.java.

$ javac Legacy.java 
Legacy.java:11: error: stream() in Legacy cannot implement stream() in MyCollection 
    public void stream() 
       ^
    return type void is not compatible with Stream<String> 
1 error 
+5

Należy zauważyć, że ta kompatybilność z dużymi literami nie jest nowa z domyślnymi metodami; ten sam problem pojawił się w Javie 1.0, jeśli dodasz metodę do nadklasy, która jest niekompatybilna z tą samą metodą w jakiejś podklasie. Dodawanie metod do interfejsów z wartościami domyślnymi ma dokładnie takie same cechy zgodności, jak dodawanie metod do klas. –

+3

Myślę, że metody zderzeń są mniejszym problemem, ponieważ kompilator je dostrzega. Większy problem występuje, gdy podpis nie koliduje. W przypadku 'strumienia()' jest to niemożliwe, ponieważ typem powrotu jest nowa klasa. Ale pomyśl o "sort (Komparator)". Mógłbyś mieć taką metodę w swojej niestandardowej implementacji 'List' przed wersją 8, a przed wersją Java 8 wdrożenie jej poprzez delegowanie do' Collections.sort' byłoby uzasadnione. Teraz 'Collections.sort' deleguje do' List.sort', które metoda pre-Java 8 przesłoniła bez zamiaru. Kompilator nie powie Ci o tym problemie ... – Holger