这几个接口都在 java.util.function
包下的,分别是Consumer
(消费型)、supplier
(供给型)、predicate
(谓词型)、function
(功能性)
下面从具体的应用场景来讲讲这个接口的用法。
Consumer接口
源码:
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); };
}
}
使用Consumer接口的示例
@Test
public void test_Consumer(){
//1. 使用consumer接口实现方法
System.out.println("使用consumer接口实现方法");
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
Stream<String> stream = Stream.of("aaa", "bbb");
stream.forEach(consumer);
System.out.println("*********************");
//2. 使用lambda表达式, Stream的forEach方法需要的入参就是一个consumer接口
System.out.println("使用lambda表达式");
Consumer<String> consumer1 = (s) -> System.out.println(s);//lambda表达式返回的就是一个Consumer接口
stream = Stream.of("aaa", "bbb");
stream.forEach(consumer1);
//更直接的方式
//stream.forEach((s) -> System.out.println(s));
System.out.println("********************");
//3. 使用方法引用,方法引用也是一个consumer
System.out.println("使用方法引用");
Consumer consumer2 = System.out::println;
stream = Stream.of("aaa", "bbb");
stream.forEach(consumer2);
//更直接的方式
//stream.forEach(System.out::println);
System.out.println("********************");
//4. 演示Consumer的andThen方法
Consumer<String> addHello = s -> System.out.println("hello");
Consumer consumer3 = s -> System.out.println(s);
//先执行consumer3定义的accept方法,再执行addHello定义的accept
System.out.println("演示Consumer的andThen方法");
stream = Stream.of("aaa", "bbb");
stream.forEach(consumer3.andThen(addHello));
}
输出:
使用consumer接口实现方法
aaa
bbb
*********************
使用lambda表达式
aaa
bbb
********************
使用方法引用
aaa
bbb
********************
演示Consumer的andThen方法
aaa
hello
bbb
hello
说明:
Consumer
是一个接口,并且只要实现一个accept
方法,就可以作为一个“消费者”输出信息。lambda
表达式、方法引用的返回值都是Consumer
类型,所以,他们能够作为Stream
的forEach
方法的参数,并且输出一个值。
其实除了Stream
的forEach
方法, 我们常见的List
列表的forEach
方法也可以接收一个Consumer
来遍历列表中的每个元素并对其进行Consumer
的accept
方法中定义的操作:
java.lang.Iterable
的forEach
方法源码:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
forEach
的参数是一个Consumer
,从forEach
这个方法的定义来看,现在我们可以理解为“遍历我所包含的所有元素,对每个元素都执行一次action.accept()
所以客户端可以这样使用List
的forEach
:
List<String> list = new ArrayList<>();
list.add("Hello ");
list.add("World!");
list.forEach(s -> System.out.println(s)); // 这里当然也可以用更为简洁的方法引用来改写
## Supplier 接口 #### 源码 > Supplier.java ``` @FunctionalInterface public interface Supplier
/**
* Gets a result.
*
* @return a result
*/
T get();
}
`Supplier`接口是一个供给型的接口,其实,说白了就是一个容器,可以用来存储数据,然后可以供其他方法使用的这么一个接口。至于如何获取数据,交给用户去实现`Supplier`的`get`方法。
#### 使用Supplier接口的示例
@Test
public void test_Supplier() {
//① 使用Supplier接口实现方法,只有一个get方法,无参数,返回一个值
Supplier
@Override
public Integer get() {
//返回一个随机值
return new Random().nextInt();
}
};
System.out.println("获取随机int");
System.out.println(supplier.get());
System.out.println("********************");
//② 使用lambda表达式,
supplier = () -> new Random().nextInt();
System.out.println("使用lambda表达式定义supplier");
System.out.println(supplier.get());
System.out.println("********************");
//③ 使用方法引用
System.out.println("使用方法引用");
Supplier<Double> supplier2 = Math::random;
System.out.println(supplier2.get());
Integer[] integers = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(integers);
Stream<Integer> stream = list.stream();
//返回一个optional对象, optional对象可以持有元素或者null
Optional<Integer> first = stream.filter(i -> i > 4)
.findFirst();
//optional对象有需要Supplier接口的方法
//orElse,如果first中存在数,就返回这个数,如果不存在,就返回传入orElse中的数字
System.out.println("使用optional对象找到大于4的第一个元素并返回,找不到返回-100");
System.out.println(first.orElse(-100));
System.out.println("********************");
//这次找大于100的数字
stream = list.stream();
Optional<Integer> above100 = stream.filter(integer -> integer > 100).findFirst();
Supplier<Integer> supplier3 = () -> new Random().nextInt();
//orElseGet,如果first中存在数,就返回这个数,如果不存在,就返回supplier3返回的值
System.out.println("orElseGet,如果first中存在数,就返回这个数,如果不存在,就返回supplier3返回的值");
System.out.println(above100.orElseGet(supplier3));
}
输出:
获取随机int
-1992653641
使用lambda表达式定义supplier
-1661833099
使用方法引用
0.4916754644996516
使用optional对象找到大于4的第一个元素并返回,找不到返回-100
5
orElseGet,如果first中存在数,就返回这个数,如果不存在,就返回supplier3返回的值
-454437243
说明:
1. `Supplier` 接口可以理解为一个容器,用于装数据的。
2. `Supplier` 接口有一个 `get` 方法,用户重写这个方法以提供返回。
<br/>
#### Supplier接口示例补充:
> CallableLock.java
public class CallableLock
public V lock(Supplier
try {
doLock();
return supplier.get();
}finally {
unLock();
}
}
private boolean doLock(){
System.out.println("Lock!");
return true;
}
private void unLock(){
System.out.println("Unlock!");
}
}
> Processor.java
public class Processor {
public boolean process() {
System.out.println("Processing");
try {
Thread.sleep(10 * 1000);
}catch (Exception e){
e.printStackTrace();
}
return true;
}
}
> LockTest.java
public class LockTest {
@Test
public void lockTest(){
CallableLock<Boolean> callableLock = new CallableLock<>();
Processor processor = new Processor();
callableLock.lock(processor::process);
System.out.println("====================");
callableLock.lock(()->processor.process());
System.out.println("====================");
callableLock.lock(new Supplier<Boolean>() {
@Override
public Boolean get() {
return processor.process();
}
});
System.out.println("====================");
}
}
<br/>
## Predicate 接口
#### 源码
> Predicate.java
@FunctionalInterface
public interface Predicate
/**
* 计算给定的boolean表达式的真假
*
* @param t 入参
* @return {@code true} 根据输入t是否符合test函数中定义的判断逻辑返回true或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.
*/
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.
*/
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.
*/
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)}.
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
说明: 默认实现的`and`、 `negate`、 `or`、`isEqual`方法都返回`Predicate`对象。 用于嵌套的逻辑判断。
#### Predicate接口示例
@Test
public void test_Predicate() {
Integer[] integers = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(integers);
Stream<Integer> stream = list.stream();
// 基本测试, 使用predicate打印所有大于3的数字
Predicate<Integer> predicate = integer -> integer > 3;
System.out.println("使用predicate打印所有大于3的数字");
stream.filter(predicate).forEach((integer)-> System.out.println(integer));
System.out.println("********************");
//默认方法测试,这里只测试and方法, 其他的方法类似
System.out.println("测试and方法, 使用两个predicate之间的and逻辑,打印所有大于3且为偶数的数字");
Predicate<Integer> even = integer -> integer%2 == 0;
stream = list.stream();
stream.filter(predicate.and(even)).forEach(System.out::println);
}
测试结果:
使用predicate打印所有大于3的数字
4
5
测试and方法, 使用两个predicate之间的and逻辑,打印所有大于3且为偶数的数字
说明:
1. `Predicate` 是一个谓词型接口,其实只是起到一个判断作用。
2. `Predicate` 通过实现一个 `test` 方法做判断。
3. `Predicate`有默认实现的逻辑判断方法
<br/>
## Function接口
#### 基本使用
见 [Java8 Function接口(apply compose andThen)](https://www.cnblogs.com/greatLong/articles/11975684.html)
<br/>
#### 链式调用进阶使用
首先定义接口`ProcessUnit`继承`Function`接口并提供`apply`方法的默认实现:
> ProcessUnit.java
public interface ProcessUnit<T, R> extends Function<T, R> {
@Override
default R apply(T t){
return process(t);
}
R process(T t);
}
这里对`apply`方法的默认实现是调用`ProcessUnit`定义的`process`方法,这个方法交给实现`ProcessUnit`的类去实现,从而可以在这里写自己的处理逻辑。在使用的时候可以使用`ProcessUnit`从`Function`接口中继承来的`compose`和`andThen`方法对逻辑处理进行组合。
下面的`AndThen1`、`AndThen2`和`AndThen3`都分别实现了`ProcessUnit`接口,并重写了`process`方法来提供自己的处理逻辑。
> AndThen1.java
public class AndThen1 implements ProcessUnit<Integer, String>{
@Override
public String process(Integer integer) {
integer += 1;
System.out.println("I am in andThen1, the number is " + integer);
String s = String.valueOf(integer);
return s;
}
}
> AndThen2.java
public class AndThen2 implements ProcessUnit<String, String>{
@Override
public String process(String string) {
Integer integer = Integer.parseInt(string) + 1;
System.out.println("I am in andThen2, the number is " + integer);
return String.valueOf(integer);
}
}
> AndThen3.java
public class AndThen3 implements ProcessUnit<String, String>{
@Override
public String process(String string) {
Integer integer = Integer.parseInt(string) + 1;
System.out.println("I am in andThen3, the number is " + integer);
return String.valueOf(integer);
}
}
测试方法:
> test.java
public class test {
Function<Integer, String> function;
@Before
public void prepare(){
System.out.println("Prepare the test ... ");
System.out.println("++++++++++++++++++++++++++++++");
function = new AndThen1().andThen(new AndThen2()).andThen(new AndThen3());
}
@Test
public void testAndThen(){
System.out.println(function.apply(100));
}
@After
public void finish(){
System.out.println("==============================");
System.out.println("finish test");
}
}
在测试类中定义了一个`Function`对象来接收方法调用链实例。
测试结果:
Prepare the test ...
++++++++++++++++++++++++++++++
I am in andThen1, the number is 101
I am in andThen2, the number is 102
I am in andThen3, the number is 103
103
finish test
Process finished with exit code 0
> 参考文章
>> [Java8之Consumer、Supplier、Predicate和Function攻略](https://www.cnblogs.com/SIHAIloveYAN/p/11288064.html)