柚子快報邀請碼778899分享:數(shù)據(jù)庫 Stream 流式編程
優(yōu)質(zhì)博文:IT-BLOG-CN
大家都知道可以將Collection類轉(zhuǎn)化成流Stream進行操作(Map并不能創(chuàng)建流),代碼變得簡約流暢。我們先看下流的幾個特點: 1、流并不存儲元素。這些元素可能存儲在底層的集合中,或者是按需生成。 2、流的操作不會修改其數(shù)據(jù)元素,而是生成一個新的流。 3、流的操作是盡可能惰性執(zhí)行的。這意味著直至需要其結(jié)果時,操作才會執(zhí)行。
一、創(chuàng)建流
負責新建一個Stream流,大多數(shù)都是基于現(xiàn)有的數(shù)組、List、Set、Map等集合創(chuàng)建新的Stream。
stream()
創(chuàng)建一個stream串行流對象。
CR時可優(yōu)化的代碼片段:
public List
List
for (SFltStudent source : sourceList) {
SFltStudent target = new SFltStudent();
target.setTicketNo(source.getOldTicketNo());
target.setFlightAgency(source.getFlightAgency());
targetList.add(target);
}
return targetList;
}
代碼優(yōu)化:這里sourceList如果數(shù)據(jù)量很大時,也可以考慮parallel stream。這里主要是想通過stream提高代碼簡潔性和可讀性。
public List
return sourceList.stream()
.map(source -> {
SFltStudent target = new SFltStudent();
target.setTicketNo(source.getOldTicketNo());
target.setFlightAgency(source.getFlightAgency());
return target;
})
.collect(Collectors.toList());
}
parallelStream()
創(chuàng)建一個可并行執(zhí)行的stream流對象??梢杂行Ю糜嬎銠C的多CPU硬件,提升邏輯的執(zhí)行速度。將一整個stream劃分為多個片段,然后對各個分片流并行執(zhí)行處理邏輯,最后將各個分片流的執(zhí)行結(jié)果匯總為一個整體流。
::: tip 如果遇到耗時的操作,或者大量IO的操作,或者有線程sleep的操作一定要避免使用并行流。
并行流場景效率會比迭代器逐個循環(huán)更高。 :::
查看parallelStream的源碼發(fā)現(xiàn)parallel Stream底層是將任務進行了切分,最終將任務傳遞給了jdk8自帶的“全局”ForkJoinPool線程池。在Fork-Join中,比如一個擁有4個線程的ForkJoinPool線程池,有一個任務隊列,一個大的任務切分出的子任務會提交到線程池的任務隊列中,4個線程從任務隊列中獲取任務執(zhí)行,哪個線程執(zhí)行的任務快,哪個線程執(zhí)行的任務就多,只有隊列中沒有任務線程才是空閑的,這就是工作竊取。
/**
* @return a possibly parallel {@code Stream} over the elements in this == parallelStream()并不一定返回一個并行流,有可能parallelStream()全是由主線程順序執(zhí)行的。
* collection
* @since 1.8
*/
default Stream
return StreamSupport.stream(spliterator(), true);
}
注意:parallelStream和整個java進程共用ForkJoinPool:如果直接使用parallelStream().foreach會默認使用全局的ForkJoinPool,而這樣就會導致當前程序很多地方共用同一個線程池,包括gc相關(guān)操作在內(nèi),所以一旦任務隊列中滿了之后,就會出現(xiàn)阻塞的情況,導致整個程序的只要當前使用ForkJoinPool的地方都會出現(xiàn)問題。
CR時可優(yōu)化的代碼片段: :并發(fā)獲取接口數(shù)據(jù),進行業(yè)務處理,對共享數(shù)據(jù)的修改需要考慮多線程安全問題。
List
List
infos.parallelStream()
.filter(XStudentOrderInfo::getChecked)
.map(XStudentOrderInfo::getProductOrderID)
.filter(StringUtils::isNotBlank)
.distinct()
.allMatch(productOrderId -> {
XRefundResponse response = xStudentCancelSoa.xStudentClassOrder(getXStudentRequest(eid, refundInfo, productOrderId));
boolean isSuccess = response.getResponseStatus() != null
&& response.getResponseStatus().ack == AckCodeType.Success
&& response.isIsSuccess() != null
&& response.isIsSuccess();
if (!isSuccess && StringUtils.isNotBlank(response.getMessage())) {
errorMessageList.add(response.getMessage());
errorProductOrderIds.add(productOrderId);
}
return isSuccess;
})
);
代碼優(yōu)化:將復雜的條件判斷提取到processOrder方法中,使主流處理邏輯更加簡潔和易讀。
List
List
boolean allSuccess = infos.parallelStream()
.filter(XStudentOrderInfo::getChecked)
.map(XStudentOrderInfo::getProductOrderID)
.filter(StringUtils::isNotBlank)
.distinct()
.allMatch(productOrderId -> processOrder(productOrderId, errorMessageList, errorProductOrderIds));
private boolean processOrder(String productOrderId, List
XRefundResponse response = xStudentCancelSoa.xStudentClassOrder(getXStudentRequest(eid, refundInfo, productOrderId));
boolean isSuccess = response.getResponseStatus() != null
&& response.getResponseStatus().ack == AckCodeType.Success
&& Boolean.TRUE.equals(response.isIsSuccess());
if (!isSuccess && StringUtils.isNotBlank(response.getMessage())) {
errorMessageList.add(response.getMessage());
errorProductOrderIds.add(productOrderId);
}
return isSuccess;
}
Stream.of()
通過給定的一系列元素創(chuàng)建一個新的stream串行流對象。
二、Stream 中間處理
輸入Stream對象,輸出一個新的Stream對象,中間管道操作可以進行疊加。
規(guī)范
CR時發(fā)現(xiàn)不規(guī)范的流式編程如下:
issueBillList.stream().map(IssueBillDO::getIssueBillId).collect(Collectors.toList());
根據(jù)代碼規(guī)范,在代碼中使用鏈式調(diào)用時,為了提高代碼的可讀性和維護性,建議在方法鏈的每個方法調(diào)用之間進行換行。這樣可以使代碼更容易閱讀和理解。
List
.map(IssueBillDO::getIssueBillId)
.collect(Collectors.toList());
filter()
按照條件過濾符合要求的元素,返回新的stream流。
CR時可優(yōu)化的代碼片段: .filter多個過濾條件并存,存在一定的優(yōu)化空間。編程如下:
.filter(r -> StringUtilsExt.compareIgnoreSpaceAndCaps(r.getPassengerName(), trace.getPassengerName())
&& StringUtilsExt.compareIgnoreSpaceAndCaps(r.getFlight(), trace.getFlightNo())
&& StringUtilsExt.compareIgnoreSpaceAndCaps(r.getDPort(), trace.getDport()))
......
建議根據(jù)業(yè)務將它們拆分為多個.filter方法調(diào)用可以提高代碼的可讀性和可維護性。但是需要注意每個.filter調(diào)用都會遍歷一次流中的元素。如果流非常大,多個.filter調(diào)用可能會帶來性能開銷。同時如果條件之間存在邏輯依賴關(guān)系,拆分成多個.filter調(diào)用可能會導致邏輯錯誤。例如,如果某個條件的結(jié)果會影響另一個條件的判斷,拆分可能會破壞這種依賴關(guān)系。雖然拆分可以提高某些情況下的可讀性,但如果條件本身很簡單,拆分反而會使代碼顯得冗長和復雜。
具體大家根據(jù)自己的業(yè)務特點進行選擇
方案一:如果條件非常復雜,或者你希望每個條件都能單獨清晰地表達,可以拆分成多個.filter方法
.filter(r -> StringUtilsExt.compareIgnoreSpaceAndCaps(r.getPassengerName(), trace.getTripInfo().getPassengerName()))
.filter(r -> StringUtilsExt.compareIgnoreSpaceAndCaps(r.getFlight(), trace.getTripInfo().getFlightNo()))
.filter(r -> StringUtilsExt.compareIgnoreSpaceAndCaps(r.getDPort(), trace.getTripInfo().getDport()))
方案二:如果條件邏輯非常復雜,考慮將條件封裝到一個輔助方法中,這樣代碼會更加清晰
.filter(r -> matchesTraceInfo(r, trace.getTripInfo()))
private boolean matchesTraceInfo(Record r, TripInfo tripInfo) {
return StringUtilsExt.compareIgnoreSpaceAndCaps(r.getPassengerName(), tripInfo.getPassengerName()) &&
StringUtilsExt.compareIgnoreSpaceAndCaps(r.getFlight(), tripInfo.getFlightNo()) &&
StringUtilsExt.compareIgnoreSpaceAndCaps(r.getDPort(), tripInfo.getDport());
}
map()
將已有元素轉(zhuǎn)換為另一個對象類型,一對一邏輯,返回新的stream流。
List
// 使用流操作
List
.map(id -> {
id.replace("A","B");
return id;
})
.collect(Collectors.toList());
System.out.println(results);
執(zhí)行之后,會發(fā)現(xiàn)每一個元素都被轉(zhuǎn)換為對應新的元素,但是前后總元素個數(shù)是一致的:
B1
B2
B3
下面的代碼因?qū)ap和filter功能的混淆,導致代碼執(zhí)行解決與預期不符,最終出現(xiàn)生產(chǎn)故障。
if (response != null && response.isPresent() && response.isPresent().get().getResult() != null) {
ResultType resultType = response.isPresent().get().getResult();
resultType.getResultList().stream()
.map(p -> matchChildResult(p) && p.getCode == CODE_404)
.findFirst().ifPresent(result -> {
logger.build("childdata", "fail:).info();
if (ConfigFunc.getBoolean("childIntercept", false)) {
throw new ResultException("fail);
}
});
原因:如果使用map這段代碼會返回一個List
flatMap()
將已有元素轉(zhuǎn)換為另一個對象類型,一對多邏輯,即原來一個元素對象可能會轉(zhuǎn)換為1個或者多個新類型的元素,返回新的stream流。
案例:
List
// 使用流操作
List
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.collect(Collectors.toList());
System.out.println(results2);
執(zhí)行之后,會發(fā)現(xiàn)每一個元素都被轉(zhuǎn)換為多個新的元素:
B1
B2
B3
B4
flatMap操作是先將每個元素進行處理并返回一個新的Stream,然后將多個Stream展開合并為了一個完整的新的Stream,如下:
CR時可優(yōu)化的代碼片段: 應用場景為List中的對象中包含List列表
List
.filter(Objects::nonNull)
.filter(p -> CollectionUtils.isNotEmpty(p.getMaterialInfoList()))
.flatMap(p -> p.getMaterialInfoList().stream().filter(Objects::nonNull))
.collect(Collectors.toList());
代碼優(yōu)化:提前檢查p.getMaterialInfoList()是否為空的處理,CollectionUtils和Collectors被頻繁使用,可以進行靜態(tài)導入以簡化代碼。
List
.filter(p -> p != null && isNotEmpty(p.getMaterialInfoList()))
.flatMap(p -> p.getMaterialInfoList().stream())
.filter(Objects::nonNull)
.collect(toList());
limit()
僅保留集合前面指定個數(shù)的元素,返回新的stream流。
Stream
.limit(2);
System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2]
skip()
跳過集合前面指定個數(shù)的元素,返回新的stream流。
Stream
.skip(2);
System.out.println(Arrays.toString(integerStream.toArray())); // [3]
concat()
將兩個流的數(shù)據(jù)合并起來為1個新的流,返回新的stream流。
distinct()
對Stream中所有元素進行去重,返回新的stream流。
**CR`時可優(yōu)化的代碼片段:**
submitReiEntityList = model.getReibursementInfo().getSubmitReiEntityList().stream()
.map(ReibursementApplyOrderInfo::getOrderId)
.distinct()
.collect(Collectors.toList());
這里主要說一個思想,是否可以將需要distinct的集合轉(zhuǎn)換為Set進行存儲,提高查找效率。
sorted()
對stream中所有的元素按照指定規(guī)則進行排序,返回新的stream流。
這里主要看一下目前存在的寫法
CR片段一
wordSet1 = wordSet.stream().sorted(new Comparator
@Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
}).collect(Collectors.toList());
CR片段二
List
.sorted((RescheduleLog i1, RescheduleLog i2) -> i2.getRecordTime().compareTo(i1.getRecordTime()))
.collect(Collectors.toList());
CR片段三:上面的片段可以按照該規(guī)范,簡化代碼。
List
.sorted(Comparator.comparing(RescheduleIssueBill::getIssueBillID).reversed())
.collect(Collectors.toList());
CR片段四
List
.stream()
.sorted(Comparator.comparing(RescheduleIssueBill::getIssueBillID).reversed())
.collect(Collectors.toList());
代碼優(yōu)化:如果不需要保留原始列表的順序,可以直接對original進行排序,避免創(chuàng)建額外的心列表。
original.sort(Comparator.comparing(SegmentInfo::getSortedSequence));
peek()
對stream流中的每個元素進行逐個遍歷處理,返回處理后的stream流。意味著peek只能作為管道中途的一個處理步驟,而沒法直接執(zhí)行得到結(jié)果,其后面必須還要有其它終止操作的時候才會被執(zhí)行;而foreach作為無返回值的終止方法,則可以直接執(zhí)行相關(guān)操作。
CR過程中使用peek的代碼,peek么有問題,但是代碼還是有一定的優(yōu)化空間。
List
.filter(auditInfo -> AllianceAuditStatusEnum.AUDIT_SUCCESS.getValue().equals(auditInfo.getAuditStatus()))
.peek(auditInfo -> {
Integer customKey = idxAtomic.getAndUpdate(idx -> idx + NumberUtils.INTEGER_ONE);
auditInfo.setCustomKey(customKey);
})
.collect(Collectors.toList());
我們給一個更優(yōu)雅的代碼:
List
.filter(auditInfo -> AllianceAuditStatusEnum.AUDIT_SUCCESS.getValue().equals(auditInfo.getAuditStatus()))
.peek(auditInfo -> auditInfo.setCustomKey(idxAtomic.getAndIncrement()))
.collect(Collectors.toList());
三、終止Stream
通過終止管道操作之后,Stream流將會結(jié)束,最后可能會執(zhí)行某些邏輯處理,或者是按照要求返回某些執(zhí)行后的結(jié)果數(shù)據(jù)。
count()
返回stream處理后最終的元素個數(shù)。
CR時可優(yōu)化的代碼片段:
groupByDataType.entrySet().stream()
.allMatch(entry -> entry.getValue().stream()
.map(DiscountInfo::getDeductionAmount)
.distinct()
.count() == 1);
代碼優(yōu)化:上述代碼distinct與count結(jié)合使用時,可以使用Set與length()方法實現(xiàn),但是這里使用count和distinct可能從業(yè)務上理解更為接近,所以具體需要根據(jù)業(yè)務場景決定。
boolean allMatch = groupByDataType.entrySet().stream()
.allMatch(entry -> entry.getValue().stream()
.map(DiscountInfo::getDeductionAmount)
.collect(Collectors.toSet())
.size() == 1);
但是這里可以根據(jù)allMatch的特性上進行優(yōu)化,只要找到一個不滿足條件的金額,就提前返回false提交性能。
boolean allMatch = groupByDataType.entrySet().stream()
.allMatch(entry -> {
Set
.map(DiscountInfo::getDeductionAmount)
.collect(Collectors.toSet());
return deductionAmounts.size() == 1;
});
max()
返回stream處理后的元素最大值。
CR時可優(yōu)化的代碼片段:
files.stream()
.mapToInt(UploadRetireMaterialInfoType::getBatchNo)
.max()
.getAsInt();
代碼優(yōu)化:這里主要的問題是,再調(diào)用getAsInt()方法時,一定要判斷下是否存在,否則回報異常。
OptionalInt maxBatchNoOptional = files.stream()
.mapToInt(UploadRetireMaterialInfoType::getBatchNo)
.max();
if (maxBatchNoOptional.isPresent()) {
int maxBatchNo = maxBatchNoOptional.getAsInt();
} else {
......
}
min()
返回stream處理后的元素最小值。
CR過程中發(fā)現(xiàn)可以使用min()方法進行優(yōu)化的代碼片段
List
.sorted(Comparator.comparing(SFltticketStudentByairlineMy::getSequence))
.collect(toList());
SFltticketStudentByairlineMy firstSeqTicketNo = sortRefundDetails.get(0);
優(yōu)化后代碼如下:
refundDetails.stream()
.min(Comparator.comparing(SFltticketStudentByairlineMy::getSequence));
findFirst()
找到第一個符合條件的元素時則終止流處理。
優(yōu)化片段一:
CR時發(fā)現(xiàn).findFirst()返回Optional可以繼續(xù)進行業(yè)務處理,存在一定的優(yōu)化空間。代碼如下:
oc.getOrderInfoList().stream()
.filter(f -> (StringUtilsExt.compareIgnoreSpaceAndCaps(f.getFlight(), lastTrip.getFlightNo())
......)
.findFirst().orElse(null);
if (lastFlight != null) {
......
}
可以在findFirst()方法后繼續(xù)執(zhí)行操作,而不需要單獨的if (lastFlight != null)語句。流式編程提供了ifPresent方法,可以讓你在找到符合條件的元素時執(zhí)行某些操作。這樣使代碼更加簡潔和流暢,不需要顯式地進行空值檢查。
oc.getOrderInfoList().stream()
.filter(f -> (StringUtilsExt.compareIgnoreSpaceAndCaps(f.getFlight(), lastTrip.getFlightNo())
......)
.findFirst()
.ifPresent(lastFlight -> {
// 在這里執(zhí)行你需要的操作
// 例如:
// System.out.println("Found flight: " + lastFlight);
});
優(yōu)化片段二:
對.findFirst()方法使用存在優(yōu)化空間
List
.sorted(Comparator.comparing(SFltticketStudentByairlineMy::getSequence))
.collect(toList());
SFltticketStudentByairlineMy firstSeqTicketNo = sortRefundDetails.get(0);
使用.findFirst()方法獲取第一個符合要求的元素即可。當然這個代碼還存在優(yōu)化空間。
SFltticketStudentByairlineMy firstSeqTicketNo = refundDetails.stream()
.sorted(Comparator.comparing(SFltticketStudentByairlineMy::getSequence))
.collect(toList())
.findFirst();
findAny()
找到任何一個符合條件的元素時則退出流處理,這個對于串行流時與findFirst相同,對于并行流時比較高效,任何分片中找到都會終止后續(xù)計算邏輯。
CR時可優(yōu)化的代碼片段:
orderInfo.getRefundInfoList().stream()
.filter(a -> MATERIAL_SUPPLEMENT_FLAG.equals(a.getKey()) && TRUE_VALUE.equals(a.getValue()))
.findAny()
.isPresent();
優(yōu)化代碼:返回的是一個boolean類型,可以直接使用anyMatch()
boolean isPresent = orderInfo.getRefundOrderFlagInfoList().stream()
.anyMatch(a -> MATERIAL_SUPPLEMENT_FLAG.equals(a.getKey()) && TRUE_VALUE.equals(a.getValue()));
anyMatch()
返回一個boolean值,類似于isContains(),用于判斷是否有符合條件的元素。
我們也會將寫的標準的代碼推薦給大家
boolean isAgencyModeOrder = CollectionsUtil.isNotEmpty(orderAlibabaCartList)
&& orderAlibabaCartList.stream()
.filter(s -> Objects.equals(s.getBookType(), BookingTypeConstants.TICKET_PLUS_X_ORDER))
.anyMatch(s -> Objects.equals(s.getPaymentVersion(), PaymentVersionConstants.PAYMENT_AGENCY));
allMatch()
返回一個boolean值,用于判斷是否所有元素都符合條件。
在CR中發(fā)現(xiàn)可以優(yōu)化的代碼:在流操作中fucLi部分存在優(yōu)化空間。
private Stream
return sourceList.stream()
.filter(
source -> {
List
buildFilterConditions(source);
return fucLi.stream().allMatch(Supplier::get);
});
}
代碼是一個過濾方法,它將一個List
優(yōu)化后的代碼:將fucLi變量內(nèi)聯(lián)到filter方法中,減少了不必要的局部變量聲明,使代碼更加簡潔。
private Stream
return sourceList.stream()
.filter(source -> buildFilterConditions(source).stream().allMatch(Supplier::get));
}
noneMatch()
返回一個boolean值, 用于判斷是否所有元素都不符合條件。
CR時可優(yōu)化的代碼片段:
boolean userBehaviorsCheck = filterRecordList.stream().noneMatch(record -> IntegerUtils.compare(record.getPageCode(), 201));
collect()
將流轉(zhuǎn)換為指定的類型,通過Collectors進行指定。
toArray()
將流轉(zhuǎn)換為數(shù)組。
iterator()
將流轉(zhuǎn)換為Iterator對象。
CR時可優(yōu)化的代碼片段:
Iterator
while (iterator.hasNext()) {
M_RelateAliPassenger passenger = iterator.next();
boolean matched = passengers2.stream()
.anyMatch(p -> p.getPassengerName() != null && p.getPassengerName().equalsIgnoreCase(passenger.getPassengerName()));
if (!matched) {
iterator.remove();
}
}
優(yōu)化后的代碼:主要任務是從passengers列表中移除那些在passengers2列表中沒有匹配的乘客??梢酝ㄟ^集合操作來簡化和優(yōu)化這段代碼。
passengers.removeIf(passenger ->
passengers2.stream()
.noneMatch(p -> p.getPassengerName() != null
&& p.getPassengerName().equalsIgnoreCase(passenger.getPassengerName()))
);
foreach()
無返回值,對元素進行逐個遍歷,然后執(zhí)行給定的處理邏輯。foreach()操作與parallelStream()搭配使用時,必須保證是線程安全的。也不要直接使用默認的線程池。
CR時可優(yōu)化的代碼片段:
parameterList.forEach(param -> orderIds.append(param.getOrderID()).append(","));
優(yōu)化后的代碼:Collectors.joining(",")最適合做上述的工作,應該是首先想到的。
String orderIds = parameterList.stream()
.map(param -> param.getOrderID())
.collect(Collectors.joining(","));
常見問題
一旦一個Stream被執(zhí)行了終止操作之后,后續(xù)便不可以再讀這個流執(zhí)行其他的操作了,否則會報錯,看下面示例:
public void testHandleStreamAfterClosed() {
List
Stream
// 統(tǒng)計stream操作后剩余的元素個數(shù)
System.out.println(stream.count());
System.out.println("-----下面會報錯-----");
// 判斷是否有元素值等于205
try {
System.out.println(stream.anyMatch("205"::equals));
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
}
System.out.println("-----上面會報錯-----");
}
結(jié)果:
-----下面會報錯-----
java.lang.IllegalStateException: stream has already been operated upon or closed
-----上面會報錯-----
java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
at java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:516)
at Solution_0908.main(Solution_0908.java:55)
因為stream已經(jīng)被執(zhí)行count()終止方法了,所以對stream再執(zhí)行anyMatch方法的時候,就會報錯stream has already been operated upon or closed,這一點在使用的時候需要特別注意。
四、collect方法
獲取一個集合類的結(jié)果對象,比如List、Set或者HashMap等。
Collectors.toList()
List
.stream()
.filter(offer -> offer.getCate1LevelId().equals("11"))
.collect(Collectors.toList());
Collectors.toSet()
Set
.stream()
.filter(offer -> offer.getCate1LevelId().equals("22"))
.collect(Collectors.toSet());
Collectors.toMap
CodeReview 時發(fā)現(xiàn)的問題:沒有考慮key重復問題。
Arrays.stream(clazz.getDeclaredFields())
.collect(Collectors.toMap(r -> r.getName().toLowerCase(), r -> r));
優(yōu)化后的代碼:Function.identity()是java.util.function.Function接口中的一個靜態(tài)方法。它總是返回一個其輸入?yún)?shù)的函數(shù)。這在需要傳遞一個不做任何變換的函數(shù)時非常有用。Function.identity()等價于上面的r -> r。(k1, k2) -> k2就是解決重復key的問題,當存在重復key時使用最后一個key。
Arrays.stream(clazz.getDeclaredFields())
.collect(NormalOfferModel::getName, Function.identity(), (k1, k2) -> k2));
Collectors.joining
List
String joinResult = ids.stream().collect(Collectors.joining(","));
Collectors.averagingInt
List
// 計算平均值
Double average = ids.stream().collect(Collectors.averagingInt(value -> value));
Collectors.summarizingInt
List
// 數(shù)據(jù)統(tǒng)計信息
IntSummaryStatistics summary = ids.stream().collect(Collectors.summarizingInt(value -> value));
Optional 類
ifPresent(Consumer super T> action)
如果Optional中包含值,執(zhí)行給定的Consumer操作,否則什么也不做。常用于簡化代碼,避免顯式的空值檢查。
isPresent()
檢查Optional中是否包含值。如果包含值,返回true,否則返回false。
get()
如果Optional中包含值,返回該值;否則拋出NoSuchElementException。這個方法不推薦頻繁使用,因為它違背了Optional的初衷,即避免顯式的空值檢查和異常處理。
orElse(T other)
如果Optional中包含值,返回該值;否則返回other。常用于提供默認值。
orElseGet(Supplier extends T> other)
如果Optional中包含值,返回該值;否則通過調(diào)用Supplier獲取一個默認值。與orElse不同的是,Supplier只有在需要時才會被調(diào)用,因此適用于生成默認值開銷較大的情況。
isEmpty()
檢查Optional中是否為空。如果為空,返回true,否則返回false。
orElseThrow()
如果Optional中包含值,返回該值;否則拋出NoSuchElementException。
optional.orElseThrow(() -> new IllegalArgumentException("Value is absent"));
orElseThrow(Supplier extends X> exceptionSupplier)
如果Optional中包含值,返回該值;否則通過Supplier拋出指定的異常。
filter(Predicate super T> predicate)
如果Optional中包含值,并且該值滿足給定的謂詞,返回一個包含該值的Optional;否則返回一個空的Optional。常用于條件過濾。
Optional
map(Function super T, ? extends U> mapper)
如果Optional中包含值,應用給定的函數(shù)并返回一個包含映射結(jié)果的Optional;否則返回一個空的Optional。常用于鏈式調(diào)用。
Optional
flatMap(Function super T, Optional> mapper)
與map類似,但mapper函數(shù)返回的是一個Optional對象,并且不會對返回的Optional進行嵌套。
Optional
柚子快報邀請碼778899分享:數(shù)據(jù)庫 Stream 流式編程
推薦鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。