最近的需求裡有這樣一個場景,要校驗一個集合中每個物件的多個Id的有效性。比如一個Customer物件,有3個Id:id1
,id2
,id3
,要把這些Id全部取出來,然後去資料庫裡查詢它是否存在。
@Data
@AllArgsConstructor
public class Customer {
private String name;
private String id1;
private String id2;
private String id3;
}
在通常情況下,我們要從集合中取出一個物件屬性,很好辦,用這個辦法:
customerList.stream().map(Customer::getId1).filter(Objects::nonNull).collect(Collectors.toList())
現在要取3個欄位,怎麼做呢?
Stream.concat
Stream介面中的靜態方法concat,可以把兩個流合成一個,我們取3個欄位可以合併兩次:
Stream<String> concat = Stream.concat(customerList.stream().map(Customer::getId1),
customerList.stream().map(Customer::getId2));
List<String> ids = Stream.concat(concat, customerList.stream().map(Customer::getId3))
.filter(Objects::nonNull)
.collect(Collectors.toList());
取4個欄位,就再繼續合併。但是這種不夠簡潔,可以使用扁平化流flatMap。
flatMap
flatmap方法讓你把一個流中的每個值都換成另一個流,然後把所有的流連線起來成為一個流。
Stream.flatMap
方法的入參為一個Function函式,函式返回值的泛型要求為Stream型別。對比一下,map
和flatMap
都是將流中的元素對映為我們想要的值,只是flatMap
對映的結果是一個新的Stream。
而Stream.of
方法剛好可以構建一個型別為Stream的原始流,以供flatMap
操作。
List<String> ids = Stream.of(customerList.stream().map(Customer::getId1),
customerList.stream().map(Customer::getId2),
customerList.stream().map(Customer::getId3))
.flatMap(idStream -> idStream)
.filter(Objects::nonNull)
.collect(Collectors.toList());
注意,Stream.of方法返回的流的泛型跟方法入參的型別是一樣,上面的程式碼就相當於,Stream.of(stream, stream, stream)
, 得到的結果就是Stream<Stream>
,緊接著用flatMap
扁平化處理,把每一個元素合成一個新流。