BaseStream<T,S extends BaseStream<T,S>>介面有4個子介面
DoubleStream、IntStream、LongStream、Stream<T>,其中一個就是Stream<T>
java.lang.CharSequence、java.util.Collection、java.util.Arrays 和 Stream 本身都有新增方法可以取得 Stream,可能還有其他套件
※取得 Steam 的幾種方式
// String 取得 Stream new String("abcde").chars().forEach(System.out::println); // List 取得 Stream List<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); // 順序 Stream<String> parallelStream = list.parallelStream(); // 並行,速度較順序快 // Arrays 取得 Stream Stream<Integer> arraysStream = Arrays.stream(new Integer[10]); // Stream 本身取得 Stream Stream<Integer> streamOf = Stream.of(1, 2, 3, 4, 5, 6); // 無窮的 Stream Stream<Integer> streamIterate = Stream.iterate(0, x -> x + 2).limit(5); streamIterate.forEach(System.out::println); // 無窮的 Stream Stream<Double> streamGenerate = Stream.generate(Math::random).limit(3); streamGenerate.forEach(System.out::println);
※
※of、collect
// 原本的方法 List<String> ox = Arrays.asList("xxx", "ooo", "xox"); System.out.println(ox); // Stream Stream<String> st = Stream.of("xxx", "ooo", "xox"); List<String> xo = st.collect(Collectors.toList()); // Stream.of("xxx", "ooo", "xox").collect(Collectors.toList()); System.out.println(xo);
※of會按照順序,回傳裡面的值;collect可以回傳集合,此例也可以回傳toSet()
※count
// 原本的方法 List<Integer> list = Arrays.asList(1, 2, 3); System.out.println("size=" + list.size()); // Stream long count = Stream.of(1, 2, 3).count(); System.out.println("count=" + count);
※
※Collectors.joining
// 原本的方法 final List<String> animal = new ArrayList<>(); animal.add("elephant"); animal.add("dog"); animal.add("pig"); animal.add("rat"); animal.add("tiger"); animal.add("cat"); StringBuilder sb = new StringBuilder("["); for (String s : animal) { sb.append(","); sb.append(s); } sb.append("]").delete(1, 2); // 刪除第一個逗點 System.out.println(sb.toString()); // Stream String result = animal.stream().collect(Collectors.joining(",", "[", "]")); System.out.println(result);
※Collectors裡面有超多方法,這個還不錯用
※map
// ===将属性取代=== // 原本的方法 List<String> ox = new ArrayList<>(); for (String data : Arrays.asList("xxx", "ooo", "xox")) { ox.add(data.replace("o", "z")); } System.out.println(ox); // Stream Stream<String> st = Stream.of("xxx", "ooo", "xox"); Stream<String> map = st.map(data -> data.replace("o", "z")); List<String> xo = map.collect(Collectors.toList()); // Stream.of("xxx", "ooo", "xox").map(data -> data.replace("o", "z")).collect(Collectors.toList()); System.out.println(xo); // ===只取得部分属性=== Animal a1 = new Animal(1, "aaa"); Animal a2 = new Animal(2, "bbb"); Animal a3 = new Animal(3, "ccc"); List<Animal> animals = Stream.of(a1, a2, a3).collect(Collectors.toList()); // 原本的方法 List<String> c1 = new ArrayList<>(); for (Animal a : animals) { c1.add(a.getName()); } c1.forEach(System.out::println); // Stream List<String> c2 = animals.stream().map(Animal::getName).collect(Collectors.toList()); c2.forEach(System.out::println);
※map 裡放的參數是 Function
※flatMap
public class Java8Test { public static void main(String[] args) {
// 使用 map Stream<Stream<String>> stream1 = Stream.of("a1", "b2", "c3").map(Java8Test::xxx); stream1.forEach(stream -> stream.forEach(System.out::println));
// 使用 flatMap Stream<String> stream2 = Stream.of("a1", "b2", "c3").flatMap(Java8Test::xxx); stream2.forEach(System.out::println);
// List 的 add 和 addAll List<String> list1 = Arrays.asList("xxx", "ooo", "xox"); List<Object> list2 = Stream.of("a1", "b2", "c3").collect(Collectors.toList()); // list2.add(list1); // System.out.println(list2); // [a1, b2, c3, [xxx, ooo, xox]] list2.addAll(list1); System.out.println(list2); // [a1, b2, c3, xxx, ooo, xox] } public static Stream<String> xxx(String s) { List<String> l = new ArrayList<>(); l.add(s.substring(0, 1)); return l.stream(); } }
※map 和 flatMap 的關係就相當於 List 裡的 add 和 addAll
※filter
// 原本的方法 String[] animal = { "elephant", "dog", "pig", "rat", "tiger", "cat" }; List<String> result = new ArrayList<>(); for (String a : animal) { if (a.endsWith("t")) { result.add(a); } } System.out.println(result); // Stream Stream<String> st = Stream.of(animal); Stream<String> filt = st.filter(a -> a.endsWith("t")); List<String> rtn = filt.collect(Collectors.toList()); System.out.println(rtn);
※filter 裡放的參數是 Predicate
※allMatch、anyMatch、noneMatch
static List<String> animal = new ArrayList<>(); static { animal.add("elephant"); animal.add("dog"); animal.add("pig"); animal.add("rat"); animal.add("tiger"); animal.add("cat"); } public static void main(String[] args) { animal.stream().map(str -> str.toUpperCase()).distinct(). collect(Collectors.toList()). forEach(System.out::println); if (animal.stream().allMatch(str -> str.contains("a"))) { System.out.println("全有a"); } if (animal.stream().anyMatch(str -> str.contains("n"))) { System.out.println("其中一個以上有n"); } if (animal.stream().noneMatch(str -> str.contains("A"))) { System.out.println("全部都沒有A"); } }
※這三個方法的參數,都是 Predicate
※注意使用 distinct 時,必須覆寫 hashCode 和 equals 方法,只是此例的 String 內鍵已經寫好了
※多條件判斷
Predicate有提供and/or方法List<String> animal = new ArrayList<>(); animal.add("ELEPHANT"); animal.add("RAT"); animal.add("CAT"); animal.add("12345678"); Predicate<String> p1 = (str) -> str.startsWith("E"); Predicate<String> p2 = (str) -> str.length() == 8; animal.stream().filter(p1.or(p2)).forEach(System.out::println); System.out.println(); animal.stream().filter(p1.and(p2)).forEach(System.out::println);
※
※sorted
// 原本的方法 final List<Integer> list = Arrays.asList(1, 3, 5, 2, 4); // 正序 Collections.sort(list); System.out.println("asc=" + list); // 倒序 Collections.reverse(list); System.out.println("desc=" + list); // Stream final Integer[] i = { 1, 3, 5, 2, 4 }; // 正序 (自然排序) List<Integer> asc = Stream.of(i).sorted().collect(Collectors.toList()); System.out.println("asc=" + asc); // 倒序 (自訂排序) List<Integer> desc = Stream.of(i).sorted((p1, p2) -> p2.compareTo(p1)).collect(Collectors.toList()); System.out.println("desc=" + desc);
※
※flatMap
List<Integer> listA = new ArrayList<>(); listA.add(1); listA.add(2); listA.add(3); List<Integer> listB = new ArrayList<>(); listB.add(4); listB.add(5); listB.add(6); /* * 原本的方法,使用Arrays.asList然後用add、addAll、remove執行時期會報錯 * Arrays.asList()API有說明,它是固定的長度,不能改的,但可以用如下的方式解決 * List<Integer> xxx = Arrays.asList(1, 2, 3); * List<Integer> listA = new ArrayList<>(xxx); */ listA.addAll(listB); System.out.println(listA); // Stream,使用Arrays.asList和List都可以 List<Integer> aList = Arrays.asList(1, 2, 3); List<Integer> bList = Arrays.asList(4, 5, 6); Stream<List<Integer>> abList = Stream.of(aList, bList); Stream<Integer> rtn = abList.flatMap(x -> x.stream()); List<Integer> result = rtn.collect(Collectors.toList()); System.out.println(result);
※可將兩個相同集合合併
※min、max
// 原本的方法 List<Integer> list = Arrays.asList(1, 3, 5, 4, 2); Collections.sort(list); System.out.println("min=" + list.get(0)); System.out.println("max=" + list.get(list.size() - 1)); // Stream Stream<Integer> st1 = Stream.of(1, 3, 5, 4, 2); Optional<Integer> opt1 = st1.min(Comparator.comparing(p -> p)); int min = opt1.get(); System.out.println("min=" + min); Stream<Integer> st2 = Stream.of(1, 3, 5, 4, 2); Optional<Integer> opt2 = st2.max(Comparator.comparing(p -> p)); int max = opt2.get(); System.out.println("max=" + max);
※注意回傳的是Optional,下一篇會說明
※reduce
// 原本的做法 List<String> list = Arrays.asList("xxx", "ooo", "xox"); StringBuffer sb = new StringBuffer(); for (String s : list) { sb.append(s); } System.out.println("sb=" + sb); // Stream 的做法 class User { private Integer age; public User(Integer age) { this.age = age; } public Integer getAge() { return age; } } List<User> users = List.of(new User(1), new User(2), new User(3), new User(4), new User(5)); // 一個參數 (p1 為第一次或上次的值;p2 為每次循環的值) User one1 = users.stream().reduce((p1, p2) -> new User(p1.getAge() + p2.getAge())).get(); System.out.println(one1.getAge()); // 15 User one2 = users.stream().parallel().reduce((p1, p2) -> new User(p1.getAge() + p2.getAge())).get(); System.out.println(one2.getAge()); // 15 // 兩個參數 (和一個參數比較,第一個參數為初始值,第二個參數和一個參數一樣) User two1 = users.stream().reduce(new User(10), (p1, p2) -> new User(p1.getAge() + p2.getAge())); System.out.println(two1.getAge()); // 25 User two2 = users.stream().parallel().reduce(new User(10), (p1, p2) -> new User(p1.getAge() + p2.getAge())); System.out.println(two2.getAge()); // 65, 第二個參數配合 parallel 是 11+12+13+14+15 // 三個參數 (和兩個參數比較,前兩個參數一樣,最後的參數是 BinaryOperator) int three1 = users.stream().reduce(10, (i, u) -> i + u.getAge(), Integer::sum); System.out.println(three1); // 25 int three2 = users.stream().parallel().reduce(10, (i, u) -> i + u.getAge(), Integer::sum); System.out.println(three2); // 65, 算法和兩個參數一樣,但回傳值不同
※reduce是個overloading,有三個,分別是一個參數、兩個參數、三個參數
※一個參數的回傳的是 Optional,用它的 get 方法可取出
※兩個參數相當於第一個參數給初始值,但回傳的是第一個參數的型態,所以不用像一個參數那樣,還要用 get 方法
因為有給初始值了,所以不可能為 null,就不需要 Optional 了
※三個參數可以直接用想要的回傳值去接 (兩個參數也可用 map 達到類似的效果,寫法很多)
※Statistics
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); IntSummaryStatistics result = list.stream().mapToInt(i -> i).summaryStatistics(); System.out.println("最大值=" + result.getMax()); System.out.println("最小值=" + result.getMin()); System.out.println("加總=" + result.getSum()); System.out.println("個數=" + result.getCount()); System.out.println("平均值=" + result.getAverage());
※統計用的類別,在java.util包下,實作IntConsumer介面
※mapToInt
class Chess { private String name; private int amount; private int price; public Chess(String name, int price, int amount) { this.name = name; this.price = price; this.amount = amount; } public Chess(){} // setter/getter... }
※
List<Chess> chess = new ArrayList<>(); chess.add(new Chess("jump", 30, 1)); chess.add(new Chess("road", 40, 5)); chess.add(new Chess("elephant", 55, 2)); chess.add(new Chess("animal", 25, 3)); chess.stream().map((Chess ch) -> { return ch.getAmount() * ch.getPrice(); }).forEachOrdered(System.out::println); // reduce(),將集合中的資料合為一個結果 int result = chess.stream().map((Chess ch) -> { return ch.getAmount() * ch.getPrice(); }).reduce((Integer s, Integer c) -> s + c).get(); System.out.println("result = " + result); IntSummaryStatistics iss = chess.stream().mapToInt((Chess ch) -> { // 還有mapToDouble、mapToLong,用法差不多 return ch.getAmount() * ch.getPrice(); }).summaryStatistics(); System.out.println("result = " + iss); // 這一行包括下面5個方法 System.out.println("result = " + iss.getCount()); System.out.println("result = " + iss.getSum()); System.out.println("result = " + iss.getMin()); System.out.println("result = " + iss.getAverage()); System.out.println("result = " + iss.getMax());
※
※sequential、parallel
public static void main(String[] args) { final List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); sequential(list); parallel(list); } // 順序運算 private static void sequential(List<Integer> list) { long start = System.nanoTime(); list.stream().sequential().sorted().collect(Collectors.toList()); long end = System.nanoTime(); long resule = TimeUnit.NANOSECONDS.toMillis(end - start); System.out.println("sequntial=" + resule); } // 並行運算 private static void parallel(List<Integer> list) { long start = System.nanoTime(); list.stream().parallel().sorted().collect(Collectors.toList()); long end = System.nanoTime(); long resule = TimeUnit.NANOSECONDS.toMillis(end - start); System.out.println("parallel=" + resule); }
※並行就是充份的利用CPU,所以通常速度比較快,但沒有順序,都不寫預設為順序運算
※如果先執行parallel再執行sequential,會發現sequential是0,可能並行(parallel)會先儲在某個地方吧!
※TimeUnit、nanoTime也是java8新增的,後續篇幅會說明
※例二
List<String> animal = new ArrayList<>(); animal.add("ELEPHANT"); animal.add("RAT"); animal.add("CAT"); animal.add("1234A5678"); Predicate<String> p1 = (str) -> str.contains("A"); Predicate<String> p2 = (str) -> str.length() == 8; //是否並行(預設false,預設使用順行); 並行(Parallel)比順行(sequential)快,但沒順行 System.out.println(animal.stream().filter(p1.or(p2)).isParallel()); animal.stream().filter(p1.or(p2)).forEach(System.out :: println); //ELEPHANT RAT CAT 1234A5678,有順序 順序運算 System.out.println(); animal.stream().filter(p1.or(p2)).parallel().forEach(System.out :: println); //CAT 1234A5678 RAT ELEPHANT,沒順序 並行運算 System.out.println(); animal.stream().filter(p1.or(p2)).parallel().sequential().forEach(System.out :: println); // 兩個都寫會後者蓋前者,所以為順序運算
※forEach、limit
// 使用lambda IntStream.range(0, 10).forEach(i -> System.out.print(i)); System.out.println(); // 使用引用 IntStream.range(0, 10).forEach(System.out::print); System.out.println(); // range改成rangeClosed會包括最後的10 IntStream ist = new Random().ints(); IntStream isl = ist.limit(3); isl.forEach(i -> System.out.println(i)); // 重覆使用Stream Stream<Integer> stream = Stream.of(1, 3, 5, 4, 2); stream.forEach(i -> System.out.print(i)); System.out.println(); // stream.forEachOrdered(i -> System.out.print(i));// stream has already been operated upon or closed Supplier<Stream<Integer>> streamSup = () -> Stream.of(1, 3, 5, 4, 2); streamSup.get().forEach(System.out::println); System.out.println(); streamSup.get().forEachOrdered(System.out::println);
※還有個forEachOrdered,用法和forEach一樣,但它保證會按照順序輸出,不是排序哦!
※limit是限制輸出多少個
※註解打開會錯誤,因為它已經關閉了,Stream只能使用一次
※可以利用Supplier來達到多次的目的
沒有留言:
張貼留言