Java 8 中函数接口分析

来源:互联网 发布:淘宝正品鞋店 编辑:程序博客网 时间:2024/05/23 16:50

本篇文章先介绍下java 8之前的回调方式。之后分析下函数接口中几个最常用的接口——Predicate, Consumer, Function,以及他们实际的应用

java 8之前的回调主要使用例如,新建一个监听器接口

[java] view plain copy
  1. /** 
  2.  *  
  3.  */  
  4. package com.smartchemical.redis_sample.api;  
  5.   
  6. /** 
  7.  * @author chenshijue 
  8.  * 
  9.  */  
  10. public interface Listener {  
  11.       
  12.     void onMessage();  
  13.       
  14. }  
新建一个监听器,并作为参数传递给发送函数

[java] view plain copy
  1. /** 
  2.  *  
  3.  */  
  4. package com.smartchemical.redis_sample.serivce;  
  5.   
  6. import com.smartchemical.redis_sample.api.ISampleDefault;  
  7. import com.smartchemical.redis_sample.api.Listener;  
  8.   
  9. /** 
  10.  * @author chenshijue 
  11.  * 
  12.  */  
  13. public class ListenerSampleImpl implements ISampleDefault {  
  14.       
  15.     protected void sendMessage(Listener listener){  
  16.         String newMsg = "new message";  
  17.         listener.onMessage(newMsg);  
  18.     }  
  19.   
  20.     @Override  
  21.     public void run() {  
  22.         Listener listener = new MsgListener();  
  23.         sendMessage(listener);  
  24.     }  
  25.   
  26. }  

现在来分析函数接口。

函数接口的定义(来自java.lang包FunctionalInterface注解里面的解释):

[java] view plain copy
  1. Conceptually, a functional interface has exactly one abstract method.   
函数接口概念上来说,就是只有一个抽象方法的接口。而这个抽象方法,可以被之后的lambda表达式、方法引用、构造函数引用覆盖。

理论上来说,java会将所有符合要求的接口看做函数接口。但通常我们会加上@FunctionalInterface注解,这是良好的编程习惯。

下面开始分析几个常用函数接口,Predicate, Consumer, Function。

1. Predicate

[java] view plain copy
  1. package java.util.function;  
  2.   
  3. import java.util.Objects;  
  4.   
  5. @FunctionalInterface  
  6. public interface Predicate<T> {  
  7.   
  8.     /** 
  9.      * Evaluates this predicate on the given argument. 
  10.      * 
  11.      * @param t the input argument 
  12.      * @return {@code true} if the input argument matches the predicate, 
  13.      * otherwise {@code false} 
  14.      */  
  15.     boolean test(T t);  
  16.   
  17.     /** 
  18.      * Returns a composed predicate that represents a short-circuiting logical 
  19.      * AND of this predicate and another.  When evaluating the composed 
  20.      * predicate, if this predicate is {@code false}, then the {@code other} 
  21.      * predicate is not evaluated. 
  22.      * 
  23.      * <p>Any exceptions thrown during evaluation of either predicate are relayed 
  24.      * to the caller; if evaluation of this predicate throws an exception, the 
  25.      * {@code other} predicate will not be evaluated. 
  26.      * 
  27.      * @param other a predicate that will be logically-ANDed with this 
  28.      *              predicate 
  29.      * @return a composed predicate that represents the short-circuiting logical 
  30.      * AND of this predicate and the {@code other} predicate 
  31.      * @throws NullPointerException if other is null 
  32.      */  
  33.     default Predicate<T> and(Predicate<? super T> other) {  
  34.         Objects.requireNonNull(other);  
  35.         return (t) -> test(t) && other.test(t);  
  36.     }  
  37.   
  38.     /** 
  39.      * Returns a predicate that represents the logical negation of this 
  40.      * predicate. 
  41.      * 
  42.      * @return a predicate that represents the logical negation of this 
  43.      * predicate 
  44.      */  
  45.     default Predicate<T> negate() {  
  46.         return (t) -> !test(t);  
  47.     }  
  48.   
  49.     /** 
  50.      * Returns a composed predicate that represents a short-circuiting logical 
  51.      * OR of this predicate and another.  When evaluating the composed 
  52.      * predicate, if this predicate is {@code true}, then the {@code other} 
  53.      * predicate is not evaluated. 
  54.      * 
  55.      * <p>Any exceptions thrown during evaluation of either predicate are relayed 
  56.      * to the caller; if evaluation of this predicate throws an exception, the 
  57.      * {@code other} predicate will not be evaluated. 
  58.      * 
  59.      * @param other a predicate that will be logically-ORed with this 
  60.      *              predicate 
  61.      * @return a composed predicate that represents the short-circuiting logical 
  62.      * OR of this predicate and the {@code other} predicate 
  63.      * @throws NullPointerException if other is null 
  64.      */  
  65.     default Predicate<T> or(Predicate<? super T> other) {  
  66.         Objects.requireNonNull(other);  
  67.         return (t) -> test(t) || other.test(t);  
  68.     }  
  69.   
  70.     /** 
  71.      * Returns a predicate that tests if two arguments are equal according 
  72.      * to {@link Objects#equals(Object, Object)}. 
  73.      * 
  74.      * @param <T> the type of arguments to the predicate 
  75.      * @param targetRef the object reference with which to compare for equality, 
  76.      *               which may be {@code null} 
  77.      * @return a predicate that tests if two arguments are equal according 
  78.      * to {@link Objects#equals(Object, Object)} 
  79.      */  
  80.     static <T> Predicate<T> isEqual(Object targetRef) {  
  81.         return (null == targetRef)  
  82.                 ? Objects::isNull  
  83.                 : object -> targetRef.equals(object);  
  84.     }  
  85. }  
