书接上文,上一篇对 Java 8 的新特性做了简单的介绍,由于这些接口大多是独立于数据结构架构之外,是 Java 8 中新增的,而 Java 8 的数据结构中有多处使用这些接口的新方法,并且 Java 8 提供的重要更新-- 流式处理类 Stream 中大量方法使用了行为接口参数,所以在阅读数据结构的源码之前,先来对这些接口做一下简单的了解。
Consumer
消费行为接口,以下是 Consumer 接口的源码
/**有些接口上会显示的添加 @FuntionalInterface 注解来声明它是一个函数式接口,Consumer 就是这样的,抽象方法接收一个范型参数,无返回值**/
@FunctionalInterface
public interface Consumer<T> {
/**对接收到的范型参数进行一系列操作,没有返回值**/
void accept(T t);
/**链式操作范型参数**/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
接口的主要方法void accept(T t)
很简单,无需赘述,这里直接上使用方式:
public class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> consumer = str ->
System.out.println("This is consumer: " + str);
consumer.accept("This is a demo");
}
}
默认方法 default Consumer<T> andThen(Consumer<? super T> after)
传入一个 Consumer 参数,返回一个新的 Consumer,在实现时参数先执行前一个消费方法,再执行后一个消费方法,用于链式调用,使用方式如下:
public class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> consumer = str ->
System.out.println("This is first consumer: " + str);
Consumer<String> consumer2 = str ->
System.out.println("This is second consumer: " + str);
consumer.andThen(consumer2).accept("This is a demo");
}
}
Sink
/**Sink 是一个特殊的能力接口,它首次出现在流失处理--管道抽象类 PipelineHelper 中,它继承自 Consumer,其中定义的方法都是默认方法,并且没有默认实现 accept 无参数方法,所以它和 Consumer 一样,只有一个 accept 抽象方法,意味着 Sink 也是一个行为接口**/
interface Sink<T> extends Consumer<T> {
/**重置一个 sink,需要在向 sink 中发送任何数据之前调用,或者在调用 Sink#end() 方法之后调用,接收一个 long 参数,该参数与发送数据的个数相关,若知道确切个数,传入个数值,否则传入 -1**/
default void begin(long size) {}
/**示意一个 sink 中的所有元素都被推送了,如果这个 sink 是状态相关的(这里首次提到了状态相关概念,将在流式处理篇中详细分析),它需要把这些状态发送出去,然后清楚所有状态**/
default void end() {}
/**示意一个 sink 不希望再接收任何数据了,返回 false**/
default boolean cancellationRequested() {
return false;
}
/**接收一个 int 类型的数据,该方法必须被实现类重写,否则会抛出异常**/
default void accept(int value) {
throw new IllegalStateException("called wrong accept method");
}
/**接收一个 long 类型的数据,该方法必须被实现类重写,否则会抛出异常**/
default void accept(long value) {
throw new IllegalStateException("called wrong accept method");
}
/**接收一个 double 类型的数据,该方法必须被实现类重写,否则会抛出异常**/
default void accept(double value) {
throw new IllegalStateException("called wrong accept method");
}
/**Java 8 对 int 类型操作的增强,实现 IntConsumer 使其具有链式调用的能力**/
interface OfInt extends Sink<Integer>, IntConsumer {
@Override
void accept(int value);
@Override
default void accept(Integer i) {
/**Tripwire 是 Java 8 中加入的一个工具类,用来检测是否有无意的装箱操作,这个检测的打开与关闭是通过系统参数来设定的,在生产环境中通常调节为关闭**/
if (Tripwire.ENABLED)
Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
accept(i.intValue());
}
}
/**Java 8 对 double 类型操作的增强**/
interface OfLong extends Sink<Long>, LongConsumer {
@Override
void accept(long value);
@Override
default void accept(Long i) {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(), "{0} calling Sink.OfLong.accept(Long)");
accept(i.longValue());
}
}
/**Java 8 对 long 类型操作的增强**/
interface OfDouble extends Sink<Double>, DoubleConsumer {
@Override
void accept(double value);
@Override
default void accept(Double i) {
if (Tripwire.ENABLED)
Tripwire.trip(getClass(), "{0} calling Sink.OfDouble.accept(Double)");
accept(i.doubleValue());
}
}
/**这里使用装饰器模式扩展 Sink 接口**/
static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
protected final Sink<? super E_OUT> downstream;
public ChainedReference(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream);
}
@Override
public void begin(long size) {
downstream.begin(size);
}
@Override
public void end() {
downstream.end();
}
@Override
public boolean cancellationRequested() {
return downstream.cancellationRequested();
}
}
/**Java 8 对 int 类型做的增强**/
static abstract class ChainedInt<E_OUT> implements Sink.OfInt {
protected final Sink<? super E_OUT> downstream;
public ChainedInt(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream);
}
@Override
public void begin(long size) {
downstream.begin(size);
}
@Override
public void end() {
downstream.end();
}
@Override
public boolean cancellationRequested() {
return downstream.cancellationRequested();
}
}
/**Java 8 对 long 类型做的增强**/
static abstract class ChainedLong<E_OUT> implements Sink.OfLong {
protected final Sink<? super E_OUT> downstream;
public ChainedLong(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream);
}
@Override
public void begin(long size) {
downstream.begin(size);
}
@Override
public void end() {
downstream.end();
}
@Override
public boolean cancellationRequested() {
return downstream.cancellationRequested();
}
}
/**Java 8 对 double 类型做的增强**/
static abstract class ChainedDouble<E_OUT> implements Sink.OfDouble {
protected final Sink<? super E_OUT> downstream;
public ChainedDouble(Sink<? super E_OUT> downstream) {
this.downstream = Objects.requireNonNull(downstream);
}
@Override
public void begin(long size) {
downstream.begin(size);
}
@Override
public void end() {
downstream.end();
}
@Override
public boolean cancellationRequested() {
return downstream.cancellationRequested();
}
}
}
Supplier
供应行为接口,首次出现在流式处理-管道准则类 AbstractPipeline 中,AbstractPipeline 将在流式处理篇中进行分析,以下是 Supplier 接口的源码
@FunctionalInterface
public interface Supplier<T> {
/**返回一个对象**/
T get();
}
Predicate
官方的称呼为谓词,我称它为断言行为接口,以下是 Predicate 接口的源码
/**JDK 1.8 断言接口,函数式接口,与 Consumer 接口类似,传入一个范型参数与实现方法**/
@FunctionalInterface
public interface Predicate<T> {
/**函数式接口唯一抽象方法,传入一个范型参数与判断实现,返回 boolean 值**/
boolean test(T t);
/**&& 操作方法**/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**!操作方法**/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**|| 操作方法**/
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
/**equals 操作方法**/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
接口的主要方法 boolean test(T t)
接收一个范型参数,返回一个 boolean 值,可以认为这是一个断言方法,需要传入对该范型参数验证的实现,以下是使用实例:
public class PredicateDemo {
public static void main(String[] args) {
Predicate<Integer> predicate = i -> i > 0;
predicate.test(5);
}
}
三个默认方法主要对应逻辑运算符 &&、||、!,传入一个 Predicate 参数,在实现时返回前一个参数的与后一个参数的逻辑运算结果。提供这些方法是为了增强程序的可读性,使用方式如下:
public class PredicateDemo {
public static void main(String[] args) {
Predicate<Integer> predicate1 = i -> i > 0;
Predicate<Integer> predicate2 = i -> i % 2 == 0;
predicate1.and(predicate2).test(5);
}
}
静态方法 static <T> Predicate<T> isEqual(Object targetRef)
主要是封装了 obj1 != null 与 obj1.equals(obj2) 方法
Function
函数接口(你没有看做,它就叫这个名)。。我称它为函数行为接口,一些是 Function 接口的源码
/**Function 函数行为接口**/
@FunctionalInterface
public interface Function<T, R> {
/**主要方法,接受第一范型与该范型的操作方法,返回第二范型**/
R apply(T t);
/**接受一个 Function 参数,先执行参数的 apply 方法,然后再执行接受这个 apply 方法返回值的 apply 方法(执行顺序从左到右)**/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**接受一个 Function 参数,先执行 apply 方法,然后再执行接受这个 apply 方法返回值的参数的 apply 方法(执行顺序从右到左)**/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**静态实现 identity 方法,返回一个与自己相同的 Lambda 表达式对象,在某些需要传入参数但必须以 Lambda 表达式的时候使用**/
static <T> Function<T, T> identity() {
return t -> t;
}
}
主要方法 R apply(T t)
接收一个范型参数,返回另一个类型的结果,使用方式如下:
public class FunctionDemo {
public static void main(String[] args) {
Function<Integer, String> function = a -> a.toString();
function.apply(5);
}
}
默认方法 default <V> Function<V, R> compose(Function<? super V, ? extends T> before)
接收一个 Function 参数,调用时先执行这个 Function 参数对于范型参数的操作,再执行调用 compose 方法的 Function 对于前一个结果的操作,使用方式如下:
public class FunctionDemo {
public static void main(String[] args) {
Function<Transportation, Weight> function1 = a -> a.getWeight(a);
Function<Param, Vehicle> function2 = b -> b.findVehicle(b);
/**使用的时候要注意 function1 与 function2 的范型参数类型直接的关系,有一点绕**/
function2.compose(function1).apply(new Vehicle());
}
}
/**公共交通类*/
class Transportation {
/**根据公共交通实现类获取重量方法**/
Weight getWeight(Transportation t) {
return new Weight();
}
}
/**汽车类,公共交通子类**/
class Vehicle extends Transportation {}
/**参数类**/
class Param {
/**根据重量参数朝着公共汽车方法**/
Vehicle findVehicle(Param p) {
return new Vehicle();
}
}
/**重量类,参数类子类**/
class Weight extends Param {}
默认方法default <V> Function<T, V> andThen(Function<? super R, ? extends V> after)
与 compose 方法类似,只是 function1 与 function2 对参数的操作顺序倒了过来,使用方式如下:
/**只需要修改上述代码中 function1 与 function2 的位置,其它与上述代码相同,实际项目中对换两个操作方法的顺序可能会得到不同的结果**/
public static void main(String[] args) {
Function<Transportation, Weight> function1 = a -> a.getWeight(a);
Function<Param, Vehicle> function2 = b -> b.findVehicle(b);
function1.andThen(function2).apply(new Vehicle());
}
静态方法 static <T> Function<T, T> identity()
返回一个与自身范型类型相同的,Function 类型对象,在调用 apply 的时候返回自己,看上去很鸡肋,但是在某些时候是很有用的,比如工具类 Collectors 的 toMap 方法 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)
要求传入两个 Function 类型参数,而实现只需要将将第一个修改第一参数的实现,第二个参数保持不变的时候,就需要这样实现:toMap(firstOpertions which returns Function, a -> a)
,而此时,使用 Function.identity 方法就可以将代码优化成 toMap(firstOpertions which returns Function, identity())
,提高代码的可读性。
BiFunction
BiFunction 是对 Function 接口的一个增强,源码如下:
/**Function 接口增强接口**/
@FunctionalInterface
public interface BiFunction<T, U, R> {
/**接收两个范型对象,返回第三个范型结果**/
R apply(T t, U u);
/**接收一个 Function 对象作为参数,首先应用前一个 Function 对象的 apply 方法,然后再对这个 apply 方法返回值进行后一个 BiFunction 的 apply 操作**/
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
有了前面对 Function 接口的了解,这个 BiFunction 就好理解多了,使用方式如下
public class BiFunctionDemo {
public static void main(String[] args) {
BiFunction<BiTransportation, BiParam, BiSubDescription> biFunction = (a, b) -> new BiSubDescription(a, b);
Function<BiDescription, BiDescription> function = a -> a;
/**没有什么特别的,同样要注意 BiFunction 与 Function 的范型关系**/
biFunction.andThen(function).apply(new BiVehicle(), new BiWeight());
}
}
/**公共交通类*/
class BiTransportation {
/**根据公共交通实现类获取重量方法**/
BiWeight getWeight(BiTransportation t) {
return new BiWeight();
}
}
/**汽车类,公共交通子类**/
class BiVehicle extends BiTransportation {}
/**参数类**/
class BiParam {
/**根据重量参数朝着公共汽车方法**/
BiVehicle findVehicle(BiParam p) {
return new BiVehicle();
}
}
/**重量类,参数类子类**/
class BiWeight extends BiParam {}
/**描述类**/
class BiDescription {
public BiDescription(BiTransportation t, BiParam p) {}
}
/**描述类子类**/
class BiSubDescription extends BiDescription {
public BiSubDescription(BiTransportation t, BiParam p){
super(t, p);
}
}
总结:通过这些业界最佳实现的行为接口我们可以发现一个共同点,就是这些函数式接口的默认方法通常是返回一个自己类型的对象,这些对象通常是用来做流式或者逻辑操作的,而它们的抽象方法则类似于一个执行信号,在调用时候是放在调用链的最后一环。
以上就是在 Java 8 的数据结构新增方法与流式处理类 Stream 中用到的行为接口,下一篇将对 Java 8 流式处理类做简单的介绍。