Stream流
目錄
1.概述:
1.1為什么學(xué)Stream流?
1.2?函數(shù)式編程思想
1.2.1?概念
1.2.2?優(yōu)點
2.?Lambda表達(dá)式
2.1?概述
2.2?核心原則
2.3?基本格式
例一
例二
例三
2.4?省略規(guī)則
3.?Stream流
3.1?概述
3.2?案例數(shù)據(jù)準(zhǔn)備
3.3?快速入門
3.3.1?需求
3.3.2?實現(xiàn)
3.4?常用操作
3.4.1?創(chuàng)建流
3.4.2?中間操作
filter
map
distinct
sorted
limit
skip
flatMap
3.4.3?終結(jié)操作
forEach
count
max&min
collect
3.4.4查找與匹配
anyMatch
allMatch
noneMatch
findAny
findFirst
reduce歸并
3.5?注意事項
1.概述:
Java8的Stream使用的是函數(shù)式編程模式,如同它的名字一樣,它可以被用來對集合或數(shù)組進(jìn)行鏈狀流式的操作。可以更方便的讓我們對集合或數(shù)組操作。
1.1為什么學(xué)Stream流?
給出以下代碼做出比較就知道了!
List<Book> bookList = new ArrayList<>(); Set<Book> uniqueBookValues = new HashSet<>(); Set<Author> uniqueAuthorValues = new HashSet<>(); for (Author author : authors) {if (uniqueAuthorValues.add(author)) {if (author.getAge() < 18) {List<Book> books = author.getBooks();for (Book book : books) {if (book.getScore() > 70) {if (uniqueBookValues.add(book)) {bookList.add(book);}}}}} } System.out.println(bookList); List<Book> collect = authors.stream().distinct().filter(author -> author.getAge() < 18).map(author -> author.getBooks()).flatMap(Collection::stream).filter(book -> book.getScore() > 70).distinct().collect(Collectors.toList()); System.out.println(collect);同樣的操作前者if-else嵌套過多,代碼冗余
后者代碼清晰明了,沒有嵌套地獄。
1.2?函數(shù)式編程思想
1.2.1?概念
面向?qū)ο笏枷胄枰P(guān)注用什么對象完成什么事情。而函數(shù)式編程思想就類似于我們數(shù)學(xué)中的函數(shù)。它主要關(guān)注的是對數(shù)據(jù)進(jìn)行了什么操作。
1.2.2?優(yōu)點
-
代碼簡潔,開發(fā)快速
-
接近自然語言,易于理解
-
易于"并發(fā)編程"
2.?Lambda表達(dá)式
2.1?概述
Lambda是JDK8中一個語法糖。他可以對某些匿名內(nèi)部類的寫法進(jìn)行簡化。它是函數(shù)式編程思想的一個重要體現(xiàn)。讓我們不用關(guān)注是什么對象。而是更關(guān)注我們對數(shù)據(jù)進(jìn)行了什么操作。
2.2?核心原則
可推導(dǎo)可省略
2.3?基本格式
(參數(shù)列表)->{代碼}
例一
我們在創(chuàng)建線程并啟動時可以使用匿名內(nèi)部類的寫法:
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("你知道嗎 我比你想象的 更想在你身邊");} }).start();可以使用Lambda的格式對其進(jìn)行修改。修改后如下:
new Thread(()->{System.out.println("你知道嗎 我比你想象的 更想在你身邊"); }).start();例二
現(xiàn)有方法定義如下,其中IntBinaryOperator是一個接口。
先使用匿名內(nèi)部類的寫法調(diào)用該方法。
public static int calculateNum(IntBinaryOperator operator){int a = 10;int b = 20;return operator.applyAsInt(a, b);}public static void main(String[] args) {int i = calculateNum(new IntBinaryOperator() {@Overridepublic int applyAsInt(int left, int right) {return left + right;}});System.out.println(i);}Lambda寫法:
public static void main(String[] args) {int i = calculateNum((int left, int right)->{return left + right;});System.out.println(i);}例三
現(xiàn)有方法定義如下,其中IntPredicate是一個接口。先使用匿名內(nèi)部類的寫法調(diào)用該方法。
public static void printNum(IntPredicate predicate){int[] arr = {1,2,3,4,5,6,7,8,9,10};for (int i : arr) {if(predicate.test(i)){System.out.println(i);}}}public static void main(String[] args) {printNum(new IntPredicate() {@Overridepublic boolean test(int value) {return value%2==0;}});}Lambda寫法:
public static void main(String[] args) {printNum((int value)-> {return value%2==0;});}public static void printNum(IntPredicate predicate){int[] arr = {1,2,3,4,5,6,7,8,9,10};for (int i : arr) {if(predicate.test(i)){System.out.println(i);}}}2.4?省略規(guī)則
-
參數(shù)類型可以省略
-
方法體只有一句代碼時大括號return和唯一一句代碼的分號可以省略
-
方法只有一個參數(shù)時小括號可以省略
3.?Stream流
3.1?概述
Java8的Stream使用的是函數(shù)式編程模式,如同它的名字一樣,它可以被用來對集合或數(shù)組進(jìn)行鏈狀流式的操作。可以更方便的讓我們對集合或數(shù)組操作。
3.2?案例數(shù)據(jù)準(zhǔn)備
~~~~xml<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.16</version></dependency></dependencies> ~~~~~~~~java @Data @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode//用于后期的去重使用 public class Author {//idprivate Long id;//姓名private String name;//年齡private Integer age;//簡介private String intro;//作品private List<Book> books; } ~~~~~~~~java @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode//用于后期的去重使用 public class Book {//idprivate Long id;//書名private String name;//分類private String category;//評分private Integer score;//簡介private String intro;} ~~~~~~~~javaprivate static List<Author> getAuthors() {//數(shù)據(jù)初始化Author author = new Author(1L,"蒙多",33,"一個從菜刀中明悟哲理的祖安人",null);Author author2 = new Author(2L,"亞拉索",15,"狂風(fēng)也追逐不上他的思考速度",null);Author author3 = new Author(3L,"易",14,"是這個世界在限制他的思維",null);Author author4 = new Author(3L,"易",14,"是這個世界在限制他的思維",null);//書籍列表List<Book> books1 = new ArrayList<>();List<Book> books2 = new ArrayList<>();List<Book> books3 = new ArrayList<>();books1.add(new Book(1L,"刀的兩側(cè)是光明與黑暗","哲學(xué),愛情",88,"用一把刀劃分了愛恨"));books1.add(new Book(2L,"一個人不能死在同一把刀下","個人成長,愛情",99,"講述如何從失敗中明悟真理"));books2.add(new Book(3L,"那風(fēng)吹不到的地方","哲學(xué)",85,"帶你用思維去領(lǐng)略世界的盡頭"));books2.add(new Book(3L,"那風(fēng)吹不到的地方","哲學(xué)",85,"帶你用思維去領(lǐng)略世界的盡頭"));books2.add(new Book(4L,"吹或不吹","愛情,個人傳記",56,"一個哲學(xué)家的戀愛觀注定很難把他所在的時代理解"));books3.add(new Book(5L,"你的劍就是我的劍","愛情",56,"無法想象一個武者能對他的伴侶這么的寬容"));books3.add(new Book(6L,"風(fēng)與劍","個人傳記",100,"兩個哲學(xué)家靈魂和肉體的碰撞會激起怎么樣的火花呢?"));books3.add(new Book(6L,"風(fēng)與劍","個人傳記",100,"兩個哲學(xué)家靈魂和肉體的碰撞會激起怎么樣的火花呢?"));author.setBooks(books1);author2.setBooks(books2);author3.setBooks(books3);author4.setBooks(books3);List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));return authorList;} ~~~~3.3?快速入門
3.3.1?需求
我們可以調(diào)用getAuthors方法獲取到作家的集合。現(xiàn)在需要打印所有年齡小于18的作家的名字,并且要注意去重。
3.3.2?實現(xiàn)
//打印所有年齡小于18的作家的名字,并且要注意去重List<Author> authors = getAuthors();authors.stream()//把集合轉(zhuǎn)換成流.distinct()//先去除重復(fù)的作家.filter(author -> author.getAge()<18)//篩選年齡小于18的.forEach(author -> System.out.println(author.getName()));//遍歷打印名字3.4?常用操作
3.4.1?創(chuàng)建流
單列集合:?`集合對象.stream()`
List<Author> authors = getAuthors();Stream<Author> stream = authors.stream();數(shù)組:`Arrays.stream(數(shù)組)?`或者使用`Stream.of`來創(chuàng)建
Integer[] arr = {1,2,3,4,5};Stream<Integer> stream = Arrays.stream(arr);Stream<Integer> stream2 = Stream.of(arr);雙列集合:轉(zhuǎn)換成單列集合后再創(chuàng)建
Map<String,Integer> map = new HashMap<>();map.put("蠟筆小新",19);map.put("黑子",17);map.put("日向翔陽",16);Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();3.4.2?中間操作
filter
可以對流中的元素進(jìn)行條件過濾,符合過濾條件的才能繼續(xù)留在流中。
例如:
????打印所有姓名長度大于1的作家的姓名
List<Author> authors = getAuthors();authors.stream().filter(author -> author.getName().length()>1).forEach(author -> System.out.println(author.getName()));map
可以把對流中的元素進(jìn)行計算或轉(zhuǎn)換。
例如:
????打印所有作家的姓名
List<Author>?authors?=?getAuthors();authors.stream().map(author?->?author.getName()).forEach(name->System.out.println(name));distinct
可以去除流中的重復(fù)元素。
例如:
????打印所有作家的姓名,并且要求其中不能有重復(fù)元素。
List<Author> authors = getAuthors();authors.stream().distinct().forEach(author -> System.out.println(author.getName()));注意:distinct方法是依賴Object的equals方法來判斷是否是相同對象的。所以需要注意重寫equals方法。
sorted
例如:
????對流中的元素按照年齡進(jìn)行降序排序,并且要求不能有重復(fù)的元素。
List<Author> authors = getAuthors(); // 對流中的元素按照年齡進(jìn)行降序排序,并且要求不能有重復(fù)的元素。authors.stream().distinct().sorted().forEach(author -> System.out.println(author.getAge()));List<Author> authors = getAuthors(); // 對流中的元素按照年齡進(jìn)行降序排序,并且要求不能有重復(fù)的元素。authors.stream().distinct().sorted((o1, o2) -> o2.getAge()-o1.getAge()).forEach(author -> System.out.println(author.getAge()));注意:如果調(diào)用空參的sorted()方法,需要流中的元素是實現(xiàn)了Comparable。
limit
可以設(shè)置流的最大長度,超出的部分將被拋棄。
例如:
????對流中的元素按照年齡進(jìn)行降序排序,并且要求不能有重復(fù)的元素,然后打印其中年齡最大的兩個作家的姓名。
List<Author> authors = getAuthors();authors.stream().distinct().sorted().limit(2).forEach(author -> System.out.println(author.getName()));skip
跳過流中的前n個元素,返回剩下的元素
例如:
????打印除了年齡最大的作家外的其他作家,要求不能有重復(fù)元素,并且按照年齡降序排序。
List<Author> authors = getAuthors();authors.stream().distinct().sorted().skip(1).forEach(author -> System.out.println(author.getName()));flatMap
map只能把一個對象轉(zhuǎn)換成另一個對象來作為流中的元素。而flatMap可以把一個對象轉(zhuǎn)換成多個對象作為流中的元素。
例一:
????打印所有書籍的名字。要求對重復(fù)的元素進(jìn)行去重。
List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBooks().stream()).distinct().forEach(book -> System.out.println(book.getName()));例二:
????打印現(xiàn)有數(shù)據(jù)的所有分類。要求對分類進(jìn)行去重。不能出現(xiàn)這種格式:哲學(xué),愛情
List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBooks().stream()).distinct().flatMap(book -> Arrays.stream(book.getCategory().split(","))).distinct().forEach(category-> System.out.println(category));3.4.3?終結(jié)操作
forEach
對流中的元素進(jìn)行遍歷操作,我們通過傳入的參數(shù)去指定對遍歷到的元素進(jìn)行什么具體操作。
例子:
????輸出所有作家的名字
List<Author> authors = getAuthors();authors.stream().map(author -> author.getName()).distinct().forEach(name-> System.out.println(name));count
可以用來獲取當(dāng)前流中元素的個數(shù)。
例子:
????打印這些作家的所出書籍的數(shù)目,注意刪除重復(fù)元素。
List<Author> authors = getAuthors();long count = authors.stream().flatMap(author -> author.getBooks().stream()).distinct().count();System.out.println(count);max&min
可以用來或者流中的最值。
例子:
????分別獲取這些作家的所出書籍的最高分和最低分并打印。
List<Author> authors = getAuthors();Optional<Integer> max = authors.stream().flatMap(author -> author.getBooks().stream()).map(book -> book.getScore()).max((score1, score2) -> score1 - score2);Optional<Integer> min = authors.stream().flatMap(author -> author.getBooks().stream()).map(book -> book.getScore()).min((score1, score2) -> score1 - score2);System.out.println(max.get());System.out.println(min.get());collect
把當(dāng)前流轉(zhuǎn)換成一個集合。
例子:
獲取一個存放所有作者名字的List集合。
List<Author> authors = getAuthors();List<String> nameList = authors.stream().map(author -> author.getName()).collect(Collectors.toList());System.out.println(nameList);獲取一個所有書名的Set集合。
List<Author> authors = getAuthors();Set<Book> books = authors.stream().flatMap(author -> author.getBooks().stream()).collect(Collectors.toSet());System.out.println(books);獲取一個Map集合,map的key為作者名,value為List<Book>
List<Author> authors = getAuthors();Map<String, List<Book>> map = authors.stream().distinct().collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));System.out.println(map);3.4.4查找與匹配
anyMatch
可以用來判斷是否有任意符合匹配條件的元素,結(jié)果為boolean類型。
例子:
????判斷是否有年齡在29以上的作家
List<Author> authors = getAuthors();boolean flag = authors.stream().anyMatch(author -> author.getAge() > 29);System.out.println(flag);allMatch
可以用來判斷是否都符合匹配條件,結(jié)果為boolean類型。如果都符合結(jié)果為true,否則結(jié)果為false。
例子:
????判斷是否所有的作家都是成年人
List<Author> authors = getAuthors();boolean flag = authors.stream().allMatch(author -> author.getAge() >= 18);System.out.println(flag);noneMatch
可以判斷流中的元素是否都不符合匹配條件。如果都不符合結(jié)果為true,否則結(jié)果為false
例子:
????判斷作家是否都沒有超過100歲的。
List<Author> authors = getAuthors();boolean b = authors.stream().noneMatch(author -> author.getAge() > 100);System.out.println(b);findAny
獲取流中的任意一個元素。該方法沒有辦法保證獲取的一定是流中的第一個元素。
例子:
????獲取任意一個年齡大于18的作家,如果存在就輸出他的名字
List<Author> authors = getAuthors();Optional<Author> optionalAuthor = authors.stream().filter(author -> author.getAge()>18).findAny();optionalAuthor.ifPresent(author -> System.out.println(author.getName()));findFirst
獲取流中的第一個元素。
例子:
????獲取一個年齡最小的作家,并輸出他的姓名。
List<Author> authors = getAuthors();Optional<Author> first = authors.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).findFirst();first.ifPresent(author -> System.out.println(author.getName()));reduce歸并
????對流中的數(shù)據(jù)按照你指定的計算方式計算出一個結(jié)果。(縮減操作)
????reduce的作用是把stream中的元素給組合起來,我們可以傳入一個初始值,它會按照我們的計算方式依次拿流中的元素和初始化值進(jìn)行計算,計算結(jié)果再和后面的元素計算。
????reduce兩個參數(shù)的重載形式內(nèi)部的計算方式如下:
T result = identity; for (T element : this stream)result = accumulator.apply(result, element) return result;????其中identity就是我們可以通過方法參數(shù)傳入的初始值,accumulator的apply具體進(jìn)行什么計算也是我們通過方法參數(shù)來確定的。
例子:
????使用reduce求所有作者年齡的和
List<Author> authors = getAuthors();Integer sum = authors.stream().distinct().map(author -> author.getAge()).reduce(0, (result, element) -> result + element);System.out.println(sum);????使用reduce求所有作者中年齡的最大值
List<Author> authors = getAuthors();Integer max = authors.stream().map(author -> author.getAge()).reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);System.out.println(max);????使用reduce求所有作者中年齡的最小值
List<Author> authors = getAuthors();Integer min = authors.stream().map(author -> author.getAge()).reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);System.out.println(min);????reduce一個參數(shù)的重載形式內(nèi)部的計算
boolean foundAny = false;T result = null;for (T element : this stream) {if (!foundAny) {foundAny = true;result = element;}elseresult = accumulator.apply(result, element);}return foundAny ? Optional.of(result) : Optional.empty();????如果用一個參數(shù)的重載方法去求最小值代碼如下:
List<Author> authors = getAuthors();Optional<Integer> minOptional = authors.stream().map(author -> author.getAge()).reduce((result, element) -> result > element ? element : result);minOptional.ifPresent(age-> System.out.println(age));3.5?注意事項
-
惰性求值(如果沒有終結(jié)操作,沒有中間操作是不會得到執(zhí)行的)
-
流是一次性的(一旦一個流對象經(jīng)過一個終結(jié)操作后。這個流就不能再被使用)
-
不會影響原數(shù)據(jù)(我們在流中可以多數(shù)據(jù)做很多處理。但是正常情況下是不會影響原來集合中的元素的。這往往也是我們期望的)
總結(jié)
- 上一篇: 函数式编程--三更
- 下一篇: PDF文件编辑密码解除