欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)邀請(qǐng)碼778899分享:數(shù)據(jù)庫(kù) Stream 流式編程

柚子快報(bào)邀請(qǐng)碼778899分享:數(shù)據(jù)庫(kù) Stream 流式編程

http://yzkb.51969.com/

優(yōu)質(zhì)博文:IT-BLOG-CN

大家都知道可以將Collection類轉(zhuǎn)化成流Stream進(jìn)行操作(Map并不能創(chuàng)建流),代碼變得簡(jiǎn)約流暢。我們先看下流的幾個(gè)特點(diǎn): 1、流并不存儲(chǔ)元素。這些元素可能存儲(chǔ)在底層的集合中,或者是按需生成。 2、流的操作不會(huì)修改其數(shù)據(jù)元素,而是生成一個(gè)新的流。 3、流的操作是盡可能惰性執(zhí)行的。這意味著直至需要其結(jié)果時(shí),操作才會(huì)執(zhí)行。

一、創(chuàng)建流

負(fù)責(zé)新建一個(gè)Stream流,大多數(shù)都是基于現(xiàn)有的數(shù)組、List、Set、Map等集合創(chuàng)建新的Stream。

stream()

創(chuàng)建一個(gè)stream串行流對(duì)象。

CR時(shí)可優(yōu)化的代碼片段:

public List toListByOldTicketNo(List sourceList) {

List targetList = Lists.newArrayListWithExpectedSize(sourceList.size());

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ù)量很大時(shí),也可以考慮parallel stream。這里主要是想通過(guò)stream提高代碼簡(jiǎn)潔性和可讀性。

public List toListByOldTicketNo(List sourceList) {

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)建一個(gè)可并行執(zhí)行的stream流對(duì)象。可以有效利用計(jì)算機(jī)的多CPU硬件,提升邏輯的執(zhí)行速度。將一整個(gè)stream劃分為多個(gè)片段,然后對(duì)各個(gè)分片流并行執(zhí)行處理邏輯,最后將各個(gè)分片流的執(zhí)行結(jié)果匯總為一個(gè)整體流。

::: tip 如果遇到耗時(shí)的操作,或者大量IO的操作,或者有線程sleep的操作一定要避免使用并行流。

并行流場(chǎng)景效率會(huì)比迭代器逐個(gè)循環(huán)更高。 :::

查看parallelStream的源碼發(fā)現(xiàn)parallel Stream底層是將任務(wù)進(jìn)行了切分,最終將任務(wù)傳遞給了jdk8自帶的“全局”ForkJoinPool線程池。在Fork-Join中,比如一個(gè)擁有4個(gè)線程的ForkJoinPool線程池,有一個(gè)任務(wù)隊(duì)列,一個(gè)大的任務(wù)切分出的子任務(wù)會(huì)提交到線程池的任務(wù)隊(duì)列中,4個(gè)線程從任務(wù)隊(duì)列中獲取任務(wù)執(zhí)行,哪個(gè)線程執(zhí)行的任務(wù)快,哪個(gè)線程執(zhí)行的任務(wù)就多,只有隊(duì)列中沒(méi)有任務(wù)線程才是空閑的,這就是工作竊取。

/**

* @return a possibly parallel {@code Stream} over the elements in this == parallelStream()并不一定返回一個(gè)并行流,有可能parallelStream()全是由主線程順序執(zhí)行的。

* collection

* @since 1.8

*/

default Stream parallelStream() {

return StreamSupport.stream(spliterator(), true);

}

注意:parallelStream和整個(gè)java進(jìn)程共用ForkJoinPool:如果直接使用parallelStream().foreach會(huì)默認(rèn)使用全局的ForkJoinPool,而這樣就會(huì)導(dǎo)致當(dāng)前程序很多地方共用同一個(gè)線程池,包括gc相關(guān)操作在內(nèi),所以一旦任務(wù)隊(duì)列中滿了之后,就會(huì)出現(xiàn)阻塞的情況,導(dǎo)致整個(gè)程序的只要當(dāng)前使用ForkJoinPool的地方都會(huì)出現(xiàn)問(wèn)題。

