Dawno nie było pisania technicznego :(, troszkę jest rzeczy na głowie. Dzisiaj na tapetę idzie Java 8 i jej jeden z ficzerów operator Lambda.
Co to są Lambdy?
Jest to uproszczony sposób zapis metod anonimowych, tylko taki bardziej czytelniejszy. Lambda nawiązuje do języków funkcyjnych, gdzie tak jak w matematyce kładzie się nacisk na obliczanie wartości danego wyrażenia. W przeciwieństwie do typowych języków programowanie, gdzie ważne jest wykonywanie poleceń. Przykładem języków typowo funkcyjnych jest: Erlang, Scala.
Zastosowanie:
Lambdy mają w Javie 8 zastosowanie do:
- operowania na kolekcjach danych
- operowania na strumieniach danych, w połączeniu ze strumieniami oraz nowym API Nio2
Składnia polecenia lambda:
(lista parametrów) -> {polecenia;}
Gdzie:
- lista parametrów jest opcjonalna
- opcjonalne jest podawanie typów parametrów
- opcjonalne są nawiasy bloku
- nie jest wymagane wyrażenie return
- lambdy mają dostęp do pól, metod instancji obiektu
- lambdy mają dostęp do statycznych metod i pól klasy
- w przypadku użycia lambdy na finalnym polu gdzie lambda ma przypisać do niego wartość dostaniemy błąd kompilacji
Przykłady:
Proste użycie gdzie nie ma określonego typu zwracanych danych, są określane na podstawie interfejsu funkcyjnego, dokonuje się prostych operacji:
package pl.jclab.examples.lambda; public class Lambda1{ @FunctionalInterface interface DoubleLambda{ double getValue(); } @FunctionalInterface interface StringLambda{ String getValue(); } @FunctionalInterface interface DoubleParameterLambda{ double getValue(double x, double y); } @FunctionalInterface interface StringParameterLambda{ String getValue(String x, String y); } @FunctionalInterface interface GenericLambda<T>{ T getValue(T x, T y); } public static void main(String[] args){ // // Proste przypisanie // DoubleLambda testPi = () -> 3.14; System.out.println(testPi.getValue()); StringLambda testString = () -> "SuperDuper"; System.out.println(testString.getValue()); // // Operacje na danych z kilkoma parametrami zdefiniowanymi w interface // DoubleParameterLambda testMultipler = (x, y) -> x * y; System.out.println(testMultipler.getValue(3, 4)); DoubleParameterLambda testAdd = (x, y) -> x + y; System.out.println(testAdd.getValue(3, 4)); DoubleParameterLambda testDiv = (x, y) -> x / y; System.out.println(testAdd.getValue(3, 4)); // // Trochę zabawy na tekstach, pokazany dostęp do metod // StringParameterLambda toUpperAndLower = (x, y) -> x.toUpperCase() + " " + y.toLowerCase(); System.out.println(toUpperAndLower.getValue("DEMO", "DEMO")); System.out.println(toUpperAndLower.getValue("demo", "demo")); // // Przykład z generykiem // GenericLambda<Double> testGeneric = (x, y) -> x * y; System.out.println(testGeneric.getValue(5.0, 10.0)); GenericLambda<Integer> testGeneric2 = (x, y) -> x * y; System.out.println(testGeneric2.getValue(5, 10)); GenericLambda<String> testGeneric3 = (x, y) -> x + "_" + y; System.out.println(testGeneric3.getValue("5", "10")); } } |
Przykład bardziej złożonej lambdy, gdzie ciało lambdy wykonuje obliczenia, są pętle oraz warunki sterowania, wywalić wyjątkiem w twarz:
package pl.jclab.examples.lambda; public class Lambda2{ @FunctionalInterface interface OneParameter{ double calculate(int x) throws IllegalArgumentException; } public static void main(String[] args){ // // W ciele lambdy realizowane są złożone operacje // // // Silnia // OneParameter factorial = (x) -> { int summary = 1; for (int i = 1; i <= x; ++i){ summary = i * summary; } return summary; }; System.out.println(factorial.calculate(1)); System.out.println(factorial.calculate(2)); System.out.println(factorial.calculate(5)); System.out.println(factorial.calculate(10)); // // Ciąg fibonaccigo // OneParameter fibonacci = (x) -> { if (x == 0){ throw new IllegalArgumentException(); } if (x == 1 || x == 2){ return 1; } int a = 0, b = 1, fibb = 1; for (int i = 2; i <= x; i++){ fibb = a + b; a = b; b = fibb; } return fibb; }; System.out.println(fibonacci.calculate(1)); System.out.println(fibonacci.calculate(2)); System.out.println(fibonacci.calculate(5)); System.out.println(fibonacci.calculate(10)); } } |
Wielowątkowe wywołania:
package pl.jclab.examples.lambda; public class Lambda3{ public static void main(String[] args){ Runnable run = () -> System.out.println("args = [" + args + "]"); Runnable run2 = () -> { int a = 10; int b = 10; System.out.println("a+b=" + a + b); }; run.run(); run2.run(); } } |
Użycie w kolekcjach i tablicach, porównywanie – lambda jako komparator w przypadku sortowania danych:
package pl.jclab.examples.lambda; import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; public class Lambda4{ String[] names = { "Marcia", "Darrel", "Sandee", "Trena", "Clark", "Almeta", "Bettyann", "Yael", "Harvey", "Andy" }; public static void main(String[] args){ Lambda4 lambda4 = new Lambda4(); // // Sorotowanie przy użyciu funkcji anonimowych // List<String> namesList = Arrays.asList(lambda4.names); Collections.sort(namesList, new Comparator<String>(){ @Override public int compare(String o1, String o2){ return o1.compareTo(o2); } }); System.out.println("Sort ASC collection by anonymous inner class: " + namesList.toString()); // // Sortowanie przy użyciu funkcji lambda // namesList = Arrays.asList(lambda4.names); Collections.sort(namesList, (s1, s2) -> s1.compareTo(s2)); System.out.println("Sort ASC collection by lambda: " + namesList.toString()); // // Sortowanie przy użyciu funkcji lambda i statycznej metody // namesList = Arrays.asList(lambda4.names); Collections.sort(namesList, String::compareTo); System.out.println("Sort ASC collection by static method: " + namesList.toString()); // // Sortowanie odwrotne przy użyciu funkcji lambda // namesList = Arrays.asList(lambda4.names); Collections.sort(namesList, (s1, s2) -> -s1.compareTo(s2)); System.out.println("Sort DESC collection by lambda: " + namesList.toString()); } } |
Użycie w kolekcjach – forach, filtrowanie danych:
package pl.jclab.examples.lambda; import java.util.Arrays; import java.util.List; public class Lambda5{ private static String[] names = { "Marcia ", "Darrel ", "Sandee ", "Trena ", "Clark ", "Almeta ", "Bettyann ", "Yael ", "Harvey ", "Andy " }; public static void main(String[] args){ // // Standartowy for // List<String> namesList = Arrays.asList(Lambda5.names); System.out.println("Standard for:"); for (String name : namesList){ System.out.print(name); } System.out.println(); // // ForEach przy pomocy lambdy // System.out.println("Lambda for:"); namesList.forEach(s -> System.out.print(s)); System.out.println(); System.out.println("Lambda for static method:"); namesList.forEach(System.out::print); System.out.println(); // // Modyfikacja i filtrowanie danych przy pomocy strumieni i lambdy // System.out.println("Stream filter and map:"); namesList.stream() .filter(s -> s.startsWith("A")) .map(s -> s + " ") .forEach(System.out::print); System.out.println(); // // Sortowanie i modyfikacja danych przy pomocy strumieni i lambdy // System.out.println("Stream sort and map:"); namesList.stream() .sorted() .map(s -> s + " ") .map(String::toUpperCase) .forEach(System.out::print); System.out.println(); } } |
Możliwość komentowania jest wyłączona.