Programowanie funkcyjne - rlip/java GitHub Wiki
to takie, które posiadają tylko 1 metodę, można go oznaczyć @FunctionalInterface i można do nich użyć lambdy:
Movable m1 = new Movable() {
@Override
public int move(String direction) {
return 11;
}
};
Movable m2 = (String direction) -> {
return 11;
};
Movable m3 = (String direction) -> 11; // jak jest 1 linijka to nie piszemy return
Movable m4 = direction -> 11; // jak jest 1 argument to nie trzeba podawać jego typu
taki interfejs, który zamienia jakiś obiekt na booleana
Predicate<Student> isAnia = new Predicate<Student>() {
@Override
public boolean test(Student student) {
return student.getName().equals("Ania");
}
};
Predicate<Student> isUnder30 = student -> student.getAge() < 30;
Predicate<Student> isAniaAndUnder30 = isAnia.and(isUnder30);
Predicate<Student> isAniaORUnder30 = isAnia.or(isUnder30);
Predicate<Student> isNotAnia = isAnia.negate();
bierze jakiś obiekt, wykonuje jakąś operację i nic nie zwraca
Consumer<Student> printStudentName = new Consumer<Student>() {
@Override
public void accept(Student student) {
System.out.println(student.getName());
}
};
Consumer<Student> printStudentName = (student) -> System.out.println(student.getName());
//można je też łączyć
printStudentName.andThen(printStudentNameToUppercase))
odwrotnie, nie bierze argumentów, coś zwraca
Supplier<List<Student>> supplierPredefinedStudents = new Supplier<List<Student>>() {
@Override
public List<Student> get() {
return createData();
}
};
Supplier<List<Student>> supplierPredefinedStudents = () -> createData();
Supplier<List<Student>> supplierPredefinedStudents = App::createData;
bierze 1 typ obiektu, modyfikuje go i zwraca inny typ obiektu
Function<Student,String> getStudentName = new Function<Student, String>() {
@Override
public String apply(Student student) {
return student.getName();
}
};
Function<Student,String> getStudentName2 = student -> student.getName();
Function<Student,String> getStudentName3 = Student::getName;
bierze 2 typy i zwraca 3
BiFunction<String, Student, Integer> bifunction = new BiFunction<String, Student, Integer>() {
@Override
public Integer apply(String s, Student student) {
return null;
}
};
bierze 2 obiekty i zwraca 1
BinaryOperator<Student> binaryOperator = new BinaryOperator<Student>() {
@Override
public Student apply(Student student, Student student2) {
return null;
}
};
żeby nie operować na klasach
IntPredicate intPredicate = new IntPredicate() { //są też inne, a odwrotnie działające mają przedrostek "To"
@Override
public boolean test(int value) {
return false;
}
};
opakowuje inny obiekt, które być, albo może go nie być
Tworzymy:
Optional.ofNullable(zmienna); // tak można stworzyć
Optional.of(zmienna) // to gdy jesteśmy pewni, że wartość nie jest nullem
Optional.empty() // pusty
Optional.get() - pobiera wartość, zwróci wyjątek, jeśli będzie to null
Potem:
index.ifPresent(new Consumer<Index>() {
@Override
public void accept(Index index) {
System.out.println(index.getName());
}
});
Index aa = index.orElse(new Index("aa")); // zwraca index, a jeśli nie ma to nowy index
Index aa2 = index.orElseGet(new Supplier<Index>() { // zwraca index, a jeśli go nie ma to zwraca suppliera
@Override
public Index get() {
return null;
}
});
index.filter(new Predicate<Index>() {
@Override
public boolean test(Index idx) {
return idx.getName().equals("1234");
}
});
index.filter(idx -> idx.getName().equals("1234")).ifPresent(new Consumer<Index>() {
@Override
public void accept(Index index) {
System.out.println("Znalazłem");
}
});
index.map(i -> i.getName()).filter(iName -> iName.equals("111")).ifPresent(indexNr -> System.out.println(indexNr));
Klasa, albo można też zrobić na kolekcjach, jednokrotnego użytku
students.stream().filter(isAnia).map(getStudentName).forEach(print);
// z kolekcji wybieramy te które spełniają filter, następnie
// mapujemy wybierając tylko imię i wyświetlamy imię
TWORZENIE:
Stream.of("A","B","C"); // wymienione
students.stream(); // z kolekcji
Stream.generate(() -> Math.random()).limit(10).forEach((v) -> System.out.println(v));
Stream.generate(Math::random).limit(10).forEach(System.out::println); //losowy
Stream.iterate(0, i->i+2).limit(20).forEach(System.out::println); // 20 liczb parzystych
Są też streamy pymitywów, np InsStreem.rangeClosed(5,100).filter(i->i%2==0).forEach(System.out::println);
odfiltrowuje dane na streamach, przyjmuje predykat (zwracający booleanna), przepuszcza dane go spełniające
Stream<Student> stream = createDataStream();
stream
.filter(student -> student.getAge() > 25)
.filter((student) -> student.getName().equals("Ania"))
.map(Student::getName)
.forEach(print);
przyjmuje funkcję (coś co na podstawie jednego obiektu zwraca inny) i mapuje jeden typ obiektu w drugi
stream
.map(student -> student.getIndex())
.filter(optionalIndex -> optionalIndex.isPresent())
.map(optionalInddex -> optionalInddex.get())
.map(index -> index.getName())
.forEach(System.out::println);
Są też mapy do prymitywów:
createDataStream().map(Student::getAge).mapToInt(new ToIntFunction<Integer>() {
@Override
public int applyAsInt(Integer value) {
return value + 1;
}
}).forEach(System.out::println);
W optionalach:
// Optional<Optional<String>> - nie zwiększa to bezpieczeństwa od nula
assertEquals(Optional.of(Optional.of("STRING")),
Optional
.of("string")
.map(s -> Optional.of("STRING")));
// więc można zrobić jako Optional<String>
assertEquals(Optional.of("STRING"), Optional
.of("string")
.flatMap(s -> Optional.of("STRING")));
W stream:
List<List<String>> list = Arrays.asList(
Arrays.asList("a"),
Arrays.asList("b"));
System.out.println(list);
// Otrzymamy list of lists [[a], [b]]. Z faltMap:
System.out.println(list
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList()));
// Bedzie to [a, b].
forEach - przyjmuje consumera (coś co coś przyjmuje i nic nie zwraca)
findFirst() - zwróci pierwszy obiekt który dotrze do tego momentu w strumieniu
anyMatch(Predicate) - przyjmuje predykat i zwraca boolana czy jakiś spełnia ten warunek
allMatch(Predicate) - j.w. tylko sprawdza czy wszystkie obiekty ze strumienia spełniają warunek
noneMatch(Predicate) - j.w. tylko sprawdza czy wszystkie obiekty ze strumienia nie spełniają warunku
Boolean atLeastOneAnia = createDataStream()
.anyMatch(student -> student.getName().equals("Ania"));
Boolean allAreAnia = createDataStream()
.allMatch(student -> student.getName().equals("Ania"));
Boolean thereIsNotAnyAnia = createDataStream()
.noneMatch(student -> student.getName().equals("Ania"));
Przyjmuje wartość początkową i binary operator (przyjmujący 2 wartości i zwracający jedną z nich) zwraca jeden łączny wynik Binaryoeratora dla wszystkich elementów
Double reduce = Stream.generate(Math::random).limit(10)
// .reduce(0.0, Double::sum) // to samo co
.reduce(0.0, new BinaryOperator<Double>() {
@Override
public Double apply(Double aDouble, Double aDouble2) {
return aDouble + aDouble2;
}
});
createDataStream().map(student -> student.getAge())
// .reduce( (a1, a2) -> a1 > a2 ? a1 : a2) // to samo co
.reduce(Integer::max)
.ifPresent(System.out::println);
zbiera dane i zwraca listę, mapę albo coś innego
String agesString = createDataStream().map(student -> student.getAge()).map(age -> age.toString()).collect(Collectors.joining(", "));
System.out.println(agesString);
Map<Integer, List<Student>> studentsByAgeMap = createDataStream().collect(groupingBy(Student::getAge));
studentsByAgeMap.forEach(new BiConsumer<Integer, List<Student>>() {
@Override
public void accept(Integer integer, List<Student> students) {
System.out.println(integer.toString() + ":");
students.stream().map(Student::getName).forEach(System.out::println);
}
});
}
Map<String, Boolean> updatableAndAllowedCountries = cappingConfig.updatableCountries()
.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue() && allowedCountries.contains(entry.getKey())));
limit(3) - ile elementów przepuścić
skip(3) - ile początkowych elementów pominąć
distinct() - przepuszcza tylko unikalne, bazuje na metodzie equals
sorted() - bez argumentu - sortuje wg. naturalnego porządku korzysta z metody compareTo
sorted(Comparator) - można też z własnym comparatorem
count() - ilość elementów w strumieniu