CR時(shí)可優(yōu)化的代碼片段: :并發(fā)獲取接口數(shù)據(jù),進(jìn)行業(yè)務(wù)處理,對(duì)共享數(shù)據(jù)的修改需要考慮多線程安全問(wèn)題。

List errorMessageList = Collections.synchronizedList(new ArrayList<>());

List errorProductOrderIds = Collections.synchronizedList(new ArrayList<>());

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)化:將復(fù)雜的條件判斷提取到processOrder方法中,使主流處理邏輯更加簡(jiǎn)潔和易讀。

List errorMessageList = Collections.synchronizedList(new ArrayList<>());

List errorProductOrderIds = Collections.synchronizedList(new ArrayList<>());

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 errorMessageList, List errorProductOrderIds) {

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()

通過(guò)給定的一系列元素創(chuàng)建一個(gè)新的stream串行流對(duì)象。

二、Stream 中間處理

輸入Stream對(duì)象,輸出一個(gè)新的Stream對(duì)象,中間管道操作可以進(jìn)行疊加。

規(guī)范

CR時(shí)發(fā)現(xiàn)不規(guī)范的流式編程如下:

issueBillList.stream().map(IssueBillDO::getIssueBillId).collect(Collectors.toList());

根據(jù)代碼規(guī)范,在代碼中使用鏈?zhǔn)秸{(diào)用時(shí),為了提高代碼的可讀性和維護(hù)性,建議在方法鏈的每個(gè)方法調(diào)用之間進(jìn)行換行。這樣可以使代碼更容易閱讀和理解。

List issueBillIds = issueBillList.stream()

.map(IssueBillDO::getIssueBillId)

.collect(Collectors.toList());

filter()

按照條件過(guò)濾符合要求的元素,返回新的stream流。

CR時(shí)可優(yōu)化的代碼片段: .filter多個(gè)過(guò)濾條件并存,存在一定的優(yōu)化空間。編程如下:

.filter(r -> StringUtilsExt.compareIgnoreSpaceAndCaps(r.getPassengerName(), trace.getPassengerName())

&& StringUtilsExt.compareIgnoreSpaceAndCaps(r.getFlight(), trace.getFlightNo())

&& StringUtilsExt.compareIgnoreSpaceAndCaps(r.getDPort(), trace.getDport()))

......

建議根據(jù)業(yè)務(wù)將它們拆分為多個(gè).filter方法調(diào)用可以提高代碼的可讀性和可維護(hù)性。但是需要注意每個(gè).filter調(diào)用都會(huì)遍歷一次流中的元素。如果流非常大,多個(gè).filter調(diào)用可能會(huì)帶來(lái)性能開銷。同時(shí)如果條件之間存在邏輯依賴關(guān)系,拆分成多個(gè).filter調(diào)用可能會(huì)導(dǎo)致邏輯錯(cuò)誤。例如,如果某個(gè)條件的結(jié)果會(huì)影響另一個(gè)條件的判斷,拆分可能會(huì)破壞這種依賴關(guān)系。雖然拆分可以提高某些情況下的可讀性,但如果條件本身很簡(jiǎn)單,拆分反而會(huì)使代碼顯得冗長(zhǎng)和復(fù)雜。

具體大家根據(jù)自己的業(yè)務(wù)特點(diǎn)進(jìn)行選擇

方案一:如果條件非常復(fù)雜,或者你希望每個(gè)條件都能單獨(dú)清晰地表達(dá),可以拆分成多個(gè).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()))

方案二:如果條件邏輯非常復(fù)雜,考慮將條件封裝到一個(gè)輔助方法中,這樣代碼會(huì)更加清晰

.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)換為另一個(gè)對(duì)象類型,一對(duì)一邏輯,返回新的stream流。

List ids = Arrays.asList("A1", "A2", "A3");

// 使用流操作

List results = ids.stream()

.map(id -> {

id.replace("A","B");

return id;

})

.collect(Collectors.toList());

System.out.println(results);

