探索Java8:(五)Supplier和Consumer接口的使用
Supplier是函数式编程的另一个接口,与Function、Predicate接口类似,区别在于Supplier不接收任何参数,只返回结果。
Supplier的基本使用
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
使用Supplier也很简单,与Function接口一样,Supplier使用lambda表达式和方法引用来实例化。
public class SupplierTest {
public static void main(String[] args) {
Supplier<String> supplier1 = () ->10;
System.out.println(supplier1.get());
LocalDateTime now = LocalDateTime.now();
Supplier<String> supplier2 =()->now.toString();
//也可以使用Supplier<String> supplier2 = now::toString
System.out.println(supplier2.get());
}
}
指定类型的Supplier
除了Supplie以外,Java8中还提供了BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier。以LongSupplier为例
@FunctionalInterface
public interface LongSupplier {
/**
* Gets a result.
*
* @return a result
*/
long getAsLong();
}
通过源码我们可以看到,LongSupplier相当于是一个指定了返回参数类型的Supplier。建议这种带类型的函数式接口可以结合起来看,可以同时看下LongFunction、LongConsumer、LongPredicate。
public class LongSupplierTest {
public static void main(String[] args) {
LongSupplier supplier1 = () ->1000L;
System.out.println(supplier1.getAsLong());
}
}
自定义Supplier
我们也可以使用@FunctionalInterface
注解来自定义一个Supplier类。
import java.util.Random;
@FunctionalInterface
interface UserSupplier {
User getUser();
}
class User{
private String username;
private String password;
public User(){
this.usename="test";
this.password="test";
}
}
public class CustomSupplierDemo {
public static void main(String[] args) {
UserSupplier s1=User::new;
System.out.println(s1.getUser());
}
}
Consumer的基本使用
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Consumer和Supplier正好相反,Consumer接收一个参数,但不返回任何结果。可以把Consumer看成是消费者,Supplier看成是生产者。Consumer支持复合操作,可以使用andThen()
来连接其他的Consumer完成对同一参数的多次消费。注意:Consumer不返回结果,因此复合消费其实是对传入参数的多次消费,并改变上一次消费的参数。这点要与Function有所区别。
我们举个例子来说明一下:
public class ConsumerTest {
public static void main(String[] args) {
Supplier<String> supplier2 =()->"Hello World!";
Consumer<String> consumer1=c-> System.out.println(c.toLowerCase());
Consumer<String> consumer2=c-> System.out.println(c.toUpperCase());
consumer1.accept(s1.get());
//多次消费操作
consumer1.andThen(consumer2).accept(s1.get());
}
}
hello world!
hello world!
HELLO WORLD!
使用场景
Supplier比较常用的场景是提供一个返回结果。比如从HTTP请求中获取一个值,这个操作可以用Supplier包装起来。虽然Supplier可以返回静态的字符串或者其他对象,但实际开发中这样的业务逻辑不如直接写一个方法进行返回来的简单明了。Supplier真正的用武之地是对一个复杂操作返回结果进行包装。
Consumer的常用场景是对已有数据的处理,比如创建一个对象之后发送到kafka、redis、写入数据库等。
总之,函数式编程应该用在抽象层次高、复用多的场景,而不是单纯业务逻辑的简单使用(反而影响代码的可阅读性)。找到具体场景中的最佳实践才能发挥函数式编程最大优点。