Predicate接口只包含一个抽象方法,boolean test(T t),接受一个参数,返回一个boolean值。从这个抽象方法可以看出,Predicate接口主要作用是判断,例如在collection的removeIf的方法中,Predicate用来接收判断的表达式或者方法,来判断对元素的操作。

[java] view plain copy
  1. public void run() {  
  2.         List<Order> orderList1 = new ArrayList<Order>();  
  3.           
  4.         for (int i = 0; i < 6; i++){  
  5.             Order temp = new Order(String.valueOf(i), "man"100);  
  6.             orderList1.add(temp);  
  7.         }  
  8.         Predicate<Order> filter = o -> o.getAmount() > 99;  
  9.         orderList1.removeIf(filter);  
  10.     }  
上例中,Predicate接受一个lambda表达式,o -> o.getAmount() > 99,判断o的金额是否超过99。之后在list的removeIf中传入Predicate,list中的超过99的金额就会被删除。

and()方法,此方法返回一个Predicate<T>类型,意味着and方法可以像nodejs的then一样进行链式判断。例如:

[java] view plain copy
  1. public void run() {  
  2.         List<Order> orderList1 = new ArrayList<Order>();  
  3.         for (int i = 0; i < 6; i++){  
  4.             Order temp = new Order(String.valueOf(i), "man"98 + i);  
  5.             orderList1.add(temp);  
  6.         }  
  7.         Predicate<Order> filter = o -> o.getAmount() > 99;  
  8.         Predicate<Order> filter1 = o -> o.getCreatedBy().equals("man");  
  9.         orderList1.removeIf(filter.and(filter1));  
  10.         System.out.println(orderList1.size());<span style="white-space:pre">                </span>//结果2  
  11.     }  
negate()方法,此方法很简答,就是将test方法的值取非。

or()方法,接受另一个Predicate方法作为参数,将参数方法和本身的test方法取或。or()方法和and()方法一样,可以进行链式判断。

isEqual()方法,这个方法就很有趣了。我们看看它的实现:

[java] view plain copy
  1. /** 
  2.      * Returns a predicate that tests if two arguments are equal according 
  3.      * to {@link Objects#equals(Object, Object)}. 
  4.      * 
  5.      * @param <T> the type of arguments to the predicate 
  6.      * @param targetRef the object reference with which to compare for equality, 
  7.      *               which may be {@code null} 
  8.      * @return a predicate that tests if two arguments are equal according 
  9.      * to {@link Objects#equals(Object, Object)} 
  10.      */  
  11.     static <T> Predicate<T> isEqual(Object targetRef) {  
  12.         return (null == targetRef)  
  13.                 ? Objects::isNull  
  14.                 : object -> targetRef.equals(object);  
  15.     }  
