正确覆盖 CompletableFuture.cancel
Correctly override CompletableFuture.cancel
我注意到,如果在未来调用 thenApply
,则重写 cancel
方法不会生效。派生的未来并不知道原始版本有这样的覆盖这一事实。下面的代码演示了这个问题。
有没有什么方法可以正确覆盖方法而不失去改造未来的可能性?
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args){
CompletableFuture<Object> unmodified = new CompletableFuture<>(){
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
System.out.println("----> cancelling unmodified");
return super.cancel(mayInterruptIfRunning);
}
};
unmodified
.cancel(true);
CompletableFuture<Object> modified = new CompletableFuture<>(){
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
System.out.println("----> cancelling modified");
return super.cancel(mayInterruptIfRunning);
}
};
unmodified
.thenApply(x -> x)
.cancel(true);
System.out.println("----> end");
}
// OUTPUT
// > Task :Main.main()
// ----> cancelling unmodified
// ----> end
}
没有直接的方法做你想做的事,因为 thenApply
returns 一个新的 CompletableFuture
对象。
但是,如果您真的需要这样做,您可以尝试覆盖 CompletableFuture
class 本身。
让我解释一下!
CompletableFuture.thenApply()
方法进一步调用 CompletableFuture
class 的 uniApplyStage
私有方法,其中创建 new CompletableFuture()
实例以返回。 (我反编译了 Java 源代码来检查这一点。)
您不能覆盖此方法,因为它是私有方法。但是,如果你;
- 反编译 class
CompletableFuture
- 复制代码。
- 在
new CompletableFuture<V>()
创建实例时将 uniApplyStage
方法更改为 @Override
cancel
方法。
- 然后在运行时,按照 中提到的步骤使用 "Custom ClassLoader".
在运行时重新加载您的 class
理论上,你应该能够做到这一切。
当然,问题仍然存在。你有多拼命想要完成这件事? :D
老实说,将这个答案视为最后的手段。
您需要 Java 9 或更高版本。然后,所有创建新的依赖 future 的方法都将调用工厂方法 newIncompleteFuture()
,您可以覆盖它:
public static void main(String arg[]) {
class MyFuture<T> extends CompletableFuture<T> {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
System.out.println("customized cancel");
return super.cancel(mayInterruptIfRunning);
}
@Override
public <U> CompletableFuture<U> newIncompleteFuture() {
return new MyFuture<>();
}
}
MyFuture<Object> future = new MyFuture<>();
System.out.print("direct: ");
future.cancel(true);
System.out.print("indirect: ");
future.thenApply(x -> x).cancel(true);
System.out.print("even longer chain: ");
future.thenApply(x -> x).exceptionally(t -> null).cancel(true);
System.out.println("end");
}
direct: customized cancel
indirect: customized cancel
even longer chain: customized cancel
end
但请记住,对于 CompletableFuture
,取消与 CancellationException
的异常完成没有什么不同。所以,有人可以调用 completeExceptionally(new CancellationException())
而不是 cancel(...)
,达到同样的效果。
我注意到,如果在未来调用 thenApply
,则重写 cancel
方法不会生效。派生的未来并不知道原始版本有这样的覆盖这一事实。下面的代码演示了这个问题。
有没有什么方法可以正确覆盖方法而不失去改造未来的可能性?
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args){
CompletableFuture<Object> unmodified = new CompletableFuture<>(){
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
System.out.println("----> cancelling unmodified");
return super.cancel(mayInterruptIfRunning);
}
};
unmodified
.cancel(true);
CompletableFuture<Object> modified = new CompletableFuture<>(){
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
System.out.println("----> cancelling modified");
return super.cancel(mayInterruptIfRunning);
}
};
unmodified
.thenApply(x -> x)
.cancel(true);
System.out.println("----> end");
}
// OUTPUT
// > Task :Main.main()
// ----> cancelling unmodified
// ----> end
}
没有直接的方法做你想做的事,因为 thenApply
returns 一个新的 CompletableFuture
对象。
但是,如果您真的需要这样做,您可以尝试覆盖 CompletableFuture
class 本身。
让我解释一下!
CompletableFuture.thenApply()
方法进一步调用 CompletableFuture
class 的 uniApplyStage
私有方法,其中创建 new CompletableFuture()
实例以返回。 (我反编译了 Java 源代码来检查这一点。)
您不能覆盖此方法,因为它是私有方法。但是,如果你;
- 反编译 class
CompletableFuture
- 复制代码。
- 在
new CompletableFuture<V>()
创建实例时将uniApplyStage
方法更改为@Override
cancel
方法。 - 然后在运行时,按照 中提到的步骤使用 "Custom ClassLoader". 在运行时重新加载您的 class
理论上,你应该能够做到这一切。
当然,问题仍然存在。你有多拼命想要完成这件事? :D
老实说,将这个答案视为最后的手段。
您需要 Java 9 或更高版本。然后,所有创建新的依赖 future 的方法都将调用工厂方法 newIncompleteFuture()
,您可以覆盖它:
public static void main(String arg[]) {
class MyFuture<T> extends CompletableFuture<T> {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
System.out.println("customized cancel");
return super.cancel(mayInterruptIfRunning);
}
@Override
public <U> CompletableFuture<U> newIncompleteFuture() {
return new MyFuture<>();
}
}
MyFuture<Object> future = new MyFuture<>();
System.out.print("direct: ");
future.cancel(true);
System.out.print("indirect: ");
future.thenApply(x -> x).cancel(true);
System.out.print("even longer chain: ");
future.thenApply(x -> x).exceptionally(t -> null).cancel(true);
System.out.println("end");
}
direct: customized cancel
indirect: customized cancel
even longer chain: customized cancel
end
但请记住,对于 CompletableFuture
,取消与 CancellationException
的异常完成没有什么不同。所以,有人可以调用 completeExceptionally(new CancellationException())
而不是 cancel(...)
,达到同样的效果。