執(zhí)行之后,會(huì)發(fā)現(xiàn)每一個(gè)元素都被轉(zhuǎn)換為對(duì)應(yīng)新的元素,但是前后總元素個(gè)數(shù)是一致的:

B1

B2

B3

下面的代碼因?qū)ap和filter功能的混淆,導(dǎo)致代碼執(zhí)行解決與預(yù)期不符,最終出現(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這段代碼會(huì)返回一個(gè)List的列表,應(yīng)該不是開發(fā)者想要的。而且,只要respose返回了結(jié)果,那么map就會(huì)返回一個(gè)List列表,這個(gè)列表可能為:[true,false,......]等等,開發(fā)者應(yīng)該要的是滿足條件才拋出錯(cuò)誤的,但是生產(chǎn)應(yīng)該是只要respose返回了結(jié)果code無(wú)論是不是404都會(huì)拋錯(cuò)。導(dǎo)致線上系統(tǒng)異常,訂單下跌。

flatMap()

將已有元素轉(zhuǎn)換為另一個(gè)對(duì)象類型,一對(duì)多邏輯,即原來(lái)一個(gè)元素對(duì)象可能會(huì)轉(zhuǎn)換為1個(gè)或者多個(gè)新類型的元素,返回新的stream流。

案例:

List sentences = Arrays.asList("B1 B2","B3 B4");

// 使用流操作

List results2 = sentences.stream()

.flatMap(sentence -> Arrays.stream(sentence.split(" ")))

.collect(Collectors.toList());

System.out.println(results2);

執(zhí)行之后,會(huì)發(fā)現(xiàn)每一個(gè)元素都被轉(zhuǎn)換為多個(gè)新的元素:

B1

B2

B3

B4

flatMap操作是先將每個(gè)元素進(jìn)行處理并返回一個(gè)新的Stream,然后將多個(gè)Stream展開合并為了一個(gè)完整的新的Stream,如下:

CR時(shí)可優(yōu)化的代碼片段: 應(yīng)用場(chǎng)景為L(zhǎng)ist中的對(duì)象中包含List列表

List allMaterialList = specialEventInfoForPageList.stream()

.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被頻繁使用,可以進(jìn)行靜態(tài)導(dǎo)入以簡(jiǎn)化代碼。

List allMaterialList = specialEventInfoForPageList.stream()

.filter(p -> p != null && isNotEmpty(p.getMaterialInfoList()))

.flatMap(p -> p.getMaterialInfoList().stream())

.filter(Objects::nonNull)

.collect(toList());

limit()

僅保留集合前面指定個(gè)數(shù)的元素,返回新的stream流。

Stream integerStream = Arrays.stream({1, 2, 3})

.limit(2);

System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2]

skip()

跳過(guò)集合前面指定個(gè)數(shù)的元素,返回新的stream流。

Stream integerStream = Arrays.stream({1, 2, 3});

.skip(2);

System.out.println(Arrays.toString(integerStream.toArray())); // [3]

concat()

將兩個(gè)流的數(shù)據(jù)合并起來(lái)為1個(gè)新的流,返回新的stream流。

distinct()

對(duì)Stream中所有元素進(jìn)行去重,返回新的stream流。

