gpt4 book ai didi

java - 鉴于已检查的错误不会在我的程序中抛出,这个未经检查的包装器是否可以接受

转载 作者:行者123 更新时间:2023-12-01 16:30:03 25 4
gpt4 key购买 nike

我正在使用消费者功能接口(interface)的实现,它包装了 lambda 并似乎捕获了任何已检查的异常并抛出运行时未检查的异常。我真的很喜欢这个,因为它清理了我的 lambda,并且我在这样的情况下使用它:在这种情况下,检查的错误永远不会抛出 InterruptedException。这是可以接受的吗?如果不能的话,为什么?以下是接口(interface)实现:

@FunctionalInterface
public interface ThrowingConsumer<T, E extends Throwable> {

void accept(T t) throws E;

static <T, E extends Throwable> Consumer<T> unchecked(ThrowingConsumer<T, E> c){
return t -> {
try{
c.accept(t);
} catch (Throwable e){
throw new RuntimeException();
}
};
}

}

以下是其使用示例之一。为了提供上下文,它从 ConcurrentHashMap 中获取 EntrySet,其中包含一个用户标识符的键和一个 Packet 类型的可选 BlockingArrayQueue 值,用作与每个相应用户通信的方式。在这种情况下,我向每个用户发送一个数据包,让他们知道中继服务器将很快关闭,以便他们有机会在线程中断之前彻底关闭。因为产生它们的线程是 Main 并且已经完成执行,并且中断来自 ShutdownHook,所以似乎不可能发生另一个中断。

public class NetworkThread implements Runnable {

private SecureSocketManager secureSocketManager;
private final int tlsPort;
private final ConcurrentHashMap<String, Optional<BlockingQueue<Packet>>> channelMap;


public NetworkThread(SecureSocketManager secureSocketManager, ConcurrentHashMap<String, Optional<BlockingQueue<Packet>>> channelMap, int tlsPort) {
this.secureSocketManager = secureSocketManager;
this.tlsPort = tlsPort;
this.channelMap = channelMap;
}

public void run() {

ExecutorService clientThreads = Executors.newCachedThreadPool();
// SETUP A SECURESOCKETMANAGER INSTANCE AND ESTABLISH A SERVER SOCKET ON DESIRED PORT

try {
SSLServerSocket sslServerSocket = secureSocketManager.getSslServerSocket(tlsPort);

// BEGIN RECEIVING NEW CONNECTION INSTANCES ON THAT PORT AND LOOP

while (!interrupted()) {

try {
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
clientThreads.execute(new ClientThread(sslSocket, channelMap));

} catch (IOException e) {
e.printStackTrace();
}
}

//------------------------------RELEVANT CODE----------------------------------------------
clientThreads.shutdown();

// There should be no second interrupt so having this unchecked lambda wrapper is acceptable
channelMap.entrySet()
.stream()
.filter(e -> e.getValue().isPresent())
.forEach(ThrowingConsumer.unchecked(e -> e.getValue().get() // WRAPPER USE
.put(new Packet(e.getKey(), "",Type.RELAY_SHUTDOWN, "", "" ))));
if(!clientThreads.awaitTermination(3, TimeUnit.MINUTES))
clientThreads.shutdownNow();

//------------------------------------------------------------------------------------------

} catch (IOException | InterruptedException e) {
clientThreads.shutdownNow();
}


}

}

谢谢

最佳答案

Is this acceptable ...

询问必须接受它的人。 (或者自己决定!)

... and if not why?

如果您必须处理流中的已检查异常,那将是不幸的。但如果你必须这样做,那么你就必须这样做。

但是我对你这样做的方式有一些问题:

  1. 您正在捕获所有异常,而不仅仅是已检查的异常。如果您只是捕获Exception,那就糟糕了。但您也遇到了Error

  2. 您应该包装原始异常。你现在所做的就是把它扔掉。

  3. 您的包装器异常需要一条消息。

<小时/>

我认为这可以解决上述问题,并且是可能的:

@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {

void accept(T t) throws E;

static <TT, EE extends Exception> Consumer<TT> unchecked(ThrowingConsumer<TT, EE> c){
return t -> {
try {
c.accept(t);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;
} else {
throw new RuntimeException("Unexpected exception", e);
}
}
};
}
}
即使这让我感到有点不安,因为您依赖泛型类型安全来确保仅捕获/包装特定的已检查异常及其子类。问题是,如果您使用未经检查的转换等,则可能会违反泛型类型安全性。在这种情况下,可能会导致捕获并包装“错误”的已检查异常。这很好......除非您尝试打开它并将其转换为预期的类型。

理想情况下,您可以使用运行时类型检查来确保仅包装预期异常。但这需要您将已检查的异常 Class 对象传递给 unchecked 方法。

关于java - 鉴于已检查的错误不会在我的程序中抛出,这个未经检查的包装器是否可以接受,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62066190/

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