Opening
JDK8 is known and used as Lambda. Many people will use it, such as Stream flow, but they are simple and easy to use, such as calling the Stream API of the collection, but they will not define their own function interface or API. Today, we use several cases to improve the use of function programming in Java.
Case demonstration
Function interface description
Interface | input parameter | Return type | explain |
---|---|---|---|
UnaryOperator | T | T | Unary function with the same input and output types |
Predicate | T | boolean | Assert |
Consumer | T | / | Consume a data, only input, no output |
Function<T,R> | T | R | Input T returns R, with input and output |
Supplier | / | T | Provide a data, no input, only output |
BiFunction<T,U,R> | (T,U) | R | Two input parameters |
BiPredicate<L, R> | (L,R) | boolean | Two input parameters |
BiConsumer<T, U> | (T,U) | void | Two input parameters |
BinaryOperator | (T,T) | T | Binary function with the same input and output types |
Case 1
Function<Integer, Integer> times2 = e -> e * 2; Function<Integer, Integer> squared = e -> e * e; // Execute the parameter first and then the caller /* * 1. 4 * 4 = 16 16 * 2 = 32 */ System.out.println("result: " + times2.compose(squared).apply(4)); // 32 /* * Execute the caller first: 4 * 2 = 8, and then execute the function passed in by then 8 * 8 = 64 */ System.out.println("result: " + times2.andThen(squared).apply(4)); // 64
These two methods, andThen, are called after the Function execution outside, and compose means that before the Function executes outside, it is called.
Case 2
@Test public void test2(){ // Add three numbers Function<Integer, Function<Integer, IntFunction<Integer>>> addfun3 = x -> y -> z -> x + y + z ; // Add 7 numbers Function<Integer, Function<Integer, Function<Integer, Function<Integer, Function<Integer, Function<Integer, IntFunction<Integer>>>>>>> addfun7 = x -> y -> z -> a -> c -> b -> d -> x + y + z + a + c + b + d; // 1+2+3 Integer sum = addfun3.apply(1).apply(2).apply(3); System.out.println(sum); }
In this way, the cumulative effect of chain programming can be realized
Case 3
@SafeVarargs private static <R> Function<R, R> combineFunctions(Function<R, R>... functions) { return Arrays.stream(functions) .reduce(Function::andThen) .orElseThrow(() -> new IllegalArgumentException("No functions to combine")); } @Test public void test3() { Function<Integer, Integer> addfun2 = x -> x * x; final Integer apply = combineFunctions(addfun2, addfun2).apply(2); System.out.println(apply); String str = "1,2,3,4,5,6"; Function<Object, Object> splitByComma = s -> ((String) s).split(","); Function<Object, Object> convertToInt = tokens -> Stream.of((String[]) tokens).map(Integer::valueOf).toArray(Integer[]::new); Function<Object, Object> findMax = ints -> Stream.of((Integer[]) ints).max(Integer::compare).get(); Integer max = (Integer) combineFunctions(splitByComma, convertToInt, findMax).apply(str); System.out.println(max); }
If you want to have a method that accepts variable length Function parameters, you can use Descriptor, where generics < R, R > represent input and input types. Generics are used for higher compatibility
Case 4
@Test public void test4(){ Function<Integer, Integer> addfun2 = x -> x * x; final Calculator<Integer, Integer> calculator = new Calculator<>(2); final Integer integer = calculator.combineFunctions(addfun2, addfun2); System.out.println(integer); } public class Calculator<R,T> { // Properties to be manipulated private Object input; public Calculator(Object input) { this.input = input; } // You can define the behavior of the object itself in this way @SuppressWarnings("unchecked") @SafeVarargs public final R combineFunctions(Function<T, T>... functions) { return (R) Arrays.stream(functions) .reduce(Function::andThen) .orElseThrow(() -> new IllegalArgumentException("No functions to combine")) .apply((T)input); } }
Domain development patterns have been heard and understood more or less. Objects can have their own behavior in addition to their own attributes. The behavior methods for objects can also be defined by functional programming paradigm.
Case 5
// Biconsumer < T, Integer > two input parameters T, Integer public static <T> Consumer<T> consumerWithIndex(BiConsumer<T, Integer> consumer) { class Obj { int i; } // It will only be called once. The reason depends on Java lang.Iterable#forEach Obj obj = new Obj(); // Consumer function returned return t -> { int index = obj.i++; // Execute system out. Println ("list [" + index + "] =" + item ") consumes the data of the specified generic type. consumer.accept(t, index); }; } @Test public void test5(){ val list = Arrays.asList("Hi", "I", "am", "Henry.Yao"); // 2 elements as a group val partition = Lists.partition(list, 2); partition.forEach(LambdaUtils.consumerWithIndex((item, index) -> { System.out.println("list[" + index + "]=" + item); })); }
When Java 8's forEach() circulates objects, there is no way to get the object index subscript. In this case, you can declare a functional method to do it. The final writing form is similar to the forEach syntax of Scala and js, which is very useful!
java.lang.Iterable#forEach
// action: is a Consumer function default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { /* Here, the Consumer function will be called circularly, and the content of the Consumer function returned by consumerWithIndex is t -> { int index = obj.i++; consumer.accept(t, index); } Therefore, Obj obj = new Obj() will only be called once, so you don't have to worry that if i is not reset to 0 during new Obj, it won't happen */ consumer.accept(t, index); } action.accept(t); } }
If I think the article is helpful to you, please praise, comment and collect. Your support is my biggest motivation!!!
Finally, Xiaobian sorted out some learning materials during the learning process, which can be shared with Java engineers and friends to exchange and learn from each other, If necessary, you can join my learning exchange group 323432957 to obtain Java architecture learning materials for free (including architecture materials of multiple knowledge points such as high availability, high concurrency, high performance and distribution, Jvm performance tuning, Spring source code, MyBatis, Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx, etc.)
Author: dingyu002
Source: dinyu002
The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.