Java 数据结构 -- 03.Java 8 数据结构中的行为接口

书接上文,上一篇对 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 流式处理类做简单的介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值