Java8 Consumer、Supplier、Predicate、Function
这几个接口都在 java.util.function
包下的,分别是Consumer
(消费型)、supplier
(供给型)、predicate
(谓词型)、function
(功能性)
下面从具体的应用场景来讲讲这个接口的用法。
1. Consumer接口
1.1 源码
源码:Consumer.java
/**
* 代表这样一种操作: 接收一个单值输入,没有返回值。与大部分函数式接口不同,
* Consumer一般通过"副作用"来操作。
* Consumer 的函数式方法是accept
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* 这个默认方法与Function接口中的andThen方法类似,对于给定的入参after(类型也是Consumer),
* 先执行上面的accept方法,再执行after中的accept方法。
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
1.2 说明
Consumer
是一个接口,并且只要实现一个accept
方法,就可以作为一个**“消费者”**输出信息。lambda
表达式、方法引用的返回值都是Consumer
类型,所以,他们能够作为Stream
的forEach
方法的参数,并且输出一个值。
1.3 示例
public class ConsumerDemo {
public static void main(String[] args) {
/* ------------- 1. 使用Consumer接口实现方法 ------------- */
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
// Stream的forEach方法需要的入参是一个consumer接口
Stream<String> stream = Stream.of("aaa", "bbb");
stream.forEach(consumer);
/* ------------- 2. 使用Lambda表达式 ------------------ */
/* ------------- Lambda表达式返回的就是一个Consumer接口 */
Consumer<String> consumer2 = (s) -> {
System.out.println(s);
};
Stream.of("ccc", "ddd").forEach(consumer2);
// 更直接的方式
Stream.of("ccc", "ddd").forEach((s) -> System.out.println(s));
/* ------------- 3. 使用方法引用,方法引用也是一个Consumer ------------------ */
Consumer consumer3 = System.out::println;
Stream.of("eee", "fff").forEach(consumer3);
// 更直接的方式
Stream.of("eee", "fff").forEach(System.out::println);
/* ------------- 4. 演示Consumer的andThen方法 ------------------ */
Consumer<String> addHello = s -> System.out.println("Hello");
Consumer consumer4 = s -> System.out.println(s);
// 先执行 consumer4 定义的accept方法,再执行addHello定义的accept方法
Stream.of("ggg", "hhh").forEach(consumer4.andThen(addHello));
}
}
输出
------------- 1. 使用Consumer接口实现方法 -------------
aaa
bbb
------------- 2. 使用Lambda表达式 ------------------
ccc
ddd
------------- 3. 使用方法引用,方法引用也是一个Consumer ------------------
eee
fff
------------- 4. 演示Consumer的andThen方法 ------------------
ggg
Hello
hhh
Hello
其实除了 Stream
的 forEach
方法,我们常见的 List
列表的 forEach
方法也可以接收一个 Consumer
来遍历列表中的每个元素并对其进行 Consumer
的 accept
方法中定义的操作:
java.lang.Iterable
的 forEach
方法源码:
Copydefault void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
forEach
的参数是一个 Consumer
,从 forEach
这个方法的定义来看,现在我们可以理解为:遍历我所包含的所有元素,对每个元素都执行一次action.accept()
所以客户端可以这样使用 List
的 forEach
:
CopyList<String> list = new ArrayList<>();
list.add("Hello ");
list.add("World!");
list.forEach(s -> System.out.println(s));
// 这里当然也可以用更为简洁的方法引用来改写
2. Supplier接口
2.1 源码
源码:Supplier.java
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
2.2 说明
Supplier
接口可以理解为一个容器,用于装数据的。
Supplier
接口有一个 get()
方法,用户重写这个方法以提供返回。
2.3 示例
/**
* Supplier接口示例
*
* @author smilelingyong@163.com
* @since 2022-10-16
*/
public class SupplierDemo {
public static void main(String[] args) {
/* ---- 1. 使用Supplier接口实现方法,只有一个get()方法,无参数,返回一个值 --- */
System.out.println("------------- 1. 使用Supplier接口实现方法 -------------");
Supplier supplier = new Supplier() {
@Override
public Object get() {
// 返回一个随机值
return new Random().nextInt();
}
};
System.out.println("获取随机int数值:" + supplier.get());
/* ------------- 2. 使用Lambda表达式 ------------- */
System.out.println("------------- 2. 使用Lambda表达式 -------------");
supplier = () -> new Random().nextInt();
System.out.println("获取随机int数值:" + supplier.get());
/* ------------- 3. 使用方法引用 ------------- */
System.out.println("------------- 3. 使用方法引用 -------------");
Supplier<Double> supplier3 = Math::random;
System.out.println(supplier3.get());
// 举例1: 使用optional对象找到大于4的第一个元素并返回,找不到返回-100
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
// 返回一个Optional对象,Optional对象可以持有元素或者NULL
Optional<Integer> first = list.stream().filter(i -> i > 4).findFirst();
// Optional对象有需要Supplier接口的方法
System.out.println("使用optional对象找到大于4的第一个元素并返回,找不到返回-100");
System.out.println(first.orElse(-100));
// 举例2: 使用optional对象找到大于100的第一个元素并返回,找不到返回supplier4返回值
Supplier<Integer> supplier4 = () -> new Random().nextInt();
System.out.println("使用optional对象找到大于100的第一个元素并返回,找不到返回supplier4返回值");
System.out.println(list.stream().filter(i -> i > 100).findFirst().orElseGet(supplier4));
}
}
结果
------------- 1. 使用Supplier接口实现方法 -------------
获取随机int数值:1688503501
------------- 2. 使用Lambda表达式 -------------
获取随机int数值:227818781
------------- 3. 使用方法引用 -------------
0.5704019933873828
使用optional对象找到大于4的第一个元素并返回,找不到返回-100
5
使用optional对象找到大于100的第一个元素并返回,找不到返回supplier4返回值
-1779415818
3. Predicate接口
3.1 源码
源码:Predicate.java
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
/**
* 下面在接口中默认实现的and方法、negate方法、or方法、isEqual方法,可以实现嵌套判断。and方法提供逻辑与功能,具有短路效应
* Returns a composed predicate that represents a short-circuiting logical
* AND of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code false}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* negate方法提供逻辑非功能
* Returns a predicate that represents the logical negation of this
* predicate.
*
* @return a predicate that represents the logical negation of this
* predicate
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* or方法提供逻辑或功能,具有短路效应
* Returns a composed predicate that represents a short-circuiting logical
* OR of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
/**
* isEqual方法提供逻辑相等判断
* Returns a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return a predicate that tests if two arguments are equal according
* to {@link Objects#equals(Object, Object)}
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
3.2 说明
Predicate
是一个谓词型接口,其实,这个就是一个类似于 bool 类型的判断的接口。
Predicate
通过实现一个 test
方法做判断。
Predicate
有默认实现的逻辑判断方法
3.3 示例
/**
* Predicate接口示例
*
* @author smilelingyong@163.com
* @since 2022-10-17
*/
public class PredicateDemo {
public static void main(String[] args) {
/* ------------- 1. Lambda表达式,使用Predicate ------------- */
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Predicate<Integer> predicate = i -> i > 3;
System.out.println("使用Predicate打印所有大于3的数字");
list.stream().filter(predicate).forEach(System.out::println);
/* ------------- 2. 默认方法测试,这里只测试and()方法,其他的方法类似 - */
System.out.println("测试and方法, 使用两个predicate之间的and逻辑,打印所有大于3且为偶数的数字");
Predicate<Integer> predicate2 = i -> i % 2 == 0;
list.stream().filter(predicate.and(predicate2)).forEach(System.out::println);
}
}
结果
使用Predicate打印所有大于3的数字
4
5
测试and方法, 使用两个predicate之间的and逻辑,打印所有大于3且为偶数的数字
4
4. Function接口
4.1 源码
源码:Function.java
/**
* Represents a function that accepts one argument and produces a result.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object)}.
*
* @param <T> the type of the input to the function
* @param <R> the type of the result of the function
*
* @since 1.8
*/
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies this function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of input to the {@code before} function, and to the
* composed function
* @param before the function to apply before this function is applied
* @return a composed function that first applies the {@code before}
* function and then applies this function
* @throws NullPointerException if before is null
*
* @see #andThen(Function)
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* Returns a composed function that first applies this function to
* its input, and then applies the {@code after} function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of output of the {@code after} function, and of the
* composed function
* @param after the function to apply after this function is applied
* @return a composed function that first applies this function and then
* applies the {@code after} function
* @throws NullPointerException if after is null
*
* @see #compose(Function)
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* Returns a function that always returns its input argument.
*
* @param <T> the type of the input and output objects to the function
* @return a function that always returns its input argument
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}
4.2 说明
Function
接口是一个功能型接口,它的一个作用就是转换作用,将输入数据转换成另一种形式的输出数据。
Function
接口实现 apply()
方法来做转换。
4.3 示例
/**
* Function接口示例
*
* @author smilelingyong@163.com
* @since 2022-10-17
*/
public class FunctionDemo {
public static void main(String[] args) {
/* ------------- Function作用是转换,将一个值转换为另外一个值 ------------- */
// 使用map方法,泛型的第一个参数(输入参数)是转换前的类型,第二个(输出参数)是转化后的类型
Function<String, Integer> function = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return s.length();
}
};
Stream<String> stream = Stream.of("aaa", "bbb", "ccccc");
Stream<Integer> stream2 = stream.map(function);
stream2.forEach(System.out::println);
/**
* 除了上面使用的 Function 接口,还可以使用下面这些 Function 接口。
* IntFunction 、DoubleFunction 、LongFunction 、ToIntFunction 、
* ToDoubleFunction 、DoubleToIntFunction 等等,使用方法和上面一样。
*/
}
}
输出
3
3
5
Reference
- https://www.cnblogs.com/greatLong/p/11976821.html
- https://www.cnblogs.com/SIHAIloveYAN/p/11288064.html