首先它接受一个对象作为参数,返回一个Predicate类型的方法,如果参数targetRef为null,则直接返回Objects:null方法。

这个方法有趣的地方在,它接受一个目标对象,返回的不是boolean值,而是一个方法(object -> targetRef.equals(object)),此方法接受另一个对象为参数,判断两个对象是否相等。下面有一个例子便于理解。

[java] view plain copy
  1. public void run() {  
  2.         List<Order> orderList1 = new ArrayList<Order>();  
  3.         for (int i = 0; i < 6; i++){  
  4.             Order temp = new Order(String.valueOf(i), "man"98 + i);  
  5.             orderList1.add(temp);  
  6.         }  
  7.         Predicate<Order> filter1 = Predicate.isEqual(orderList1.get(2));  
  8.         Predicate<Order> filter2 = o -> o.getAmount() > 99;  
  9.         Predicate<Order> filter3 = o -> o.getCreatedBy().equals("man");  
  10.         orderList1.removeIf(filter1.and(filter2).and(filter3));  
  11.         System.out.println(orderList1.size());   //结果为5  
  12.     }  
以上代码,filter1为判断元素是否和orderList1.get(2)元素相等的方法,filter2是判断金额是否超过99的方法,filter3是判断创建人是否是man的方法。三个filter满足的元素只有一个,因此orderList1中只有一个元素被删除。

2. Consumer

[java] view plain copy
  1. package java.util.function;  
  2.   
  3. import java.util.Objects;  
  4.   
  5. /** 
  6.  * Represents an operation that accepts a single input argument and returns no 
  7.  * result. Unlike most other functional interfaces, {@code Consumer} is expected 
  8.  * to operate via side-effects. 
  9.  * 
  10.  * <p>This is a <a href="package-summary.html">functional interface</a> 
  11.  * whose functional method is {@link #accept(Object)}. 
  12.  * 
  13.  * @param <T> the type of the input to the operation 
  14.  * 
  15.  * @since 1.8 
  16.  */  
  17. @FunctionalInterface  
  18. public interface Consumer<T> {  
  19.   
  20.     /** 
  21.      * Performs this operation on the given argument. 
  22.      * 
  23.      * @param t the input argument 
  24.      */  
  25.     void accept(T t);  
  26.   
  27.     /** 
  28.      * Returns a composed {@code Consumer} that performs, in sequence, this 
  29.      * operation followed by the {@code after} operation. If performing either 
  30.      * operation throws an exception, it is relayed to the caller of the 
  31.      * composed operation.  If performing this operation throws an exception, 
  32.      * the {@code after} operation will not be performed. 
  33.      * 
  34.      * @param after the operation to perform after this operation 
  35.      * @return a composed {@code Consumer} that performs in sequence this 
  36.      * operation followed by the {@code after} operation 
  37.      * @throws NullPointerException if {@code after} is null 
  38.      */  
  39.     default Consumer<T> andThen(Consumer<? super T> after) {  
  40.         Objects.requireNonNull(after);  
  41.         return (T t) -> { accept(t); after.accept(t); };  
  42.     }  
  43. }  

consumer接口用来表示处理元素的方法。和Predicate方法不同,Predicate只是判断元素是否满足某种条件的函数接口,而Consumer是要对某元素进行操作的函数接口。

accept()方法接受一个参数,不返回结果。我们可以对参数进行处理,当然也可以不处理。

andThen()方法为此接口添加链式处理。

举个简单的例子:

[java] view plain copy
  1. public void run() {  
  2.         List<Order> orderList1 = new ArrayList<Order>();  
  3.         for (int i = 0; i < 6; i++){  
  4.             Order temp = new Order(String.valueOf(i), "man"98 + i);  
  5.             orderList1.add(temp);  
  6.         }  
  7.         Consumer<Order> con = o -> o.setAmount(200);  
  8.         orderList1.forEach(con.andThen(o -> o.setCreatedBy("women")));  
  9.         for (Order order :orderList1){  
  10.             System.out.println(order);  
  11.         }  
  12.     }  
