[英]Handling Java exceptions caught in constructors, with final members
我有一些丑陋的代碼,想重構它:
public class UdpTransport extends AbstractLayer<byte[]> {
private final DatagramSocket socket;
private final InetAddress address;
private final int port;
/* boolean dead is provided by superclass */
public UdpTransport(String host, int port) {
this.port = port;
InetAddress tmp_address = null;
try {
tmp_address = InetAddress.getByName(host);
} catch (UnknownHostException e) {
e.printStackTrace();
dead = true;
socket = null;
address = null;
return;
}
address = tmp_address;
DatagramSocket tmp_socket = null;
try {
tmp_socket = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
dead = true;
socket = null;
return;
}
socket = tmp_socket;
}
...
導致丑陋的問題是final
成員與捕獲的異常之間的交互。 如果可能的話,我想讓成員保持final
。
我想按以下方式編寫代碼,但是Java編譯器無法分析控制流-無法對address
進行第二次分配,因為必須進行第一次嘗試分配才能使控制到達catch
子句。
public UdpTransport(String host, int port) {
this.port = port;
try {
address = InetAddress.getByName(host);
} catch (UnknownHostException e) {
e.printStackTrace();
dead = true;
address = null; // can only have reached here if exception was thrown
socket = null;
return;
}
...
Error:(27, 13) error: variable address might already have been assigned
有什么建議嗎?
PS我有一個約束,那就是構造函數不要拋出-否則這一切都將很容易。
讓構造函數拋出異常。 如果構造函數未正常終止,則將final
保留為undefined是可以的,因為在這種情況下,不會返回任何對象。
代碼中最丑陋的部分是在構造函數中捕獲異常,然后返回現有的但無效的實例。
如果您可以自由使用私有構造函數,則可以將構造函數隱藏在公共靜態工廠方法后面,該方法可以返回UdpTransport
類的不同實例。 比方說:
public final class UdpTransport
extends AbstractLayer<byte[]> {
private final DatagramSocket socket;
private final InetAddress address;
private final int port;
/* boolean dead is provided by superclass */
private UdpTransport(final boolean dead, final DatagramSocket socket, final InetAddress address, final int port) {
super(dead);
this.socket = socket;
this.address = address;
this.port = port;
}
public static UdpTransport createUdpTransport(final String host, final int port) {
try {
return new UdpTransport(false, new DatagramSocket(), getByName(host), port);
} catch ( final SocketException | UnknownHostException ex ) {
ex.printStackTrace();
return new UdpTransport(true, null, null, port);
}
}
}
上面的解決方案可能有以下注意事項:
final
字段。 這與我記得在C#中可能稱為Scala的主要構造函數非常相似。 UdpTransport
實例化的復雜性。 socket
和address
設置為真實實例,或者將它們設置為null
表示無效狀態。 因此,此實例狀態可能與問題中的代碼所產生的狀態略有不同。 public static AbstractLayer<byte[]> createUdpTransport(final String host, final int port)
(請注意返回類型)。 這種方法的強大之處在於,如果可能的話,您可以根據需要用任何子類替換返回的值,除非您使用特定於UdpTransport
公共接口。 -1
可以表示無效的端口值,或者如果您認為無效,則可以為Integer
)可以自由更改類的字段,並且原始包裝器不受您的限制): private static final AbstractLayer<byte[]> deadUdpTransport = new UdpTransport(true, null, null, -1);
...
public static AbstractLayer<byte[]> createUdpTransport(final String host, final int port) {
try {
return new UdpTransport(false, new DatagramSocket(), getByName(host), port);
} catch ( final SocketException | UnknownHostException ex ) {
ex.printStackTrace();
return deadUdpTransport; // it's safe unless UdpTransport is immutable
}
構造函數的兩個版本,您的屬性保持最終狀態。 請注意,我不認為您的原始方法通常是“丑陋的”。 但是,由於try-catch-block對於兩個異常都是相同的,因此可以進行改進。 這成為我的構造函數#1。
public UdpTransport(String host, int port) {
InetAddress byName;
DatagramSocket datagramSocket;
try {
byName = InetAddress.getByName(host);
datagramSocket = new DatagramSocket();
} catch (UnknownHostException | SocketException e) {
e.printStackTrace();
dead = true;
datagramSocket = null;
byName = null;
}
this.port = port;
this.socket = datagramSocket;
this.address = byName;
}
public UdpTransport(int port, String host) {
this.port = port;
this.socket = createSocket();
this.address = findAddress(host);
}
private DatagramSocket createSocket() {
DatagramSocket result;
try {
result = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
this.dead = true;
result = null;
}
return result;
}
private InetAddress findAddress(String host) {
InetAddress result;
try {
result = InetAddress.getByName(host);
} catch (UnknownHostException e) {
e.printStackTrace();
this.dead = true;
result = null;
}
return result;
}
此構造函數根本沒有理由捕獲異常。 充滿null
值的對象對應用程序毫無用處。 構造函數應該拋出該異常。 沒有抓住它。
像這樣的事情呢:
public class UdpTransport extends AbstractLayer<byte[]> {
private final DatagramSocket socket;
private final InetAddress address;
private final int port;
public static UdpTransport create(String host, int port) {
InetAddress address = null;
DatagramSocket socket = null;
try {
address = InetAddress.getByName(host);
socket = new DatagramSocket();
} catch (UnknownHostException | SocketException e) {
e.printStackTrace();
}
return new UdpTransport(socket, address, port);
}
private UdpTransport(DatagramSocket socket, InetAddress address, int port) {
this.port = port;
this.address = address;
this.socket = socket;
if(address == null || socket == null) {
dead = true;
}
}
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.