詳解Java Streams 中的異常處理
前言:
Stream API 和 Lambda 是Java8的重要特性讓我們可以使用更具功能性的語(yǔ)法風(fēng)格。但是在編寫的代碼時(shí)候一個(gè)更大的問題是如何處理lambda中的已檢查異常。
但是不能直接調(diào)用從Lambda拋出異常!但是可以在Lambda中做一個(gè)簡(jiǎn)單的try-catch并將異常包裝成一個(gè)RuntimeException。
/**###很顯然這不是一種好的表現(xiàn)方式##**/
/**
* dosomething
* @param item
* @return
*/
private static Object doSomething(String item) {
System.out.println("doSomething:\t" + item);
return item;
}
public static void main(String[] args) {
List<String> myList = Arrays.asList("1", "2", "3", "4", "5", "6");
myList.stream().map(item -> {
try {
return doSomething(item);
} catch (Exception e) {
throw new RuntimeException(e);
}
}).forEach(System.out::println);
}
換一種可讀性比較好的方式呢?
/**將函數(shù)體提取到一個(gè)單獨(dú)的方法中,并調(diào)用新方法做try-catch處理**/
private Object doSomething(String item) {
System.out.println("doSomething:\t" + item);
return item;
}
private Object trySomething(String item) {
try {
return doSomething(item);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void map() {
List<String> myList = Arrays.asList("1", "2", "3", "4", "5", "6");
myList.stream().map(this::doSomething).forEach(System.out::println);
}
RuntimeException
在許多情況下對(duì)于一些運(yùn)行時(shí)異常的捕捉都使用 RuntimeException 也可以在lambda內(nèi)部調(diào)用。如果每個(gè)調(diào)用都進(jìn)行運(yùn)行時(shí)異常的捕獲,重復(fù)代碼就出現(xiàn)了。所以:將它抽象為實(shí)用函數(shù),每次需要的時(shí)候調(diào)用它!
//定義一個(gè)檢查接口
@FunctionalInterface
public interface CheckedFunction<T,R> {
R apply(T t) throws Exception;
}
您可以在此抽象接口中處理try-catch并將原始異常包裝到 RuntimeException 中。
public static <T,R> Function<T,R> wrap(CheckedFunction<T,R> checkedFunction) {
return t -> {
try {
return checkedFunction.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
/**調(diào)用公共wrap 進(jìn)行異常處理*/
public void map(){
List<String> myList = Arrays.asList("1", "2", "3", "4", "5", "6");
myList.stream()
.map(wrap(item -> doSomething(item)))
.forEach(System.out::println);
}
Either
使用流時(shí)如果發(fā)生異常不希望停止處理流,Either類型是函數(shù)式語(yǔ)言中的常見類型而不是Java的一部分。與Java中的Optional類型類似,Either是具有兩種可能性的通用包裝器。例如,如果我們有一個(gè)Either值,那么這個(gè)值可以包含String類型或Integer類型Either<String,Integer>。
public class Either<L, R> {
private final L left;
private final R right;
private Either(L left, R right) {
this.left = left;
this.right = right;
}
public static <L,R> Either<L,R> Left( L value) {
return new Either(value, null);
}
public static <L,R> Either<L,R> Right( R value) {
return new Either(null, value);
}
public Optional<L> getLeft() {
return Optional.ofNullable(left);
}
public Optional<R> getRight() {
return Optional.ofNullable(right);
}
public boolean isLeft() {
return left != null;
}
public boolean isRight() {
return right != null;
}
public <T> Optional<T> mapLeft(Function<? super L, T> mapper) {
if (isLeft()) {
return Optional.of(mapper.apply(left));
}
return Optional.empty();
}
public <T> Optional<T> mapRight(Function<? super R, T> mapper) {
if (isRight()) {
return Optional.of(mapper.apply(right));
}
return Optional.empty();
}
public String toString() {
if (isLeft()) {
return "Left(" + left +")";
}
return "Right(" + right +")";
}
}
讓函數(shù)返回Either 而不是拋出一個(gè)Exception.
//只記錄異常
public static <T,R> Function<T, Either> lift(CheckedFunction<T,R> function) {
return t -> {
try {
return Either.Right(function.apply(t));
} catch (Exception ex) {
return Either.Left(ex);
}
};
}
//記錄異常和值
public static <T,R> Function<T, Either> liftWithValue(CheckedFunction<T,R> function) {
return t -> {
try {
return Either.Right(function.apply(t));
} catch (Exception ex) {
return Either.Left(Pair.of(ex,t));
}
};
}
/**調(diào)用Either.lift 捕獲異常繼續(xù)執(zhí)行*/
public void map(){
List<String> myList = Arrays.asList("1", "2", "3", "4", "5", "6");
myList.stream()
.map(Either.lift(item -> doSomething(item)))
.forEach(System.out::println);
}
總結(jié):
如果你想在Lambda中調(diào)用它c(diǎn)heckedException,你可以將其包裝成一個(gè)RuntimeException 。建議您創(chuàng)建一個(gè)抽象進(jìn)行調(diào)用,這樣您就不會(huì)每次try/catch。也可以使用 Either 或其他類型來(lái)包裝函數(shù)的結(jié)果,使流不會(huì)終止。
以上所述是小編給大家介紹的Java Streams 中的異常處理詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
Springcloud Alibaba超詳細(xì)使用詳解
SpringCloudAlibaba是一款優(yōu)秀的微服務(wù)架構(gòu),在市面上有著廣泛的應(yīng)用,這篇文章介紹了SpringCloudAlibaba的一些基本使用,適合初學(xué)者,希望能夠給大家?guī)?lái)幫助2024-08-08
SpringBoot中@ConfigurationProperties自動(dòng)獲取配置參數(shù)的流程步驟
當(dāng)需要獲取配置文件中很多參數(shù)時(shí),我們可以定義參數(shù)的前綴相同,通過自動(dòng)映射 進(jìn)行獲取配置文件中參數(shù),所以本文給大家介紹了SpringBoot中@ConfigurationProperties自動(dòng)獲取配置參數(shù)的流程步驟,需要的朋友可以參考下2024-11-11
Spring?Boot整合阿里開源中間件Canal實(shí)現(xiàn)數(shù)據(jù)增量同步
這篇文章主要為大家介紹了Spring?Boot整合阿里開源中間件Canal實(shí)現(xiàn)數(shù)據(jù)增量同步示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Spring事務(wù)中@Transactional注解不生效的原因分析與解決
在Spring框架中,@Transactional注解是管理數(shù)據(jù)庫(kù)事務(wù)的核心方式,本文將深入分析事務(wù)自調(diào)用的底層原理,解釋為什么事務(wù)不生效,并提供多種解決方案,希望對(duì)大家有所幫助2025-03-03
基于mybatis-plus-generator實(shí)現(xiàn)代碼自動(dòng)生成器
這篇文章專門為小白準(zhǔn)備了入門級(jí)mybatis-plus-generator代碼自動(dòng)生成器,可以提高開發(fā)效率。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-05-05
教你使用eclipse?搭建Swt?環(huán)境的全過程
本文給大家分享使用eclipse?搭建Swt?環(huán)境的全過程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12
關(guān)于MyBatis的foreach標(biāo)簽常用方法
這篇文章主要介紹了關(guān)于MyBatis的foreach標(biāo)簽常用方法,foreach 標(biāo)簽可以用來(lái)遍歷數(shù)組、列表和 Map 等集合參數(shù),實(shí)現(xiàn)批量操作或一些簡(jiǎn)單 SQL 操作,需要的朋友可以參考下2023-05-05

