Zmiany w interfejsach

Dawniej interfejsy mogły zawierać wyłącznie metody, które z założenia były public i abstract. Metody interfejsu określały jakie operacje ma wykonywać klasa implementująca, ale nie określały sposobu, w jaki te operacje będą wykonywane. Nie jest to już prawdą.

Metody domyślne w interfejsach

Od Java 8 w interfejsach obok metod abstrakcyjnych można umieszczać metody oznaczone słowem kluczowym default, umieszczanym przed nazwą typu zwracanego przez metodę. Metody te z założenia są public. Metody te zawierają kod określający, nie tylko co ma być wykonywane, ale również jak te operacje mają być wykonane. Są to więc pełne metody. Klasa implementująca interfejs przejmuje te metody.

NType
interface NType {
        default int amod(int index, int modulus) {
		int i = index;
		i = i % modulus;
		if(i == 0){
			i = modulus;
		}
		if(i < 0){
			i = (modulus + i);
		}
		return i;
	}
}

W interfejsie znalazła się metoda amod() oznaczona słowem kluczowym default. Teraz możemy jej użyć w klasie Liczba implementującej ten interfejs:

			
Liczba liczba = new Liczba();
System.out.println(liczba.amod(32, 12));

Operator amod podobny jest do operatora %. Rożni się od tego w Javie tym, że 1) w przypadku gdy wynik index%modulus == 0 zwraca nie 0, ale modulus, 2) gdy wynik index%modulus<0 zwraca nie liczbę ujemną, ale wynik powiększony o modulus.

Metoda amod() zachowuje się dokładnie tak jak zachowywała się gdyby była umieszczona w klasie Liczba.

Dodawanie metod domyślnych do istniejących interfejsów

Do Javy 8 umieszczenie nowej metody w interfejsie powodowało automatycznie konieczność dodania implementacji tej metody we wszystkich klasach implementujących interfejs lub dodania słowa kluczowego abstract do tych klas.

W Java 8 dodanie do interfejsu metody oznaczonej jako default nie powoduje konieczności dokonywania jakichkolwiek zmian w istniejącym kodzie klas implementujących ten interfejs. Po prostu metoda staje się automatycznie dostępna dla wszystkich klas.

Oczywiście metodę możemy przesłonić w klasie implementującej, jeżeli zajdzie taka potrzeba.

W interfejsie możemy umieścić dowolną liczbę metod domyślnych.

Metody statyczne w interfejsach

Kiedyś metody statyczne mogły być gromadzone w klasach zawierających prywatny konstruktor. Przykładem takiej niewielkiej klasy jest klasa ColorUtil.

Obecnie nie ma potrzeby używania takich klasy. Metody można bezpośrednio przenieść do interfejsu:

ColorUtil2
interface ColorUtil2 {
	public static String HexToRGB(String hexa) {
		Integer R = Integer.valueOf(hexa.substring(0, 2), 16);
		Integer G = Integer.valueOf(hexa.substring(2, 4), 16);
		Integer B = Integer.valueOf(hexa.substring(4, 6), 16);
		return ("RGB:[" + R + "," + G + "," + B + "]");
	}
	...

Metod statycznych umieszczonych w interfejsie używamy identycznie jak metod umieszczonych w klasie z prywatnym konstruktorem

ColorUtilTest1
System.out.println(ColorUtil.RGBToHex(25, 50, 75));
System.out.println(ColorUtil2.RGBToHex(25, 50, 75));

Wynik jest w obu przypadkach jednakowy:

0x19324b
0x19324b

W interfejsie możemy umieścić dowolną liczbę metod statycznych. Słowa kluczowe static i default w metodach domyślnych i statycznych wykluczają się wzajemnie, gdyż oczywiście metody default są metodami instancji (ColorUtil3), a metody static są metodami klasy (ColorUtil2):

ColorUtilTest2
System.out.println(ColorUtil2.RGBToHex(25, 50, 75));
//System.out.println(ColorUtil3.RGBToHex(25, 50, 75));//błąd
Test2 t = new Test2();
System.out.println(t.RGBToHex(25, 50, 75));

Interfejsy funkcyjne i metody funkcyjne

W Javie 8 zwykłe interfejsy zawierające wyłącznie jedną metodę abstrakcyjną zostały nazwane interfejsami funkcyjnymi. Taka metoda w interfejsie została nazwana metodą funkcyjną. Taki i wyłącznie taki typ interfejsu pozwala na używanie go w tzw. wyrażeniach funkcyjnych lambda. Interfejsy funkcyjne poza metodą funkcyjną mogą zawierać metody domyślne i statyczne.

Interfejs IType<T> jest przykładem interfejsu funkcyjnego:

IType
public interface IType<T> {
	boolean equals(T x, T y);
}

Przykładem interfejsu funkcyjnego, który istnieje w języku Java od dawna jest na przykład Runnable zawierający jedną metodę run(), a także Comparator z metodą compareTo() czy ActionListener z metodą actionPerformed.

Metody anonimowe

Najczęstszym wykorzystaniem powyższych (i innych) interfejsów funkcyjnych jest implementacja metody funkcyjnej przez utworzenie klasy anonimowej. W Java 8 stworzono pojęcie anonimowych metod, tworzonych przez programistę, które przez kompilator zamieniane są automatycznie na odpowiednie anonimowe klasy wewnętrzne.

Pliki do ściągnięcia

lambdas2.zip (pakiet)

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *