Stream API的代碼java
返回低熱量菜餚的名稱數組
List<Dish> menu = FakeDb.getMenu(); List<String> lowCaloricDishesName = // menu.stream() menu.parallelStream() // 並行處理 .filter(d -> d.getCalories() < 400) // 篩選低卡路里 .sorted(comparing(Dish::getCalories)) // 按卡路里排序 .map(Dish::getName) // 提取菜餚名稱 .collect(toList()); // 返回list System.out.println(lowCaloricDishesName);
流的使用:一個數據源,一箇中間操做鏈,一個終端操做dom
流的操做有兩類:中間操做與終端操做ide
// 篩選前2個素菜 FakeDb.getMenu().stream() .filter(d -> d.isVegetarian()) // 這就是謂詞篩選 .limit(2) // 截斷流,返回前n個元素 .forEach(System.out::println); Arrays.asList(1, 2, 2, 3, 3, 3).stream() .distinct() // 去重 .skip(1) // 跳過元素 .forEach(System.out::println);
// 提取菜名 FakeDb.getMenu().stream() .map(Dish::getName) .forEach(System.out::println); // 求每一個字符串長度 Arrays.asList("Java 8", "Lambdas", "In", "Action").stream() .map(String::length) .forEach(System.out::println);
單詞列表返回字符列表函數
// 單詞列表返回字符列表 如輸入列表["Hello", "World"],輸出列表["H", "e", "l", "o", "W", "r", "d"] // 嘗試一:不成功 Arrays.asList("Hello", "World").stream() .map(w -> w.split("")) // 將每一個單詞轉爲字符數組 Stream<String[]> .distinct() .forEach(System.out::println);
Arrays.stream()能夠將數組轉換成流性能
// 嘗試二:不成功 Arrays.asList("Hello", "World").stream() .map(w -> w.split("")) // 將每一個單詞轉爲字符數組 Stream<String[]> .map(Arrays::stream) // 將每一個數組轉換成一個單獨的流 Stream<Stream<String>> .distinct() .forEach(System.out::println);
使用flatMap優化
Arrays.asList("Hello", "World").stream() .map(w -> w.split("")) // 將每一個單詞轉爲字符數組 .flatMap(Arrays::stream)// 將各個生成流扁平化爲單個流 Stream<String> // 各個數組並非分別映射成一個流,而是映射成流的內容 .distinct() .forEach(System.out::println);
flatMap方法讓你先把一個流中的每一個值都換成另外一個流,而後把全部的流鏈接起來成爲一個流this
flatMap使用舉例3d
// 數字列表的平方列表 Arrays.asList(1, 2, 3, 4, 5, 6).stream() .map(n -> n * n) .forEach(System.out::println); System.out.println("----------------------"); // 兩個數組列表的數對 List<Integer> numbers1 = Arrays.asList(1, 2, 3); List<Integer> numbers2 = Arrays.asList(3, 4); numbers1.stream() .flatMap(i -> numbers2.stream().map(j -> new int[]{i, j})) .forEach(a -> System.out.println(a[0] + "\t" + a[1])); System.out.println("----------------------"); // 總和能被3整除的數對 numbers1.stream() .flatMap(i -> numbers2.stream() .filter(j -> (i + j) % 3 == 0) .map(j -> new int[]{i, j})) .forEach(a -> System.out.println(a[0] + "\t" + a[1]));
從單詞列表中返回所用到的字符code
allMatch/anyMatch/noneMatch/findFirst/findAny
匹配
// 至少匹配一個元素 boolean match = FakeDb.getMenu().stream() .anyMatch(Dish::isVegetarian); System.out.println(match); // 匹配全部元素 match = FakeDb.getMenu().stream() .allMatch(d -> d.getCalories() > 1000); System.out.println(match); // 全部都不匹配 match = FakeDb.getMenu().stream() .noneMatch(d -> d.getCalories() > 1000); System.out.println(match);
查找
Optional<Dish> dish = FakeDb.getMenu().stream() .filter(Dish::isVegetarian) .findAny(); // 關於返回值 Optional<T> 的用法: System.out.println(dish.isPresent()); // 存在返回true,不然返回false dish.ifPresent(System.out::println); // 存在就執行代碼塊 System.out.println(dish.get()); // 存在返回值,不存在拋異常 Dish defaultDish = new Dish("pork", false, 800, Dish.Type.MEAT); System.out.println(dish.orElse(defaultDish)); // 存在返回值,不然返回默認值 // 查找第一個元素 Optional<Dish> dish2 = FakeDb.getMenu().stream() .filter(Dish::isVegetarian) .findFirst();
// 終端操做的返回值 // allMatch boolean // forEach void // findAny Optional<T> // collect R eg:List<T> List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 元素求和,有初始值的狀況 int sum = numbers.stream() .reduce(0, Integer::sum); System.out.println(sum); // 元素求和,無初始值 Optional<Integer> sum2 = numbers.stream() .reduce(Integer::sum); System.out.println(sum2.get()); // 最大值 int maxValue = numbers.stream().reduce(0, Integer::max); System.out.println(maxValue); // 最小值 int minValue = numbers.stream().reduce(0, Integer::min); System.out.println(minValue); // 菜單中菜的個數 int dishCount = FakeDb.getMenu().stream() .map(d -> 1) .reduce(0, (a, b) -> a + b); System.out.println(dishCount); // 內置count System.out.println(FakeDb.getMenu().stream().count());
無狀態操做:諸如map或filter等操做會從輸入流中獲取每個元素,並在輸出流中獲得0或1個結果。
有狀態操做:從流中排序和刪除重複項時都須要知道先前的歷史
List<Transaction> tList = FakeDb.getTransactions(); // (1) 找出2011年發生的全部交易,並按交易額排序(從低到高)。 List<Transaction> list01 = tList.stream() .filter(t -> t.getYear() == 2011) // 2011年的交易 .sorted(Comparator.comparing(Transaction::getValue)) // 交易額從低到高 .collect(Collectors.toList()); System.out.println(list01); // (2) 交易員都在哪些不一樣的城市工做過? List<String> cityList = tList.stream() .map(t -> t.getTrader().getCity()) // 交易員所在城市 .distinct() // 去重 .collect(Collectors.toList()); System.out.println(cityList); // (3) 查找全部來自於劍橋的交易員,並按姓名排序。 List<Trader> list3 = tList.stream() .map(Transaction::getTrader) // 交易員 .filter(t -> "Cambridge".equals(t.getCity())) // 來自劍橋 .distinct() // 去重 .sorted(Comparator.comparing(Trader::getName)) // 按姓名排序 .collect(Collectors.toList()); System.out.println(list3); // (4) 返回全部交易員的姓名字符串,按字母順序排序。 String nameStr = tList.stream() .map(t -> t.getTrader().getName()) // 交易員的姓名 .distinct() // 去重 // .sorted(Comparator.comparing(String::toString)) // 排序 .sorted() // 排序,能夠簡寫 // .collect(Collectors.toList()); // .reduce("", (n1, n2) -> n1 + n2 + " "); // 這種寫法效率不高 .collect(Collectors.joining(" ")); System.out.println(nameStr); // (5) 有沒有交易員是在米蘭工做的? // Optional<String> optional5 = tList.stream() // .map(Transaction::getTrader) // .map(Trader::getCity) // .filter(city -> "Milan".equals(city)) // .findAny(); // System.out.println(optional5.isPresent()); boolean milanBased = tList.stream() .anyMatch(t -> t.getTrader().getCity().equals("Milan")); System.out.println(milanBased); // (6) 打印生活在劍橋的交易員的全部交易額。 // Optional<Integer> optional6 = tList.stream() // .filter(t -> "Cambridge".equals(t.getTrader().getCity())) // .map(Transaction::getValue) // .reduce((a, b) -> a + b); // System.out.println(optional6.get()); tList.stream() .filter(t -> "Cambridge".equals(t.getTrader().getCity())) .map(Transaction::getValue) .forEach(System.out::println); // (7) 全部交易中,最高的交易額是多少? Optional<Integer> optional7 = tList.stream() .map(Transaction::getValue) .reduce(Integer::max); System.out.println(optional7.get()); // (8) 找到交易額最小的交易。 Optional<Integer> optional8 = tList.stream() .map(Transaction::getValue) .reduce(Integer::min); System.out.println(optional8.get());
// 計算菜單中的卡路里 int calories = FakeDb.getMenu().stream() .map(Dish::getCalories) .reduce(0, Integer::sum); // 它有一個暗含的裝箱成本,每一個Integer都必須拆箱成一個原始類型,再進行求和 System.out.println(calories); // 原始類型流特化 // IntStream,DoubleStream,LongStream分別將流中的元素特化爲int,long,double,從而避免暗含的裝箱成本 // 映射到數值流 int sum = FakeDb.getMenu().stream() // 返回 Stream<Dish> .mapToInt(Dish::getCalories) // 返回 IntStream .sum(); // sum,max,min,average // sum,若是流是空的,sum默認返回0 System.out.println(sum); // 轉換回對象流 FakeDb.getMenu().stream() .mapToInt(Dish::getCalories) .boxed(); // 轉換爲Stream<Integer> // 默認值OptionalInt OptionalDouble OptionalLong // sum有默認值0,max,min,average沒有默認值 OptionalInt maxCalories = FakeDb.getMenu().stream() .mapToInt(Dish::getCalories) .max(); System.out.println(sum);
// [1, 100) IntStream numbers = IntStream.range(1, 100); // [1 100] IntStream numbers2 = IntStream.rangeClosed(1, 100); // 求勾股數 IntStream.rangeClosed(1, 100).boxed() .flatMap(a -> IntStream.rangeClosed(a, 100) .filter(b -> Math.sqrt(a*a + b*b )%1==0) .mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a * a + b * b)})) .forEach(a -> System.out.println(a[0] + ", " + a[1] + ", " + a[2])); // 求勾股數 優化 IntStream.rangeClosed(1, 100).boxed() .flatMap(a -> IntStream.rangeClosed(a, 100) .mapToObj(b -> new double[]{a, b, Math.sqrt(a * a + b * b)})) .filter(t -> t[2] % 1 == 0) .forEach(a -> System.out.println(a[0] + ", " + a[1] + ", " + a[2]));
// 由值建立流 Stream.of("java 8", "Lambdas", "In", "Action") .map(String::toUpperCase) .forEach(System.out::println); // 由數組建立流 int[] numbers = {2, 3, 5, 7, 11, 13}; int sum = Arrays.stream(numbers).sum(); System.out.println(sum); // 由文件生成流:統計文件中的不一樣單詞數 long uniqueWords = 0; try(Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){ uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" "))) .distinct() .count(); } catch (IOException e) { e.printStackTrace(); }; System.out.println(uniqueWords); // 由函數生成流 無限流 // Stream.iterate // Stream.generate Stream.iterate(0, n -> n + 2) .limit(10) .forEach(System.out::println); // 迭代:斐波納契元組數列 Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]}) .limit(20) .forEach(t -> System.out.println("(" + t[0] + ", " + t[1] + ")")); // 生成 Stream.generate(Math::random) .limit(5) .forEach(System.out::println); // 生成一個全是1的無限流 IntStream.generate(() -> 1).limit(11).forEach(System.out::println); // 生成:斐波納契元組數列 IntStream.generate(new IntSupplier() { private int previous = 0; private int current = 1; @Override public int getAsInt() { int oldPrevious = this.previous; int nextValue = this.previous + this.current; this.previous = this.current; this.current = nextValue; return oldPrevious; } }).limit(11).forEach(System.out::println);
https://www.zhihu.com/question/51841706
遍歷數組取索引值
// import static java.util.stream.Collectors.toList; String[] names = {"Sam", "Pamela", "Dave", "Pascal", "Erik"}; IntStream.range(0, names.length) .filter(i -> names[i].length() <= i) .mapToObj(i -> names[i]) .collect(toList()); // List<String> // 方案一: IntStream.range(0, names.length) .forEach(i -> System.out.println(i + ", " + names[i])); // 方案二: AtomicInteger index = new AtomicInteger(); List<String> list = Arrays.stream(names) .filter(n -> n.length() <= index.incrementAndGet()) .collect(Collectors.toList()); // 方案三:使用Guava Streams.mapWithIndex(Arrays.stream(names) ,(str, index) -> index + ", " + str) .forEach(System.out::println); // 方案四:未看懂 Seq.seq(Stream.of(names)).zipWithIndex() .filter( namesWithIndex -> namesWithIndex.v1.length() <= namesWithIndex.v2 + 1) .toList(); // 方案五:未看懂 LazyFutureStream.of(names) .zipWithIndex() .filter( namesWithIndex -> namesWithIndex.v1.length() <= namesWithIndex.v2 + 1) .toList(); // 方案六: int[] idx = {-1}; Arrays.stream(names) .forEach(i -> System.out.println(++idx[0] + ", " + names[idx[0]]));
Guava
Apache
lambdaj
Joda-Time