JetBrains Academy: Standard functional interfaces - Kamil-Jankowski/Learning-JAVA GitHub Wiki

JetBrains Academy: Standard functional interfaces

Accounts:

You have a class Account(String number, Long balance, boolean isLocked), the list accounts of type List<Account> and the method filter(List<T> elems, Predicate<T> predicate) for filtering the given list of type T by the predicate.

The class Account has the next methods: getNumber(), getBalance(), isLocked() for getting the values of the corresponding fields.

Write code for filtering the accounts list in two ways:

  1. get list with all non-empty accounts (balance > 0) and save it to the variable nonEmptyAccounts
  2. get all non-locked accounts with too much money (balance >= 100 000 000) and save it to the variable accountsWithTooMuchMoney The class Account, the list accounts (List<Account>) and the method filter(...) will be available during testing.

Example of use the filter method: The code below gets only even number from the list.

List<Integer> numbers = ...
List<Integer> evenNumbers = filter(numbers, number -> number % 2 == 0);

PS: it's often called behaviour parametrization because behaviour of the method filter is dependent of the given predicate.

List<Account> nonEmptyAccounts = filter(accounts, acc -> acc.getBalance() > 0);

List<Account> accountsWithTooMuchMoney = filter(accounts, acc -> !acc.isLocked() && acc.getBalance() >= 100000000);

Ternary operator:

Let's combine function to build more complex functions using standard functional interfaces.

Given the predicate condition and two functions ifTrue and ifFalse. Implement a method ternaryOperator which builds a new function returning the result of invoking ifTrue, if the predicate is true and otherwise - the result of invoking ifFalse.

Here is an example:

Predicate<Object> condition = Objects::isNull;
Function<Object, Integer> ifTrue = obj -> 0;
Function<CharSequence, Integer> ifFalse = CharSequence::length;
Function<String, Integer> safeStringLength = ternaryOperator(condition, ifTrue, ifFalse);

In the example above, the resulting function returns the length of a string if the reference to the string is not null, otherwise, it returns 0.

Note: it can be collapsed into a single line, but for clarity, additional variables are used.

public static <T, U> Function<T, U> ternaryOperator(
        Predicate<? super T> condition,
        Function<? super T, ? extends U> ifTrue,
        Function<? super T, ? extends U> ifFalse) {

    return x -> condition.test(x) ? (U) ifTrue.apply(x) : (U) ifFalse.apply(x);

}

An infinite numbers supplier:

Create a supplier that return integer values from 0 to infinity.

After first get() invocation supplier must return 0. After second - 1, next - 2, 3 etc.

Supplier<Integer> sup = getInfiniteRange();
for(int i = 0; i < 5; i++) {
    System.out.print(sup.get() + " ");
}

So this code should print "0 1 2 3 4 ".

Also it should be possible to use separate suppliers simultaneously.

Supplier<Integer> sup1 = getInfiniteRange();
Supplier<Integer> sup2 = getInfiniteRange();
 
for(int i = 0; i < 5; i++) {
    System.out.print(sup1.get() + " " + sup2.get() + " ");
}

For example, this code should print "0 0 1 1 2 2 3 3 4 4 ".

import java.util.function.*;

class FunctionUtils {

    public static Supplier<Integer> getInfiniteRange() {
        Integer[] numbers = {0};
        return () -> numbers[0]++;

        // or:
        // return IntStream.iterate(0, i -> i + 1).iterator()::next;
    }
}

⚠️ **GitHub.com Fallback** ⚠️