JAVA8新特性: Stream-集合流操作

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());
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末速种,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子低千,更是在濱河造成了極大的恐慌配阵,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件示血,死亡現(xiàn)場離奇詭異棋傍,居然都是意外死亡,警方通過查閱死者的電腦和手機难审,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門瘫拣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人告喊,你說我怎么就攤上這事拂铡。” “怎么了葱绒?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斗锭。 經(jīng)常有香客問我地淀,道長,這世上最難降的妖魔是什么岖是? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任帮毁,我火速辦了婚禮实苞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烈疚。我一直安慰自己黔牵,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布爷肝。 她就那樣靜靜地躺著猾浦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪灯抛。 梳的紋絲不亂的頭發(fā)上金赦,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音对嚼,去河邊找鬼夹抗。 笑死,一個胖子當著我的面吹牛纵竖,可吹牛的內(nèi)容都是我干的漠烧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼靡砌,長吁一口氣:“原來是場噩夢啊……” “哼已脓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起乏奥,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤摆舟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后邓了,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恨诱,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年骗炉,在試婚紗的時候發(fā)現(xiàn)自己被綠了照宝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡句葵,死狀恐怖厕鹃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乍丈,我是刑警寧澤剂碴,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站轻专,受9級特大地震影響忆矛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一催训、第九天 我趴在偏房一處隱蔽的房頂上張望洽议。 院中可真熱鬧,春花似錦漫拭、人聲如沸亚兄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽审胚。三九已至,卻和暖如春挑宠,著一層夾襖步出監(jiān)牢的瞬間菲盾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工各淀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留懒鉴,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓碎浇,卻偏偏與公主長得像临谱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子奴璃,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容