**CR`時(shí)可優(yōu)化的代碼片段:**

submitReiEntityList = model.getReibursementInfo().getSubmitReiEntityList().stream()

.map(ReibursementApplyOrderInfo::getOrderId)

.distinct()

.collect(Collectors.toList());

這里主要說(shuō)一個(gè)思想,是否可以將需要distinct的集合轉(zhuǎn)換為Set進(jìn)行存儲(chǔ),提高查找效率。

sorted()

對(duì)stream中所有的元素按照指定規(guī)則進(jìn)行排序,返回新的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 sortedLogs = logs.stream()

.sorted((RescheduleLog i1, RescheduleLog i2) -> i2.getRecordTime().compareTo(i1.getRecordTime()))

.collect(Collectors.toList());

CR片段三:上面的片段可以按照該規(guī)范,簡(jiǎn)化代碼。

List orderedDescList = rescheduleIssueBills.stream()

.sorted(Comparator.comparing(RescheduleIssueBill::getIssueBillID).reversed())

.collect(Collectors.toList());

CR片段四

List orderedDescList = rescheduleIssueBills

.stream()

.sorted(Comparator.comparing(RescheduleIssueBill::getIssueBillID).reversed())

.collect(Collectors.toList());

代碼優(yōu)化:如果不需要保留原始列表的順序,可以直接對(duì)original進(jìn)行排序,避免創(chuàng)建額外的心列表。

original.sort(Comparator.comparing(SegmentInfo::getSortedSequence));

peek()

對(duì)stream流中的每個(gè)元素進(jìn)行逐個(gè)遍歷處理,返回處理后的stream流。意味著peek只能作為管道中途的一個(gè)處理步驟,而沒(méi)法直接執(zhí)行得到結(jié)果,其后面必須還要有其它終止操作的時(shí)候才會(huì)被執(zhí)行;而foreach作為無(wú)返回值的終止方法,則可以直接執(zhí)行相關(guān)操作。

CR過(guò)程中使用peek的代碼,peek么有問(wèn)題,但是代碼還是有一定的優(yōu)化空間。

List auditSuccessList = auditInfoList.stream()

.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());

我們給一個(gè)更優(yōu)雅的代碼:

List auditSuccessList = auditInfoList.stream()

.filter(auditInfo -> AllianceAuditStatusEnum.AUDIT_SUCCESS.getValue().equals(auditInfo.getAuditStatus()))

.peek(auditInfo -> auditInfo.setCustomKey(idxAtomic.getAndIncrement()))

.collect(Collectors.toList());

三、終止Stream

通過(guò)終止管道操作之后,Stream流將會(huì)結(jié)束,最后可能會(huì)執(zhí)行某些邏輯處理,或者是按照要求返回某些執(zhí)行后的結(jié)果數(shù)據(jù)。

count()

返回stream處理后最終的元素個(gè)數(shù)。

CR時(shí)可優(yōu)化的代碼片段:

groupByDataType.entrySet().stream()

.allMatch(entry -> entry.getValue().stream()

.map(DiscountInfo::getDeductionAmount)

.distinct()

.count() == 1);

代碼優(yōu)化:上述代碼distinct與count結(jié)合使用時(shí),可以使用Set與length()方法實(shí)現(xiàn),但是這里使用count和distinct可能從業(yè)務(wù)上理解更為接近,所以具體需要根據(jù)業(yè)務(wù)場(chǎng)景決定。

boolean allMatch = groupByDataType.entrySet().stream()

.allMatch(entry -> entry.getValue().stream()

.map(DiscountInfo::getDeductionAmount)

.collect(Collectors.toSet())

.size() == 1);

但是這里可以根據(jù)allMatch的特性上進(jìn)行優(yōu)化,只要找到一個(gè)不滿足條件的金額,就提前返回false提交性能。

boolean allMatch = groupByDataType.entrySet().stream()

.allMatch(entry -> {

Set deductionAmounts = entry.getValue().stream()

.map(DiscountInfo::getDeductionAmount)

.collect(Collectors.toSet());

return deductionAmounts.size() == 1;

});

max()

返回stream處理后的元素最大值。

CR時(shí)可優(yōu)化的代碼片段:

files.stream()

.mapToInt(UploadRetireMaterialInfoType::getBatchNo)

.max()

.getAsInt();

代碼優(yōu)化:這里主要的問(wèn)題是,再調(diào)用getAsInt()方法時(shí),一定要判斷下是否存在,否則回報(bào)異常。

OptionalInt maxBatchNoOptional = files.stream()

.mapToInt(UploadRetireMaterialInfoType::getBatchNo)

.max();

if (maxBatchNoOptional.isPresent()) {

int maxBatchNo = maxBatchNoOptional.getAsInt();

} else {

......

}

min()

返回stream處理后的元素最小值。

CR過(guò)程中發(fā)現(xiàn)可以使用min()方法進(jìn)行優(yōu)化的代碼片段

List sortRefundDetails = refundDetails.stream()

.sorted(Comparator.comparing(SFltticketStudentByairlineMy::getSequence))

.collect(toList());

SFltticketStudentByairlineMy firstSeqTicketNo = sortRefundDetails.get(0);

優(yōu)化后代碼如下:

refundDetails.stream()

.min(Comparator.comparing(SFltticketStudentByairlineMy::getSequence));

findFirst()

找到第一個(gè)符合條件的元素時(shí)則終止流處理。

優(yōu)化片段一:

CR時(shí)發(fā)現(xiàn).findFirst()返回Optional可以繼續(xù)進(jìn)行業(yè)務(wù)處理,存在一定的優(yōu)化空間。代碼如下:

oc.getOrderInfoList().stream()

.filter(f -> (StringUtilsExt.compareIgnoreSpaceAndCaps(f.getFlight(), lastTrip.getFlightNo())

......)

.findFirst().orElse(null);

if (lastFlight != null) {

......

}

可以在findFirst()方法后繼續(xù)執(zhí)行操作,而不需要單獨(dú)的if (lastFlight != null)語(yǔ)句。流式編程提供了ifPresent方法,可以讓你在找到符合條件的元素時(shí)執(zhí)行某些操作。這樣使代碼更加簡(jiǎn)潔和流暢,不需要顯式地進(jìn)行空值檢查。

oc.getOrderInfoList().stream()

.filter(f -> (StringUtilsExt.compareIgnoreSpaceAndCaps(f.getFlight(), lastTrip.getFlightNo())

......)

.findFirst()

.ifPresent(lastFlight -> {

// 在這里執(zhí)行你需要的操作

// 例如:

// System.out.println("Found flight: " + lastFlight);

});

優(yōu)化片段二:

對(duì).findFirst()方法使用存在優(yōu)化空間

List sortRefundDetails = refundDetails.stream()

.sorted(Comparator.comparing(SFltticketStudentByairlineMy::getSequence))

.collect(toList());

SFltticketStudentByairlineMy firstSeqTicketNo = sortRefundDetails.get(0);

使用.findFirst()方法獲取第一個(gè)符合要求的元素即可。當(dāng)然這個(gè)代碼還存在優(yōu)化空間。

SFltticketStudentByairlineMy firstSeqTicketNo = refundDetails.stream()

.sorted(Comparator.comparing(SFltticketStudentByairlineMy::getSequence))

.collect(toList())

.findFirst();

findAny()

找到任何一個(gè)符合條件的元素時(shí)則退出流處理,這個(gè)對(duì)于串行流時(shí)與findFirst相同,對(duì)于并行流時(shí)比較高效,任何分片中找到都會(huì)終止后續(xù)計(jì)算邏輯。

CR時(shí)可優(yōu)化的代碼片段:

orderInfo.getRefundInfoList().stream()

.filter(a -> MATERIAL_SUPPLEMENT_FLAG.equals(a.getKey()) && TRUE_VALUE.equals(a.getValue()))

.findAny()

.isPresent();

優(yōu)化代碼:返回的是一個(gè)boolean類型,可以直接使用anyMatch()

boolean isPresent = orderInfo.getRefundOrderFlagInfoList().stream()

.anyMatch(a -> MATERIAL_SUPPLEMENT_FLAG.equals(a.getKey()) && TRUE_VALUE.equals(a.getValue()));

anyMatch()

返回一個(gè)boolean值,類似于isContains(),用于判斷是否有符合條件的元素。

我們也會(huì)將寫的標(biāo)準(zhǔn)的代碼推薦給大家

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()

返回一個(gè)boolean值,用于判斷是否所有元素都符合條件。

在CR中發(fā)現(xiàn)可以優(yōu)化的代碼:在流操作中fucLi部分存在優(yōu)化空間。

private Stream doFilter(List sourceList) {

return sourceList.stream()

.filter(

source -> {

List> fucLi =

buildFilterConditions(source);

return fucLi.stream().allMatch(Supplier::get);

});

}

代碼是一個(gè)過(guò)濾方法,它將一個(gè)List轉(zhuǎn)換為一個(gè)Stream,并根據(jù)某些條件對(duì)其進(jìn)行過(guò)濾。具體來(lái)說(shuō),它使用了buildFilterConditions方法來(lái)生成一組Supplier,然后檢查這些條件是否都滿足。如果所有條件都滿足,則保留該元素。

優(yōu)化后的代碼:將fucLi變量?jī)?nèi)聯(lián)到filter方法中,減少了不必要的局部變量聲明,使代碼更加簡(jiǎn)潔。

private Stream doFilter(List sourceList) {

return sourceList.stream()

.filter(source -> buildFilterConditions(source).stream().allMatch(Supplier::get));

}

noneMatch()

返回一個(gè)boolean值, 用于判斷是否所有元素都不符合條件。

CR時(shí)可優(yōu)化的代碼片段:

boolean userBehaviorsCheck = filterRecordList.stream().noneMatch(record -> IntegerUtils.compare(record.getPageCode(), 201));

collect()

將流轉(zhuǎn)換為指定的類型,通過(guò)Collectors進(jìn)行指定。

toArray()

將流轉(zhuǎn)換為數(shù)組。

iterator()

將流轉(zhuǎn)換為Iterator對(duì)象。

CR時(shí)可優(yōu)化的代碼片段:

Iterator iterator = passengers.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)化后的代碼:主要任務(wù)是從passengers列表中移除那些在passengers2列表中沒(méi)有匹配的乘客??梢酝ㄟ^(guò)集合操作來(lái)簡(jiǎn)化和優(yōu)化這段代碼。

passengers.removeIf(passenger ->

passengers2.stream()

.noneMatch(p -> p.getPassengerName() != null

&& p.getPassengerName().equalsIgnoreCase(passenger.getPassengerName()))

);

foreach()

無(wú)返回值,對(duì)元素進(jìn)行逐個(gè)遍歷,然后執(zhí)行給定的處理邏輯。foreach()操作與parallelStream()搭配使用時(shí),必須保證是線程安全的。也不要直接使用默認(rèn)的線程池。

CR時(shí)可優(yōu)化的代碼片段:

parameterList.forEach(param -> orderIds.append(param.getOrderID()).append(","));

優(yōu)化后的代碼:Collectors.joining(",")最適合做上述的工作,應(yīng)該是首先想到的。

String orderIds = parameterList.stream()

.map(param -> param.getOrderID())

.collect(Collectors.joining(","));

常見(jiàn)問(wèn)題

一旦一個(gè)Stream被執(zhí)行了終止操作之后,后續(xù)便不可以再讀這個(gè)流執(zhí)行其他的操作了,否則會(huì)報(bào)錯(cuò),看下面示例:

public void testHandleStreamAfterClosed() {

List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");

Stream stream = ids.stream().filter(s -> s.length() > 2);

// 統(tǒng)計(jì)stream操作后剩余的元素個(gè)數(shù)

System.out.println(stream.count());

System.out.println("-----下面會(huì)報(bào)錯(cuò)-----");

// 判斷是否有元素值等于205

try {

System.out.println(stream.anyMatch("205"::equals));

} catch (Exception e) {

e.printStackTrace();

System.out.println(e.toString());

}

System.out.println("-----上面會(huì)報(bào)錯(cuò)-----");

}

結(jié)果:

-----下面會(huì)報(bào)錯(cuò)-----

java.lang.IllegalStateException: stream has already been operated upon or closed

-----上面會(huì)報(bào)錯(cuò)-----

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)

因?yàn)閟tream已經(jīng)被執(zhí)行count()終止方法了,所以對(duì)stream再執(zhí)行anyMatch方法的時(shí)候,就會(huì)報(bào)錯(cuò)stream has already been operated upon or closed,這一點(diǎn)在使用的時(shí)候需要特別注意。

四、collect方法

獲取一個(gè)集合類的結(jié)果對(duì)象,比如List、Set或者HashMap等。

Collectors.toList()

List collectList = normalOfferModelList

.stream()

.filter(offer -> offer.getCate1LevelId().equals("11"))

.collect(Collectors.toList());

Collectors.toSet()

Set collectSet = normalOfferModelList

.stream()

.filter(offer -> offer.getCate1LevelId().equals("22"))

.collect(Collectors.toSet());

Collectors.toMap

CodeReview 時(shí)發(fā)現(xiàn)的問(wèn)題:沒(méi)有考慮key重復(fù)問(wèn)題。

Arrays.stream(clazz.getDeclaredFields())

.collect(Collectors.toMap(r -> r.getName().toLowerCase(), r -> r));

優(yōu)化后的代碼:Function.identity()是java.util.function.Function接口中的一個(gè)靜態(tài)方法。它總是返回一個(gè)其輸入?yún)?shù)的函數(shù)。這在需要傳遞一個(gè)不做任何變換的函數(shù)時(shí)非常有用。Function.identity()等價(jià)于上面的r -> r。(k1, k2) -> k2就是解決重復(fù)key的問(wèn)題,當(dāng)存在重復(fù)key時(shí)使用最后一個(gè)key。

Arrays.stream(clazz.getDeclaredFields())

.collect(NormalOfferModel::getName, Function.identity(), (k1, k2) -> k2));

Collectors.joining

List ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");

String joinResult = ids.stream().collect(Collectors.joining(","));

Collectors.averagingInt

List ids = Arrays.asList(10, 20, 30, 40, 50);

// 計(jì)算平均值

Double average = ids.stream().collect(Collectors.averagingInt(value -> value));

Collectors.summarizingInt

List ids = Arrays.asList(10, 20, 30, 40, 50);

// 數(shù)據(jù)統(tǒng)計(jì)信息

IntSummaryStatistics summary = ids.stream().collect(Collectors.summarizingInt(value -> value));

Optional 類

ifPresent(Consumer action)

如果Optional中包含值,執(zhí)行給定的Consumer操作,否則什么也不做。常用于簡(jiǎn)化代碼,避免顯式的空值檢查。

isPresent()

檢查Optional中是否包含值。如果包含值,返回true,否則返回false。

get()

如果Optional中包含值,返回該值;否則拋出NoSuchElementException。這個(gè)方法不推薦頻繁使用,因?yàn)樗`背了Optional的初衷,即避免顯式的空值檢查和異常處理。

