Java 8 - funkcyjne interfejsy

0
@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
	
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

Zastanawia mnie pierwsze linijka 2 bloku kodu. Co ona dokładnie robi? Kiedy ona jest odpalana. Bo to wygląda tam jak zdefiniowanie działania, a dopiero później przy wywołaniu .convert("123"); gdzie wkładany jest String zostaje to skonfertowane na Integera.

Dobrze sądzę? Może ktoś to rozjaśnić?

1

W tym miejscu:

Converter<String, Integer> converter = (from) -> Integer.valueOf(from);

definiujesz ciało funkcji. W 2. linijce kodu po prostu ją wywołujesz przekazując "123".

Definicja tej funkcji to po prostu odpowiednik tego:

	<F, T> Converter<String, Integer> converterNormal() {
		return new Converter<String, Integer>() {

			@Override
			public Integer convert(String from) {
				
				return Integer.valueOf(from);
			}
		};
	}

Jak widzisz tworzysz po prostu klasę anonimową, a wyrażenie lambda jest nowszym i krótszym sposobem zapisu tego typu funkcji.

Przykład:

public class Start {

	public static void main(String[] args) {
		
		System.out.println(converter.convert("2"));
		System.out.println(converterNormal().convert("2"));
	
	}
	
	public static <F, T> Converter<String, Integer> converterNormal() {
		return new Converter<String, Integer>() {

			@Override
			public Integer convert(String from) {
				
				return Integer.valueOf(from);
			}
		};
	}

	private static Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
	
	@FunctionalInterface
	interface Converter<F, T> {
		T convert(F from);
	}
	
}
0
final int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
stringConverter.convert(2);     // 3

Ok czyli to też przejdzie, bo jakbyśmy zamienili to na klasę anonimową to ona też by miała dostęp do tej lokalnej zmiennej

final int num

. Dobrze rozumiem?

Ale czemu zadziała taki przykład:

int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

a to już nie?

int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
num = 3;
0

Z tego co czytałem to w Javie 8 przy wyrażeniach Lambda można już ominąć "final", ale zmienna i tak zachowuje się jak finalna i nie można zmieniać jej wartości. Ale pozwala to na ładniejszy zapis, bo zawsze irytowały te finale.

0

Wraz z interfejsami funkcyjnymi do specyfikacji Javy wdarło się nowe określenie - "effective final". Zmienna zadeklarowana BEZ final, ale zachowująca się w kodzie jak final.

0

@stopa
no właśnie, ale dlaczego tamten ostatni blok nie zadziała? Przez to, że zmienna używana w lamdach jest finalna domyślnie i potem nie można wykonać na niej zapisu/modyfikacji tak?

0

Nie wiem jak to działa dokładnie, ale na logikę, jeśli chcesz użyć tej zmiennej w klasie anonimowej, to musi zostać przekształcona w "effective final" (tak jak wspomniał Krwawy Kaczor), więc potem nie możesz już zmienić jej wartości, bo ma zachowanie zmiennej finalnej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1