结果:

[java] view plain copy
  1. Order Id:0  Created by:women    Amount:200.0  
  2. Order Id:1  Created by:women    Amount:200.0  
  3. Order Id:2  Created by:women    Amount:200.0  
  4. Order Id:3  Created by:women    Amount:200.0  
  5. Order Id:4  Created by:women    Amount:200.0  
  6. Order Id:5  Created by:women    Amount:200.0  

3. Function

[java] view plain copy
  1. package java.util.function;  
  2.   
  3. import java.util.Objects;  
  4.   
  5. @FunctionalInterface  
  6. public interface Function<T, R> {  
  7.   
  8.     /** 
  9.      * Applies this function to the given argument. 
  10.      * 
  11.      * @param t the function argument 
  12.      * @return the function result 
  13.      */  
  14.     R apply(T t);  
  15.   
  16.     /** 
  17.      * Returns a composed function that first applies the {@code before} 
  18.      * function to its input, and then applies this function to the result. 
  19.      * If evaluation of either function throws an exception, it is relayed to 
  20.      * the caller of the composed function. 
  21.      * 
  22.      * @param <V> the type of input to the {@code before} function, and to the 
  23.      *           composed function 
  24.      * @param before the function to apply before this function is applied 
  25.      * @return a composed function that first applies the {@code before} 
  26.      * function and then applies this function 
  27.      * @throws NullPointerException if before is null 
  28.      * 
  29.      * @see #andThen(Function) 
  30.      */  
  31.     default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {  
  32.         Objects.requireNonNull(before);  
  33.         return (V v) -> apply(before.apply(v));  
  34.     }  
  35.   
  36.     /** 
  37.      * Returns a composed function that first applies this function to 
  38.      * its input, and then applies the {@code after} function to the result. 
  39.      * If evaluation of either function throws an exception, it is relayed to 
  40.      * the caller of the composed function. 
  41.      * 
  42.      * @param <V> the type of output of the {@code after} function, and of the 
  43.      *           composed function 
  44.      * @param after the function to apply after this function is applied 
  45.      * @return a composed function that first applies this function and then 
  46.      * applies the {@code after} function 
  47.      * @throws NullPointerException if after is null 
  48.      * 
  49.      * @see #compose(Function) 
  50.      */  
  51.     default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {  
  52.         Objects.requireNonNull(after);  
  53.         return (T t) -> after.apply(apply(t));  
  54.     }  
  55.   
  56.     /** 
  57.      * Returns a function that always returns its input argument. 
  58.      * 
  59.      * @param <T> the type of the input and output objects to the function 
  60.      * @return a function that always returns its input argument 
  61.      */  
  62.     static <T> Function<T, T> identity() {  
  63.         return t -> t;  
  64.     }  
  65. }  
predicate 仅仅是判断,consumer是修改,那么function就可以理解为映射(或者说可以用来做映射),即将T映射为R。

我们还是来看一个函数接口唯一的抽象方法apply(),接受一个T参数,返回R参数。意思就是可以将T参数做相应的处理,之后返回R参数。

Function函数接口典型应用可以在Stream中找到。Stream中的<R> Stream<R> map(Function<? super T, ? extends R> mapper)方法,接受一个Function接口。在之前的博客可以找到,List可以返回Stream对象,可以用map方法做很多事。例如,转换大小写:

[java] view plain copy
  1. List<String> output = wordList.stream().map(String::toUpperCase).collect(Collectors.toList());  
例如,计算平方根:

[java] view plain copy
  1. List<Integer> nums = Arrays.asList(1234);  
  2. List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());  

再看看Function的其他方法:

compose()方法,用于在当前方法前添加一个方法,并合并两个方法,两个方法之间的参数是必须有因果关系的。例如<V, T>到 <T, R>混合之后,变成<V, R>。

andThen()方法,和compose相反,用于在当前方法后添加一个方法,并合并两个方法,两个方法之间的参数是必须有因果关系的。例如<T, R>到 <R, V>混合之后,变成<T, V>。

identity()方法,返回一个始终返回输入参数的方法。
原创粉丝点击