FP / Funkcionálne programovanie v Jave

Funkcionálne programovanie
v Jave

Woman hands pouring latte in glass mug

Funkcie vyššieho rádu

Príklad

class LengthComparator implements Comparator<String> {
    public int compare(String x, String y) {
        return Integer.compare(x.length(), y.length());
    }
}

Arrays.sort(strings, new LengthComparator());

Anonymné triedy

Arrays.sort(strings, new Comparator<String>() {
    public int compare(String x, String y) {
        return Integer.compare(x.length(), y.length());
    }
});

Java 8

Anonymné funkcie

(x, y) -> x + y
Arrays.sort(strings,
    (x, y) -> Integer.compare(x.length(), y.length()));
Arrays.sort(strings, new Comparator<String>() {
    public int compare(String x, String y) {
        return Integer.compare(x.length(), y.length());
    }
});

Funkcionálne rozhrania

Funkcionálne rozhranie — rozhranie, ktoré má práve jednu abstraktnú metódu.

Comparator<String> byLength =
    (x, y) -> Integer.compare(x.length(), y.length());

Štandardné funkcionálne rozhrania — java.util.function

Referencie na metódy

Arrays.sort(strings, (x, y) -> x.compareToIgnoreCase(y));
Arrays.sort(strings, String::compareToIgnoreCase);

Cieľový objekt je prvým argumentom.

Kompozícia funkcií

boolean allOdd(List<String> words) {
    Function<Integer, Boolean> odd = (n) -> n % 2 == 1;
    return words.stream().map(odd.compose(String::length))
                         .reduce(Boolean::logicalAnd)
                         .get();
}

Closure

Voľné premenné


public static void repeatMessage(String text, int count) {
   Runnable r = () -> {
      for (int i = 0; i < count; i++) {
         System.out.println(text);
         Thread.yield();
      }};
   new Thread(r).start();
}

Uzáver (closure)

Stream

Prúdy

Prúd (Stream) — štruktúra reprezentujúca postupnosť operácií nad kolekciou. Balík java.util.stream

List<Entry> topNoSql = entries.stream()
    .filter(a -> a.getTags().contains("nosql"))
    .sorted(Comparator.comparing(Entry::getWords).reversed())
    .limit(3)
    .collect(Collectors.toList());
int wordCount = entries.stream()
    .filter(a -> a.getTags().contains("nosql"))
    .map(Entry::getWords)
    .reduce(Integer::sum)
    .orElse(0);
int wordCount = entries.stream()
    .filter(a -> a.getTags().contains("nosql"))
    .mapToInt(Entry::getWords)
    .sum();

Paralelné prúdy

int wordCount = entries.parallelStream()
    .filter(a -> a.getTags().contains("nosql"))
    .mapToInt(Entry::getWords)
    .sum();

Lazy evaluation

take 25 (map (^2) [1..])
IntStream.iterate(1, i -> i+1)
    .map(i -> i*i)
    .limit(25).toArray()
boolean hasLongNoSql = entries.stream()
      .filter(a -> a.getTags().contains("nosql"))
      .map(Entry::getWords)
      .anyMatch(w -> w > 1000);

Monády

Optional

public Optional<Integer> optionalAdd(
        Optional<Integer> val1, Optional<Integer> val2) {
    if (val1.isPresent() && val2.isPresent()) {
        return Optional.of(val1.get() + val2.get());
    }

    return Optional.empty();
}

flatMap

public Optional<Integer> optionalAdd(
        Optional<Integer> val1, Optional<Integer> val2) {
    return
           val1.flatMap( first ->
           val2.flatMap( second ->
           Optional.of(first + second)
    ));
}