Java 8 #2: wyrażenia lambda i interfejs funkcyjny

Wyrażenie lambda

Wyrażenia lambda (ang. lambda expression) są próbą zaimplementowania koncepcji związanych z programowaniem funkcyjnych* w pełni obiektowym języku jakim jest Java. Koncept ten jest bardzo stary, o czym możesz się przekonać czytając chociażby blog Martina Fowlera**. Dotychczas w Javie pewną brzydką alternatywą dla wyrażeń lambda były klasy anonimowe. Sam przyznasz jednak, że nie są one zbyt eleganckim rozwiązaniem.

Wyrażenia lambda wyglądają dużo lepiej i poprawiają czytelność kodu. Kolejną przewagą wyrażeń lambda, jest to, że obliczenia zawarte w nich nie wychodzą poza blok funkcji, co rozwiązuje wiele problemów w programowaniu obiektowym, związanych z kontrolą stanu obiektu***. Przypominają one też funkcje matematyczne typu f(x)=x+1, z tą różnicą, że w tym przypadku, masz też możliwość używania takiej funkcji nie podając żadnego argumentu i de facto nic nie zwracając.

public class LambdaTest {

	public static void main(String[] args) {
		Playable anonymousClass = new Playable() {
			
			@Override
			public void play() {
				System.out.println("JDK 7");
			}
		};
		
		Playable lambdaExpression = () -> System.out.println("JDK 8");
		
		anonymousClass.play();
		lambdaExpression.play();
	}
}

Interfejs funkcyjny

Aby móc skorzystać z wyrażenia lambda, należy wpierw zaimplementować z tzw. interfejs funkcyjny. Jego idea jest bardzo prosta, jest to zwykły interfejs tylko, że z jedną metodą abstrakcyjną (sygnaturą). Ważne podkreślenia jest też to, że Twój interfejs funkcyjny może mieć dowolną liczbę metod statycznych i domyślnych. Dodatkowo warto skorzystać z adnotacji @FunctionalInterface, która ostrzeże Cię przed skompilowaniem kodu, gdy Twój interfejs nie stosuje się do zasad opisanych wcześniej.

Przykładowy interfejs funkcyjny:

@FunctionalInterface
public interface Playable {

	public void play();
	//public void rewind(); can't add more than one signature to functional interface
}

Klasa anonimowa vs. interfejs funkcyjny

W przypadku powyżej, dwukrotnie skorzystałem z interfejsu Playable, raz implementując go w formie klasy anonimowej, drugi raz jako wyrażenie lambda. Wydaje się, że obie formy różni tylko zapis. To jednak nie prawda. Postaraj się sprawdzić poniższy zapis:

Object playable = new Playable() {
			
	@Override
	public void play() {
		System.out.println("JDK 7");
	}
};
		
Object lambda = () -> {
	System.out.println("JDK 8");
}; //error, lambda can't be an object, until it gets cast to specific interface

Object lambdaAfterCasting = (Playable) () -> {
	System.out.println("JDK 8");
};

Wyrażenia lambda i klasa Object

Dotąd mówiłem, że wszystko w Javie (poza typami prostymi) jest obiektem. Okazuje się, że od JDK w wersji 8, nie jest tak do końca. Lambda jest wyjątkiem i może być przypisana tylko i wyłącznie do konkretnego interfejsu funkcyjnego. W tej lekcji pokazałem Ci jedynie najprostszą z możliwych lambd do napisania, ale się domyślasz nie stoi nic na przeszkodzie, aby napisać bardziej skomplikowany interfejs funkcyjny.

@FunctionalInterface
public interface Drivable {
	
	public int accelerate(int force);
}
Drivable driver = x -> {
	System.out.println(x);
	return x*x;
};
		
int force = 5;
System.out.println(driver.accelerate(force));

Inne właściwości wyrażenia lambda

Taka lambda nie tylko przyjmuje argument, ale także zwraca wartość. Co więcej ma więcej niż jedną linię kodu. Możesz też używać lambd, w przypadku natywnych funkcji JDK, które spełniają warunki bycie interfejsem funkcyjnych (np. w przypadku Runnable). Więcej wariacji przeróżnych interfejsów funkcyjnych opiszę Ci w następnej lekcji.

*Więcej o programowaniu funkcyjnym: https://en.wikipedia.org/wiki/Functional_programming

**Link do notki Martina Fowlera z 2004 roku (!) odnośnie wyrażeń lambda: https://martinfowler.com/bliki/Lambda.html

***Przeczytaj o tzw. side effects w programowaniu: https://www.radford.edu/nokie/classes/320/Tour/side.effects.html

Kod do lekcji: https://github.com/developeronthego/java-jdk8/tree/master/src/main/java/java8/lambda

Czym jest klasa anonimowa, znajdziesz u mnie w lekcji: Java #44: klasy wewnętrzne

Stay in the Loop

Get the daily email from CryptoNews that makes reading the news actually enjoyable. Join our mailing list to stay in the loop to stay informed, for free.

Ostatnio dodane

- Advertisement - spot_img

Powiązane wpisy