Stream類全路徑為:java.util.stream.Stream
Stream簡介
Java 8 中的 Stream 是對(Collection)集合對象功能的增強滑绒,它專注于對集合對象進行各種非常便利球榆、高效的聚合操作
或大批量數(shù)據(jù)操作肌毅。Stream API 借助于同樣新出現(xiàn)的 Lambda 表達式泡垃,極大的提高編程效率和程序可讀性纯衍。
Stream原理
這種編程風格將要處理的元素集合看作一種流崎弃,流在管道中傳輸乘客,并且可以在管道的節(jié)點上進行處理惶桐,比如篩選撮弧,排序潘懊,聚合等。
元素流在管道中經(jīng)過中間操作(intermediate operation)的處理贿衍,最后由最終操作(terminal operation)得到前面處理的
結(jié)果授舟。
Stream優(yōu)點
(1)速度更快
(2)代碼更少(增加了新的語法Lambda表達式)
(3)強大的Stream API
(4)便于并行
(5)最大化減少了空指針異常Optional
Stream的操作三個步驟:
(1)創(chuàng)建Stream,一個數(shù)據(jù)源(如:集合贸辈、數(shù)組)释树,獲取一個流;
(2)中間操作擎淤,一個中間操作鏈奢啥,對數(shù)據(jù)源的數(shù)據(jù)進行處理;
(3)終止操作嘴拢,一個終止操作桩盲,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果席吴。
集合有兩種方式生成流:
stream() ? 為集合創(chuàng)建串行流赌结。
parallelStream() ? 為集合創(chuàng)建并行流
-Stream的的中間操作(intermediate)和最終操作(terminal)都包含的方法:
1.中間操作(intermediate)主要有以下方法(此類型的方法返回的都是Stream對象):
方法名 | 說明 |
---|---|
map | 將對應的元素使用給定方法進行轉(zhuǎn)換 |
mapToInt(mapToLong,mapToDouble) | 將對應的元素使用給定方法進行轉(zhuǎn)換(返回類型必須是 int,long,double) |
flatMap | 如果流的元素為數(shù)組或者Collection,flatMap就是將每個Object[]元素或Collection<Object>元素都轉(zhuǎn)換為Object元素 |
filter | 通過設置條件來過濾元素 |
distinct | 集合中的元素去重 |
sorted | 將集合中的元素排序 |
peek | 生成一個包含原Stream的所有元素的新Stream孝冒,同時會提供一個消費函數(shù)即引用的方法A柬姚,當Stream每個元素被消費的時候都會先執(zhí)行新Stream給定的方法A。peek是中間操作庄涡,如果pee后沒有最終操作量承,則peek不會執(zhí)行 |
limit | 返回Stream的前n個元素 |
skip | 刪除Stream的前n個元素 |
2.終端操作(terminal)主要有以下方法:
方法名 | 說明 |
---|---|
forEach | 遍歷Stream中的每個元素 |
forEachOrdered | 遍歷Stream中的每個元素 區(qū)別: 在串行流(stream)中沒有區(qū)別,在并行流(parallelStream)中如果數(shù)據(jù)源是有序集合穴店,forEachOrdered輸出順序與數(shù)據(jù)源中順序一致宴合,forEach則是亂序。 |
toArray | 將流轉(zhuǎn)換為Object[]或者指定類型的數(shù)組 |
reduce | 將集合中的每個元素聚合成一條數(shù)據(jù) |
collect | 將流轉(zhuǎn)換成集合或聚合元素 |
min | 獲取集合中最小值 |
max | 獲取集合中最大值 |
count | 獲取集合中元素個數(shù) |
anyMatch | Stream 中任意一個元素符合傳入的 predicate迹鹅,返回 true |
allMatch | Stream 中全部元素符合傳入的 predicate,返回 true |
noneMatch | Stream 中沒有一個元素符合傳入的 predicate贞言,返回 true |
findFirst | 如果數(shù)據(jù)源是有序集合斜棚,返回Stream 中第一個元素的Optional對象,如果是無序集合该窗,則返回Stream 中任意一個元素的Optional對象弟蚀。 |
findAny | 返回Stream 中任意一個元素的Optional對象。 |
iterator | 返回一個無限元素的有序的Stream對象酗失。 |
builder | 返回一個Builder對象义钉,Builder對象在調(diào)用build()返回Stream對象。 |
empty | 返回一個空的有序的Stream對象规肴。 |
of | 返回包含單個元素的有序的Stream對象捶闸。 |
generate | 返回一個無限元素的無序的的Stream對象夜畴。 |
concat | 將兩個Stream連接成一個Stream。 |
方法演示
中間操作(intermediate)
1.filter : 通過設置條件來過濾元素删壮。
List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");
list.stream().filter((s)->s.contains("a")).forEach(s -> System.out.println(s));
以上代碼使用filter方法過濾出只包含”a”的元素贪绘,然后通過forEach將滿足條件的元素遍歷出來。輸出如下:
aaa
a2a
a3a
2.map : 就是將對應的元素使用給定方法進行轉(zhuǎn)換央碟。
List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");
list.stream().filter((s)->s.contains("a")).map((s)-> s + "---map").forEach(s -> System.out.println(s));
在filter的基礎上税灌,給每個元素后面添加字符串”—map”,輸出如下:
aaa—map
a2a—map
a3a—map
3.flatMap:如果流的元素為數(shù)組或者Collection亿虽,flatMap就是將每個Object[]元素或Collection<Object>元素都轉(zhuǎn)換為Object元素菱涤。
List<String[]> setList = new ArrayList<>();
setList.add(new String[]{"aa","bb"});
setList.add(new String[]{"cc","dd"});
setList.add(new String[]{"ee","ff"});
//使用map方法
setList.stream().map(s->Arrays.stream(s)).forEach(s-> System.out.println("map==" + s));
//使用flatMap方法
setList.stream().flatMap(s->Arrays.stream(s)).forEach(s-> System.out.println("flatMap==" + s));
輸出如下:
map==java.util.stream.ReferencePipeline&Head@50040f0c
map==java.util.stream.ReferencePipeline&Head@2dda6444
map==java.util.stream.ReferencePipeline&Head@5e9f23b4
flatMap==aa
flatMap==bb
flatMap==cc
flatMap==dd
flatMap==ee
flatMap==ff
map就是將數(shù)組流直接返回,flatMap是將數(shù)組流中的每個元素都返回洛勉。
4.distinct:將集合中的元素去重粘秆。
List<String> disList = Arrays.asList("aaa","ddd","bbb","ddd","aaa");
disList.stream().distinct().forEach(s-> System.out.println(s));
輸出如下:
aaa
ddd
bbb
5.sorted:將集合中的元素排序。
List<Integer> integerList = Arrays.asList(2,4,1,3);
integerList.stream().sorted().forEach(s-> System.out.println(s));
輸出如下:
1
2
3
4
可以按照自定義排序:
List<Integer> integerList = Arrays.asList(2,4,1,3);
integerList.stream().sorted((s1,s2)->s2.compareTo(s1)).forEach(s-> System.out.println(s));
輸出如下:
4
3
2
1
6.peek:生成一個包含原Stream的所有元素的新Stream坯认,同時會提供一個消費函數(shù)即引用的方法A翻擒,當Stream每個元素被消費的時候都會先
執(zhí)行新Stream給定的方法A。peek是中間操作牛哺,如果peek后沒有最終操作陋气,則peek不會執(zhí)行。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().peek(s-> System.out.println("peek = "+s)).forEach(s-> System.out.println("forEach = "+s));
輸出如下:
peek = 1
forEach = 1
peek = 2
forEach = 2
peek = 3
forEach = 3
peek = 4
forEach = 4
7.limit:返回Stream的前n個元素引润。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().limit(2).forEach(s-> System.out.println(s));
輸出為:
1
2
8.skip:刪除Stream的前n個元素巩趁。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().skip(2).forEach(s-> System.out.println(s));
輸出如下:
3
4
終端操作(terminal)
1.forEach:遍歷Stream中的每個元素,前面每個例子都有使用淳附,此處不再演示议慰。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().skip(2).forEach(s-> System.out.println(s));
輸出為:
1
2
3
4
2.forEachOrdered:遍歷Stream中的每個元素。
區(qū)別: 在串行流(stream)中沒有區(qū)別奴曙,在并行流(parallelStream)中如果數(shù)據(jù)源是有序集合别凹,forEachOrdered輸出順序與數(shù)據(jù)源中順序
一致,forEach則是亂序洽糟。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.parallelStream().forEachOrdered(s-> System.out.println(s));
輸出(測試多次炉菲,每次都是這個結(jié)果,與integerList中的元素順序一致):
1
2
3
4
3.toArray:將流轉(zhuǎn)換為Object[]或者指定類型的數(shù)組坤溃。
List<Integer> integerList = Arrays.asList(1,2,3,4);
Object[] array = integerList.stream().toArray();
String[] strArr = integerList.stream().toArray(String[]::new);
Stream中的toArray普通情況下和集合中的toArray沒什么區(qū)別,但是Stream中的toArray轉(zhuǎn)換為指定類型的數(shù)組拍霜。
4.reduce:將集合中的每個元素聚合成一條數(shù)據(jù)。有三種情況:
reduce(BinaryOperator accumulator):此處需要一個參數(shù)薪介,返回Optional對象:
Optional<Integer> reduce = integerList.stream().reduce((a, b) -> a + b);
reduce(T identity, BinaryOperator accumulator):此處需要兩個參數(shù)祠饺,第一個參數(shù)為起始值,第二個參數(shù)為引用的方法汁政。從起始值開始道偷,
每個元素執(zhí)行一次引用的方法(方法引用的中的兩個參數(shù):第一個參數(shù)為上個元素執(zhí)行方法引用的結(jié)果缀旁,第二個參數(shù)為當前元素)。
List<Integer> integerList = Arrays.asList(1,2,3,4);
int integer = integerList.stream().reduce(5,(a, b) -> a + b);
System.out.println(integer);
輸出為:
15
此例中使用起始值為5试疙,對集合中每個元素求和诵棵,可以理解為:5+1+2+3+4=15。
reduce:此處需要三個參數(shù)祝旷。此方法用在
并發(fā)流(parallelStream)中履澳,啟動多個子線程使用accumulator進行并行計算,最終使用combiner對子線程結(jié)果進行合并怀跛,返回identity類
型的數(shù)據(jù)距贷。
5.collect:將流轉(zhuǎn)換成集合或聚合元素。有兩種情況吻谋。接受一個參數(shù)和接受三個參數(shù)(三個參數(shù)在并發(fā)流parallelStream中使用)忠蝗,此處介紹一個參數(shù)的情況,單個參數(shù)接受的參數(shù)類型為Collector漓拾,Collectors 類實現(xiàn)了很多歸約操作
List<Integer> integerList = Arrays.asList(2,4,1,3);
List<Integer> integers = integerList.stream().filter(s -> s > 1).collect(Collectors.toList());
System.out.println(integers.toString());
此處統(tǒng)計集合中大于1的元素并最終返回list阁最。輸出如下:
[2, 4, 3]
6.min:獲取集合中最小值。
List<Integer> integerList = Arrays.asList(2,4,1,3);
Integer min = integerList.stream().min(Integer::compareTo).get();
System.out.println(min);
輸出為:
1
7.max:獲取集合中最大值骇两。
List<Integer> integerList = Arrays.asList(2,4,1,3);
Integer max = integerList.stream().max(Integer::compareTo).get();
System.out.println(max);
8.count:獲取集合中元素個數(shù)
List<Integer> integerList = Arrays.asList(2,4,1,3);
long count = integerList.stream().count();
System.out.println(count);
輸出為:
4
---------------------------------------- ----- CJZ ------ ------------------------------------------
舉例
設有一組用戶信息(userInfo:包含 姓名(name) 性別(sex) 年齡(age)),將這些用戶信息分成 男和女 存入Map(key:sex values:List<userInfo>)中.
準備數(shù)據(jù)
UserInfo實體類
class UserInfo {
private String name;
private String sex;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
獲取用戶信息
public List<UserInfo> buildUserInfoList(){
Random ra =new Random();
List<UserInfo> userInfoList = new ArrayList<>();
String first="趙錢孫李周吳鄭王馮陳褚衛(wèi)蔣沈韓楊朱秦尤許何呂施張孔";
String boy="偉剛勇毅俊峰強軍平保東文輝力明永健世廣志義興良海山仁";
for (int i=0; i<10;i++){
UserInfo userInfo = new UserInfo();
int sum1 = ra.nextInt(first.length());
int sum2 = ra.nextInt(boy.length());
userInfo.setName(first.substring(sum1,sum1+1)+boy.substring(sum2,sum2+1));
userInfo.setSex(sum1%2==0 ? "男":"女");
userInfo.setAge(ra.nextInt(100));
userInfoList.add(userInfo);
}
return userInfoList;
}
代碼實現(xiàn)
普通實現(xiàn)方式
public void userInfoClassify(){
List<UserInfo> userInfoList = buildUserInfoList();
Map<String, List<UserInfo>> map = new HashMap();
List<UserInfo> male =new ArrayList<>();
List<UserInfo> female =new ArrayList<>();
for (UserInfo userInfo:userInfoList){
if("女".equals(userInfo.getSex())){
female.add(userInfo);
}else ("男".equals(userInfo.getSex())){
male.add(userInfo);
}
}
map.put("男",male);
map.put("女",female);
}
stream實現(xiàn)方式
public void userInfoClassifyStream() {
List<UserInfo> userInfoList = buildUserInfoList();
Map<String, List<UserInfo>> collect = userInfoList.stream().collect(Collectors.groupingBy(UserInfo::getSex));
}
map 推薦遍歷方式
for (Map.Entry<String, List<UserInfo>> entry : map.entrySet()) {
System.out.println("key:"+entry.getKey()+",value:"+entry.getValue());
}