gpt4 book ai didi

java - 转换 Java 函数式接口(interface)

转载 作者:IT老高 更新时间:2023-10-28 20:20:53 27 4
gpt4 key购买 nike

和往常一样,我浏览了 JDK 8 的源代码,发现了非常有趣的代码:

@Override
default void forEachRemaining(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
forEachRemaining((IntConsumer) action);
}
}

问题是:如何Consumer<? super Integer>可能是一个实例 IntConsumer ?因为它们处于不同的层次结构中。

我已经制作了类似的代码片段来测试转换:

public class InterfaceExample {
public static void main(String[] args) {
IntConsumer intConsumer = i -> { };
Consumer<Integer> a = (Consumer<Integer>) intConsumer;

a.accept(123);
}
}

但它会抛出 ClassCastException :

Exception in thread "main" 
java.lang.ClassCastException:
com.example.InterfaceExample$$Lambda$1/764977973
cannot be cast to
java.util.function.Consumer

您可以在 java.util.Spliterator.OfInt#forEachRemaining(java.util.function.Consumer) 找到此代码

最佳答案

让我们看看下面的代码,你就知道为什么了吗?

class IntegerConsumer implements Consumer<Integer>, IntConsumer {
...
}

任何类都可以实现多接口(interface),一个是Consumer<Integer>也许实现另一个是IntConsumer .有时在我们想适应时发生IntConsumerConsumer<Integer>并保存其原始类型( IntConsumer ),代码如下所示:

class IntConsumerAdapter implements Consumer<Integer>, IntConsumer {

@Override
public void accept(Integer value) {
accept(value.intValue());
}

@Override
public void accept(int value) {
// todo
}
}

注意:是Class Adapter Design Pattern的用法.

那么你可以使用IntConsumerAdapter两者都是 Consumer<Integer>IntConsumer ,例如:

Consumer<? extends Integer> consumer1 = new IntConsumerAdapter();
IntConsumer consumer2 = new IntConsumerAdapter();

Sink.OfIntClass Adapter Design Pattern 的具体用法在 jdk-8 中。Sink.OfInt#accept(Integer) 的缺点很明显 JVM 会抛出一个 NullPointerException当它接受 null值(value),这就是为什么 Sink 是否可见。

189  interface OfInt extends Sink<Integer>, IntConsumer {
190 @Override
191 void accept(int value);
193 @Override
194 default void accept(Integer i) {
195 if (Tripwire.ENABLED)
196 Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
197 accept(i.intValue());
198 }
199 }

I found it why need to cast a Consumer<Integer> to an IntConsumer if pass a consumer like as IntConsumerAdapter?

One reason is when we use a Consumer to accept an int the compiler needs to auto-boxing it to an Integer. And in the method accept(Integer) you need to unbox an Integer to an int manually. In the other words, each accept(Integer) does 2 additional operations for boxing/unboxing. It needs to improve the performance so it does some special checking in the algorithm library.

Another reason is reusing a piece of code. The body of OfInt#forEachRemaining(Consumer) is a good example of applying Adapter Design Pattern for reusing OfInt#forEachRenaming(IntConsumer).

default void forEachRemaining(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
// action's implementation is an example of Class Adapter Design Pattern
// |
forEachRemaining((IntConsumer) action);
}
else {
// method reference expression is an example of Object Adapter Design Pattern
// |
forEachRemaining((IntConsumer) action::accept);
}
}

关于java - 转换 Java 函数式接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44288838/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com