想必很多人對(duì)JAVA中的Exception不會(huì)陌生,但是我們也會(huì)碰到諸多的Checked Exception匣椰。而我們又不想一層層去捕獲隐圾,那么就需要想辦法來(lái)忽略這些Checked Exception。
那么何為Checked Exception, 何為Unchecked Exception蛀缝。
正如上圖中所示:
- Checked Exception: 指的是不能恢復(fù),必須要被使用者來(lái)處理的一類異常目代,如果不捕獲屈梁,那么編譯會(huì)報(bào)錯(cuò)嗤练。例如,IOException在讶。
- Unchecked Exception: 指的是在運(yùn)行時(shí)才會(huì)導(dǎo)致程序奔潰的異常煞抬,編譯時(shí)候并不會(huì)報(bào)錯(cuò)。例如构哺,Runtime Exception革答。
如果在代碼中處處來(lái)處理Checked Exception,那么代碼就會(huì)變成冗長(zhǎng)并且可讀性變差曙强,所以在某些情況下需要對(duì)其進(jìn)行處理残拐,變成Unchecked Exception。
1. try catch
最簡(jiǎn)單的方案之一就是使用try catch然后在捕獲到checked exception之后拋出Unchecked Exception碟嘴。
例如:
public DbConnection getDbConnection(String username, String password) {
try {
return new DbProvider().getConnect(username, password);
} catch (IOException e) {
throw new RuntimeException();
}
}
這樣的處理邏輯到處都會(huì)用到溪食,代碼也會(huì)顯得冗長(zhǎng),降低了可讀性娜扇。
2. 一個(gè)通用的Wrapper
可以嘗試著寫一個(gè)通用的Wrapper错沃,統(tǒng)一處理類似的Checked Exception。
-
我們需要把上述代碼中的
new DbProvider().getConnect(username, password);
包裝成一個(gè)通用的接口RuntimeExceptionWrappable
:public interface RuntimeExceptionWrappable<T> {
T execute() throws IOException;
} -
接下來(lái)可以替換原有代碼中的
new DbProvider().getConnect(username, password);
:RuntimeExceptionWrappable<DbConnection> wrappable = new RuntimeExceptionWrappable<DbConnection>() { @Override public DbConnection execute() throws IOException { return new DbProvider().getConnect(username, password); } };
-
原有代碼的邏輯現(xiàn)在就變成下面的形式:
RuntimeExceptionWrappable<DbConnection> wrappable = new RuntimeExceptionWrappable<DbConnection>() { @Override public DbConnection execute() throws IOException { return new DbProvider().getConnect(username, password); } }; try { return wrappable.execute(); } catch (IOException e) { throw new RuntimeException(); }
到目前為止雀瓢,我們依然沒(méi)有把try catch去掉枢析。我們接著把try catch部分提取出來(lái):
public class RuntimeExceptionWrapper {
public static <T> T wrap(RuntimeExceptionWrappable<T> wrappable) {
try {
return wrappable.execute();
} catch (IOException e) {
throw new RuntimeException();
}
}
}
- 最后一步,完成整個(gè)代碼:
RuntimeExceptionWrappable<DbConnection> wrappable = new RuntimeExceptionWrappable<DbConnection>() {
@Override
public DbConnection execute() throws IOException {
return new DbProvider().getConnect(username, password);
}
};
return RuntimeExceptionWrapper.wrap(wrappable);
到這里就可以看到刃麸,Wrapper被抽象到獨(dú)立的類中了登疗。
3. Stream中的Exception
自從JAVA8依賴,流處理在代碼中已經(jīng)變得越來(lái)越常見嫌蚤,這樣就不可避免的會(huì)有Exception出現(xiàn)在Stream流處理中。
public class UrlHandler {
public List<URL> getURLs() {
return Stream.of("http://www.baidu.com", "https://www.google.com")
.map(this:createURL)
.collect(Collectors.toList());
}
private URL createURL(String url) throws MalformedURLException {
return new URL(url);
}
}
上述代碼是編譯不通過(guò)的断傲,原因是createURL拋出了Checked Exception脱吱。只有對(duì)stream流處理進(jìn)行修改,接收Exception代碼才能編譯:
public List<URL> getURLs() {
return Stream.of("http://www.baidu.com", "https://www.google.com")
.map(url -> {
try {
return this.createURL(url);
} catch (MalformedURLException e) {
throw new RuntimeException();
}
})
.collect(Collectors.toList());
}
這段代碼雖然能夠工作认罩,但是依然顯得不是很優(yōu)雅箱蝠。還是跟前一部分一樣,我們抽取出來(lái)一個(gè)通用的Wrapper垦垂。
- 首先將this.createURL提取出來(lái)宦搬,作為一個(gè)通用的接口,由于createURL是一個(gè)函數(shù)劫拗,所以接口形式如下:
@FunctionalInterface
public interface RuntimeWrappableFunction<T, R> {
R apply(T t) throws Exception;
}
- 接下來(lái)间校,由于map的參數(shù)是一個(gè)函數(shù)式接口,所以我們來(lái)完成一個(gè)消費(fèi)上述函數(shù)接口的實(shí)現(xiàn):
public class RuntimeWrappableFunctionMapper {
public static <T, R> Function<T, R> wrap(RuntimeWrappableFunction<T, R> wrappableFunction) {
return t -> {
try {
return wrappableFunction.apply(t);
} catch (Exception e) {
throw new RuntimeException();
}
};
}
}
- 完善原有的代碼:
public class UrlHandler {
public List<URL> getURLs() {
return Stream.of("http://www.baidu.com", "https://www.google.com")
.map(RuntimeWrappableFunctionMapper.wrap(this::createURL))
.collect(Collectors.toList());
}
private URL createURL(String url) throws MalformedURLException {
return new URL(url);
}
}
- 有一些可選的庫(kù)也可以完成上述的功能页慷。