orElse(T other)

如果Optional中包含值,返回該值;否則返回other。常用于提供默認(rèn)值。

orElseGet(Supplier other)

如果Optional中包含值,返回該值;否則通過(guò)調(diào)用Supplier獲取一個(gè)默認(rèn)值。與orElse不同的是,Supplier只有在需要時(shí)才會(huì)被調(diào)用,因此適用于生成默認(rèn)值開銷較大的情況。

isEmpty()

檢查Optional中是否為空。如果為空,返回true,否則返回false。

orElseThrow()

如果Optional中包含值,返回該值;否則拋出NoSuchElementException。

optional.orElseThrow(() -> new IllegalArgumentException("Value is absent"));

orElseThrow(Supplier exceptionSupplier)

如果Optional中包含值,返回該值;否則通過(guò)Supplier拋出指定的異常。

filter(Predicate predicate)

如果Optional中包含值,并且該值滿足給定的謂詞,返回一個(gè)包含該值的Optional;否則返回一個(gè)空的Optional。常用于條件過(guò)濾。

Optional filtered = optional.filter(value -> value.length() > 3);

map(Function mapper)

如果Optional中包含值,應(yīng)用給定的函數(shù)并返回一個(gè)包含映射結(jié)果的Optional;否則返回一個(gè)空的Optional。常用于鏈?zhǔn)秸{(diào)用。

Optional length = optional.map(String::length);

flatMap(Function> mapper)

與map類似,但mapper函數(shù)返回的是一個(gè)Optional對(duì)象,并且不會(huì)對(duì)返回的Optional進(jìn)行嵌套。

Optional name = optional.flatMap(value -> Optional.of("Processed " + value));

柚子快報(bào)邀請(qǐng)碼778899分享:數(shù)據(jù)庫(kù) Stream 流式編程

http://yzkb.51969.com/

推薦鏈接

評(píng)論可見(jiàn),查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://m.gantiao.com.cn/post/19472475.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問(wèn)

文章目錄