Stream and Optional in Java 8 bring us the fun of functional programming, but Java still lacks many key features of functional programming.
Lambda Expressions Optional and Stream It's just the tip of the iceberg for functional programming. This also led to the emergence of varvr and functionlajava class libraries, both of which originated from Haskell, a pure functional programming language.
If you want more "functional" programming, the first thing you need to pay attention to is not to interrupt monad (a design pattern, which means that an operation process is divided into multiple steps connected by functions).
As long as the function required for the next operation is provided, the whole operation will be carried out automatically Optional,Stream For example, many people often call Optional.get() and Stream.collect() to terminate monad in advance before they need to. This article mainly talks about how to make the code more "functional" through the promotion method.
Suppose there is an interface for calculating numbers.
public interface Math { int multiply(int a, int b); double divide(int a, int b); .. }
We will use this interface to calculate the number of packages using Optional.
public interface NumberProvider { Optional<Integer> getNumber(); }
Then we implement a method that can return the result of dividing two numbers by using Optional packing. Return null if one of the two numbers is null Optional . As follows:
public Optional<Double> divideFirstTwo(NumberProvider numberProvider, Math math) { Optional<Integer> first = numberProvider.getNumber(); Optional<Integer> second = numberProvider.getNumber(); if(first.isPresent() && second.isPresent()) { double result = math.divide(first.get(), second.get()); return Optional.of(result); } else { return Optional.empty(); } }
The above code is not elegant. There is a lot of code being done Optional The packaging and unpacking of. You can make the above code more "functional", as follows:
public Optional<Double> divideFirstTwo(NumberProvider numberProvider, Math math) { return numberProvider.getNumber() .flatMap(first -> numberProvider.getNumber() .map(second -> math.divide(first, second))); }
In this way, the code is much less and much more elegant. Call first Optional The flatMap of Lambda Call second Optional We can further extract a lifting method from the map of:
public interface Optionals { static <R, T, Z> BiFunction<Optional<T>, Optional<R>, Optional<Z>> lift(BiFunction<? super T, ? super R, ? extends Z> function) { return (left, right) -> left.flatMap(leftVal -> right.map(rightVal -> function.apply(leftVal, rightVal))); } }
As mentioned above, this method promotion can promote any function with two Optional parameters and one Optional result, so that the promoted function has one characteristic of Optional: if a parameter is empty, the result is empty.
If JDK extracts flatMap and map to a common interface, such as monad, then we can provide each instance of Java Monad( Stream,Lambda , own implementation class) to implement a public promotion function. But the reality is that we have to copy and paste the above code for each instance. The final dividerfirsttwo code is as follows:
import static com.ps.functional.monad.optional.Optionals.lift; ... public Optional<Double> divideFirstTwo(NumberProvider numberProvider, Math math) { return lift(math::divide).apply(numberProvider.getNumber(), numberProvider.getNumber()); }
Original text: https://dzone.com/articles/lifting-functions-to-work-with-monads-in-java?edition=311409 //Translator: SA ran Hang https://www.rowkey.me/blog/2017/08/18/lift-functions/
Recommend to my blog to read more:
1.Java JVM, collection, multithreading, new features series
2.Spring MVC, Spring Boot, Spring Cloud series tutorials
3.Maven, Git, Eclipse, Intellij IDEA series tools tutorial
4.Latest interview questions of Java, backend, architecture, Alibaba and other large factories
Feel good, don't forget to like + forward!