摘要:歸約把一個流中的元素組合起來,使用操作來表達更復雜的查詢,比如計算菜單中的總卡路里或菜單中卡路里最高的菜是哪一個。有沒有交易員是在深圳工作的打印生活在北京的交易員的所有交易額。
篩選和切片
filter 方法
distinct 方法
limit 方法
skip 方法
謂詞篩選Stream 接口支持 filter 方法,該操作會接受一個謂詞(一個返回 boolean的函數(shù))作為參數(shù),并返回一個包括所有符合謂詞的元素的流。
List篩選重復的元素dishes = Dish.menu.stream() .filter(Dish::isVegetarian) .collect(Collectors.toList());
Stream 接口支持 distinct 的方法, 它會返回一個元素各異(根據(jù)流所生成元素的 hashCode和equals方法實現(xiàn))的流。例如,以下代碼會篩選出列表中所有的偶數(shù),并確保沒有 重復。
List限制元素數(shù)量numbers = Arrays.asList(1,2,1,3,3,2,4); numbers.stream().filter(i -> i % 2 == 0) .distinct() //去重元素2 .forEach(System.out::println);
Stream 支持limit(n)方法,該方法會返回一個不超過給定長度的流。所需的長度作為參數(shù)傳遞 給limit。如果流是有序的,則最多會返回前n個元素。
List跳過指定數(shù)量的元素dishLimits = Dish.menu.stream() .filter(d -> d.getCalories() > 300) .limit(3) //只返回符合要求的前3個元素 .collect(Collectors.toList());
Stream 支持 skip(n) 方法,返回一個扔掉了前n個元素的流。如果流中元素不足n個,則返回一 個空流。limit(n) 和 skip(n) 是互補的。
List映射 map 操作dishSkip = Dish.menu.stream() .filter(d -> d.getCalories() > 300) .skip(2) //去掉符合要求的集合中的前2個元素后返回 .collect(Collectors.toList()); dishSkip.forEach(System.out::println);
Stream 支持 map 方法,它會接受一個函數(shù)作為參數(shù)。這個函數(shù)會被應用到每個元素上,并將其映 射成一個新的元素
ListflatMap 操作dishNames = Dish.menu.stream() .map(Dish::getName) .map(String::length) .collect(Collectors.toList()); List words = Arrays.asList("Hello", "World"); List wordLens = words.stream() .map(String::length) //轉(zhuǎn)為字符串長度的集合 .collect(Collectors.toList());
flatmap 方法讓你把一個流中的每個值都換成另一個流,然后把所有的流連接起來成為一個流。
//使用flatMap找出單詞列表中各不相同的字符 Listwords = Arrays.asList("Hello", "World"); List wordMap = words.stream() .map(word -> word.split("")) .flatMap(Arrays::stream) .distinct() .collect(Collectors.toList());
給定兩個數(shù)字列表,如何返回所有的數(shù)對呢?例如,給定列表[1, 2, 3]和列表[3, 4],應該返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]。
List查找和匹配 anyMatchnum1 = Arrays.asList(1, 2, 3); List num2 = Arrays.asList(4, 5); List pairs = num1.stream() .flatMap(i -> num2.stream().map(j -> new int[]{i, j})) .collect(Collectors.toList()); pairs.stream().forEach( i -> { Arrays.stream(i).forEach(System.out::println);
流中是否有一個元素能匹配給定的謂詞。
if (Dish.menu.stream().anyMatch(Dish::isVegetarian)) { System.out.println("Vegetarion"); }allMatch
流中是否有所有元素能匹配給定的謂詞。
if (Dish.menu.stream().allMatch(d -> d.getCalories() < 1000)) { System.out.println("都有利于健康"); }nonMatch
流中是否有沒有任何元素能匹配給定的謂詞。
if (Dish.menu.stream().noneMatch(d -> d.getCalories() >= 1000)) { System.out.println("都有利于健康"); }findAny
findAny 方法將返回當前流中的任意一個元素。
OptionalfindFirstdish = Dish.menu.stream().filter(Dish::isVegetarian) .findAny(); dish.ifPresent(d -> System.out.println(d.toString()));
findAny 方法將返回當前流中的第一個元素。
ListOptionalnum1 = Arrays.asList(1, 2, 3, 4, 5); num1.stream().map(x -> x * x) .filter(x -> x % 3 == 0) //平方能被3整除的數(shù) .findFirst().ifPresent(x -> System.out.println(x)); }
Optional
isPresent()將在Optional包含值的時候返回true, 否則返回false。
ifPresent(Consumer
T get()會在值存在時返回值,否則拋出一個NoSuchElement異常。
T orElse(T other)會在值存在時返回值,否則返回一個默認值。
歸約(reduce)把一個流中的元素組合起來,使用 reduce 操作來表達更復雜的查 詢,比如“計算菜單中的總卡路里”或“菜單中卡路里最高的菜是哪一個”。此類查詢需要將流中所有元素反復結(jié)合起來,得到一個值,比如一個Integer。這樣的查詢可以被歸類為歸約操作 (將流歸約成一個值)。
reduce操作是如何作用于一個流的:Lambda反復結(jié)合每個元素,直到流被歸約成一個值。reduce方法接受兩個參數(shù):一個初始值,這里是0;一個 BinaryOperator
List最大值numbers = Arrays.asList(3,4,5,1,2); int sum1 = numbers.stream().reduce(0,(a, b) -> a + b); System.out.println(sum1); int sum2 = numbers.stream().reduce(0,Integer::sum); System.out.println(sum2);
int max = numbers.stream().reduce(0,Integer::max); System.out.println(max);最小值
//reduce不接受初始值,返回一個Optional對象(考慮流中沒有任何元素的情況) Optional數(shù)值流 原始類型流特化min = numbers.stream().reduce(Integer::min); min.ifPresent(System.out::println);
Java 8引入了三個原始類型特化流接口來解決這個問題: IntStream 、 DoubleStream 和 LongStream,分別將流中的元素特化為int、long和double,從而避免了暗含的裝箱成本。每 個接口都帶來了進行常用數(shù)值歸約的新方法,比如對數(shù)值流求和的sum,找到最大元素的max。 此外還有在必要時再把它們轉(zhuǎn)換回對象流的方法。這些特化的原因并不在于流的復雜性,而是裝箱造成的復雜性——即類似int和Integer之間的效率差異。
映射到數(shù)值流:將流轉(zhuǎn)換為特化版本的常用方法是mapToInt、mapToDouble和mapToLong。這些方法和前 面說的map方法的工作方式一樣,只是它們返回的是一個特化流,而不是Stream
int colories = Dish.menu.stream() .mapToInt(Dish::getCalories) //返回IntStream .sum();
轉(zhuǎn)換回對象流
通過 box 方法可以將數(shù)值流轉(zhuǎn)化為 Stream 非特化流。
IntStream intStream = menu.stream().mapToInt(Dish::getCalories); //將Strean轉(zhuǎn)化為數(shù)值流 Streamstream = intStream.boxed(); //將數(shù)值流轉(zhuǎn)化為Stream
默認值 OptionalInt
Optional 可以用 Integer、String等參考類型來參數(shù)化。對于三種原始流特化,也分別有一個Optional原始類 型特化版本:OptionalInt、OptionalDouble和OptionalLong。
Dish.menu.stream() .mapToInt(Dish::getCalories) //返回IntStream .max().ifPresent(System.out::println);數(shù)值范圍
IntStream.rangeClosed(1, 100) .filter(x -> x % 10 == 0) .forEach(System.out::println);
Java 8引入了兩個可以用于IntStream和LongStream的靜態(tài)方法,幫助生成這種范圍: range和rangeClosed。這兩個方法都是第一個參數(shù)接受起始值,第二個參數(shù)接受結(jié)束值。但 range是不包含結(jié)束值的,而rangeClosed則包含結(jié)束值。
數(shù)值流應用:勾股數(shù)生成 (5, 12, 13)、(6, 8, 10)和(7, 24, 25) 這樣有效的勾股數(shù)數(shù)組集合。
Stream構(gòu)建流 值創(chuàng)建流pythagoreanTriples = IntStream.rangeClosed(1, 100).boxed() .flatMap(a -> IntStream.rangeClosed(a,100) .filter(b -> Math.sqrt(a * a + b * b) % 1 == 0).boxed() .map(b -> new int[]{a,b,(int)Math.sqrt(a * a + b * b)}) ); pythagoreanTriples.forEach(t -> System.out.println(t[0] + ";" + t[1] +";" + t[2]));
Stream數(shù)組創(chuàng)建流streams = Stream.of("Java", "Python"); streams.map(String::toUpperCase).forEach(System.out::println); Stream.concat(Stream.of("Java", "Python"), Stream.of("C++", "Ruby")).forEach(System.out::println);
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int sum = Arrays.stream(numbers).sum();文件生成流
String ret = Files.lines(Paths.get("/Users/liuguoquan/Java/java8/src/com/company/data.txt"), Charset.defaultCharset()) .reduce("", (a, b) -> a + " " + b);函數(shù)生成流:創(chuàng)建無限流
//迭代 Stream.iterate(0, n -> n + 2) .limit(10) .forEach(System.out::println); //生成 Stream.generate(Math::random) .limit(5) .forEach(System.out::println); }示例實戰(zhàn)
假設你是執(zhí)行交易的交易員。你的經(jīng)理讓你為八個查詢找到答案。你能做到嗎?
(1) 找出2016年發(fā)生的所有交易,并按交易額排序(從低到高)。
(2) 交易員都在哪些不同的城市工作過?
(3) 查找所有來自于北京的交易員,并按姓名排序。
(4) 返回所有交易員的姓名字符串,按字母順序排序。
(5) 有沒有交易員是在深圳工作的?
(6) 打印生活在北京的交易員的所有交易額。
(7) 所有交易中,最高的交易額是多少?
(8) 找到交易額最小的交易。
交易員類
/** * 交易人 * Created by liuguoquan on 2017/4/28. */ public class Trader { private String name; private String city; public Trader(String name, String city) { this.name = name; this.city = city; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Override public String toString() { return "Trader{" + "name="" + name + """ + ", city="" + city + """ + "}"; } }
交易類
/** * 交易單 * Created by liuguoquan on 2017/4/28. */ public class Transaction { private Trader trader; private int year; private int value; public Transaction(Trader trader, int year, int value) { this.trader = trader; this.year = year; this.value = value; } public Trader getTrader() { return trader; } public void setTrader(Trader trader) { this.trader = trader; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } @Override public String toString() { return "Transaction{" + "trader=" + trader + ", year="" + year + """ + ", value=" + value + "}"; } }
計算
public class TransactionProcess { public static void main(String[] args) { Trader liu = new Trader("Lau","Beijing"); Trader lee = new Trader("Lee","Shanghai"); Trader zhang = new Trader("Zhang","Guangzhou"); Trader wang = new Trader("Wang","Beijing"); List小結(jié)transactions = Arrays.asList( new Transaction(liu,2016,300), new Transaction(lee,2015,100), new Transaction(lee,2016,500), new Transaction(zhang,2016,9000), new Transaction(wang,2017,1000), new Transaction(liu,2016,1500) ); // (1) 找出2016年發(fā)生的所有交易,并按交易額排序(從低到高)。 transactions.stream().filter(t -> t.getYear() == 2016) .sorted(Comparator.comparing(Transaction::getValue)) .collect(Collectors.toList()); // (2) 交易員都在哪些不同的城市工作過? transactions.stream().map(t -> t.getTrader().getCity()) .distinct() .collect(Collectors.toList()); // (3) 查找所有來自于北京的交易員,并按姓名排序。 transactions.stream().map(t -> t.getTrader()) .filter(t -> t.getCity().equals("Beijing")) .distinct() .sorted(Comparator.comparing(Trader::getName)) .collect(Collectors.toList()); // (4) 返回所有交易員的姓名字符串,按字母順序排序。 transactions.stream().map(t -> t.getTrader()) .map(t -> t.getName()) .distinct() .sorted() .collect(Collectors.toList()); // (5) 有沒有交易員是在深圳工作的? boolean isExist = transactions.stream().anyMatch(t -> t.getTrader().getCity().equals("Shenzhen")); if (isExist) { System.out.println("有在深圳工作的"); } else { System.out.println("沒有在深圳工作的"); } // (6) 打印生活在北京的交易員的所有交易額。 int sum = transactions.stream().filter(t -> t.getTrader().getCity().equals("Beijing")) .map(t -> t.getValue()) .reduce(0,Integer::sum); System.out.println(sum); // (7) 所有交易中,最高的交易額是多少? int max = transactions.stream().map(t -> t.getValue()) .reduce(0,Integer::max); System.out.println(max); // (8) 找到交易額最小的交易。 int min = transactions.stream().map(t -> t.getValue()) .reduce(0,Integer::min); System.out.println(min); } }
中間操作表
操作 | 類型 | 返回類型 | 目的 |
---|---|---|---|
filter | 中間操作 | Stream |
過濾元素 |
distinct | 中間操作 | Stream |
過濾重復的元素 |
skip | 中間操作 | Stream |
跳過指定數(shù)量的元素 |
limit | 中間操作 | Stream |
限制元素的數(shù)量 |
map | 中間操作 | Stream |
流的轉(zhuǎn)化 |
flatmap | 中間操作 | Stream |
流的扁平化 |
sorted | 中間操作 | Stream |
元素排序 |
終端操作表
操作 | 類型 | 返回類型 | 目的 |
---|---|---|---|
forEach | 終端操作 | void | 消費流中的每個元素,返回void |
count | 終端操作 | long | 返回流中元素的個數(shù),返回long |
collect | 終端操作 | R | 把流歸約為一個集合 |
anyMatch | 終端操作 | boolean | 流中是否有符合要求的元素 |
noneMatch | 終端操作 | boolean | 流中是否沒有任何符合要求的元素 |
allMatch | 終端操作 | boolean | 流中是否所有元素都是符合要求的 |
findAny | 終端操作 | Optional |
查找符合要求的元素 |
findFirst | 終端操作 | Optional |
查找第一個符合要求的元素 |
reduce | 終端操作 | Optional |
歸約 |
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/69975.html
摘要:歐陽思海繼承接口后,又加了新的抽象方法,這個接口就不再是函數(shù)式接口默認方法在接口中添加了一個默認方法。總結(jié)在這篇文章中,我們講了表達式方法引用函數(shù)式接口接口中的靜態(tài)方法接口中的默認方法的使用。 今天我來聊聊 Java8 的一些新的特性,確實 Java8 的新特性的出現(xiàn),給開發(fā)者帶來了非常大的便利,可能剛剛開始的時候會有點不習慣的這種寫法,但是,當你真正的熟悉了之后,你一定會愛上這些新的...
摘要:接口有一個方法,可以返回值。在上面的代碼中,就是獲取字符串的長度,然后將每個字符串的長度作為返回值返回。 今天我們還講講Consumer、Supplier、Predicate、Function這幾個接口的用法,在 Java8 的用法當中,這幾個接口雖然沒有明目張膽的使用,但是,卻是潤物細無聲的。為什么這么說呢? 這幾個接口都在 java.util.function 包下的,分別是Con...
摘要:現(xiàn)在爸爸終于讓平臺支持了,這篇文章中便來和大家聊聊如何在項目中配置使用。要想在項目中使用的新特性,需要將你的升級到及以上版本,并采用新的編譯。 轉(zhuǎn)載請注明出處:https://zhuanlan.zhihu.com/p/23279894 前言 在過去的文章中我介紹過Java8的一些新特性,包括: Java8新特性第1章(Lambda表達式) Java8新特性第2章(接口默認方法) J...
閱讀 1318·2021-11-15 11:37
閱讀 2575·2021-09-22 10:56
閱讀 3399·2021-09-06 15:11
閱讀 811·2021-08-31 09:45
閱讀 2910·2021-07-28 11:16
閱讀 1815·2019-08-30 15:44
閱讀 484·2019-08-30 13:22
閱讀 3352·2019-08-30 13:18