Delay calculation of Stream in Java8 actual combat

  • 2021-11-10 09:38:14
  • OfStack

Directory 1. Functional programming
1.1 Example 1: No action in the method modifies the existing structure
1.2 Example 2: "Tail-pass" iteration
2. Corrification
3. Functional data structures-persistent
4. Delay calculation of Stream
4.1 List Interface 4.2 Delay List 4.3 Create an Infinite Delay List 4.4 Create an Infinite Delay Prime List 4.5 Use Infinite Delay Prime List Summary

1. Functional programming

To be called a functional expression, a function or method should not throw any exceptions. Using Optional < R > Type as the return value.

Transparency: There is no action in the method that modifies the existing structure

When programming with Java8, try to use Stream instead of iterative operations. If recursion can be simpler and has no side effects, recursion should be used instead of iteration.

The "tail-recursive" iteration does not need to save the intermediate value of each recursive calculation on different stack frames. At present, Java does not support this optimization, and many modern JVM languages, such as Scala and Groovy, support this form of recursive iterative optimization.

1.1 Example 1: No action in the method modifies the existing structure

Gets a subset of the list:


    public static List<List<Integer>> findAllSubList(List<Integer> list) {
        if (list.size()==0) {
            List<List<Integer>> res = new ArrayList<>();
            res.add(Collections.emptyList());
            return res;
        }
        Integer first = list.get(0);
        List<Integer> subList = list.subList(1, list.size());
        List<List<Integer>> allSubList = findAllSubList(subList);
        List<List<Integer>> allSubList2 = insertAll(first, allSubList);
        return concat(allSubList, allSubList2);
    }
    
    private static List<List<Integer>> concat(List<List<Integer>> allSubList, List<List<Integer>> allSubList2) {
        List<List<Integer>> res = new ArrayList<>(allSubList);
        res.addAll(allSubList2);
        return res;
    }

    private static List<List<Integer>> insertAll(Integer item, List<List<Integer>> allSubList) {
        List<List<Integer>> res = new ArrayList<>();
        for (List<Integer> a : allSubList) {
            List<Integer> oneList = new ArrayList<>(a);
            oneList.add(item);
            res.add(oneList);
        }
        return res;
    }

1.2 Example 2: "Tail-pass" iteration

Find the factorial of n:

Scenario 1: Iteration


    /**
     *  Using iteration to calculate factorial 
     * r  And  i  Is updated in each iteration 
     * @param n
     * @return
     */
    public static int factorialIterator(int n) {
        int r = 1;
        for (int i=1; i<=n; i++) {
            r *= i;
        }
        return r;
    }

Scenario 2: Using recursion


    /**
     *  Use recursion   Calculate factorial 
     *   It is less efficient than iteration: because every recursion needs to create a stack frame 
     * @param n
     * @return
     */
    public static int factorialRecursive(int n) {
        return n==1? 1 : n * factorialIterator(n-1);
    }

Scenario 3: Using Stream


    /**
     *  Use Stream  Calculate factorial 
     * @param n
     * @return
     */
    public static int factorialStream(int n) {
        return IntStream.rangeClosed(1, n).reduce(1, (x, y)->x*y);
    }

Scenario 4: Recursive optimization: "tail-recursive" iteration


    /**
     *  Tail - Handing   Iteration 
     * @param n
     * @return
     */
    public static int factorialTailIterator(int n) {
        return factorialTailHelp(1, n);
    }

    /**
     *  Tail - Handing   Iterative helper class 
     * @param acc
     * @param n
     * @return
     */
    private static int factorialTailHelp(int acc, int n) {
        return n==1?acc:factorialTailHelp(acc*n, n-1);
    }

2. Corrification

Corritization: A technique that helps you modularize functions and improve code reusability.

Corritization represents a method of converting a function with n tuple parameters into a chain of n 1-variable functions.

3. Functional data structures-persistent

The value of the data structure is always kept at 1, which is not affected by changes in other parts.

Additional condition: All users who use persistent data structures must abide by this 1 "do not modify" principle. Do not modify the return value.

4. Delay calculation of Stream

Create a list of prime numbers:

4.1 List Interface


/**
 * @Date 2021/9/5
 * @Author lifei
 */
public interface MyList<T> {

    T head();
    MyList<T> tail();

    MyList<T> filter(Predicate<T> p);

    default boolean isEmpty() {
        return true;
    }
}

4.2 Delay List


public class LazyList<T> implements MyList<T> {
    final T head;
    final Supplier<MyList<T>> tail;

    public LazyList(T head, Supplier<MyList<T>> tail) {
        this.head = head;
        this.tail = tail;
    }
    @Override
    public T head() {
        return head;
    }

    @Override
    public MyList<T> tail() {
        return tail.get();
    }

    @Override
    public MyList<T> filter(Predicate<T> p) {
        return isEmpty()?this:p.test(head())? new LazyList<>(head, ()->tail().filter(p)):tail().filter(p);
    }

    @Override
    public boolean isEmpty() {
        return false;
    }
}

4.3 Create a list with infinite delay


    /**
     *  Create 1 List of infinitely delayed 
     * @param n
     * @return
     */
    public static LazyList<Integer> from(int n) {
        return new LazyList<>(n, ()->from(n+1));
    }

4.4 Create a list of prime numbers with infinite delay


    /**
     *  Create 1 Of infinite loops   List of prime numbers 
     * @param numbers
     * @return
     */
    public static MyList<Integer> primes(MyList<Integer> numbers) {
        return new LazyList<>(numbers.head(), ()->primes(numbers.tail().filter(n->n%numbers.head()!=0)));
    }

4.5 List of prime numbers with infinite delay


    public static void main(String[] args) {
        LazyList<Integer> numbers = from(2);
        Integer res2 = numbers.head();
        Integer res3 = numbers.tail().head();
        Integer res4 = numbers.tail().tail().head();
        System.out.println(res2);
        System.out.println(res3);
        System.out.println(res4);
        System.out.println(" Create 1 List of prime numbers with infinite delay ");
        MyList<Integer> primes = primes(numbers);
        for (int i=0; i<30; i++) {
            if (!primes.isEmpty()){
                System.out.print(primes.head() + ", ");
                primes = primes.tail();
            }
        }
        System.out.println();

    }

Summarize


Related articles: