Java Stream

Posted by Adam on August 24, 2022
### [Stream Group By](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html) ```java // Group employees by department Map<Department, List<Employee>> byDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment)); // Compute sum of salaries by department Map<Department, Integer> totalByDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment, Collectors.summingInt(Employee::getSalary))); // 使用 Stream API 將物件分類並保持排序 Map<String, List<Item>> categorizedItems = items.stream() .collect(Collectors.groupingBy( Item::getCategory, LinkedHashMap::new, // 使用 LinkedHashMap 保持排序 Collectors.toList() // 將子串列收集為 List )); ``` ### groupingBy 之後的內容再做轉換 ```java import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Main { public static class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } public static void main(String[] args) { List<Person> people = List.of( new Person("Alice", 25), new Person("Bob", 30), new Person("Charlie", 25), new Person("David", 30) ); // 使用 groupingBy 分組,然後對每個分組的人名轉換為大寫 Map<Integer, List<String>> groupedNames = people.stream() .collect(Collectors.groupingBy( Person::getAge, Collectors.mapping( person -> person.getName().toUpperCase(), Collectors.toList() ) )); System.out.println(groupedNames); } } ``` ### N 個一組 ```java import java.util.stream.Collectors; import java.util.*; public class Main { public static void main(String[] args) { List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H", "I", "J"); int n = 3; // n 個一組 Map<Integer, List<String>> groupedMap = list.stream() .collect(Collectors.groupingBy(str -> list.indexOf(str) / n)); groupedMap.forEach((key, value) -> { System.out.println("Group " + key + ": " + value); }); } } ``` ### 依照原串列順序做出 Map ```java import java.util.*; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> names = Arrays.asList("Alice2", "Alice1", "Charlie", "Bob1", "Bob2", "Alice3"); Map<String, List<String>> groupedNames = names.stream() .collect(Collectors.groupingBy(name -> name.substring(0, 1), LinkedHashMap::new, Collectors.toList())); // 印出分組後的結果,保持原始順序 groupedNames.forEach((key, value) -> System.out.println(key + ": " + value)); } } ``` ### groupingBy 將 null 值作為單獨的分組 ```java import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", null, "David", null); Map<String, List<String>> groupedNames = names.stream() .collect(Collectors.groupingBy( name -> name == null ? "NULL" : name,Collectors.toList() )); System.out.println(groupedNames); // {NULL=[null, null], Bob=[Bob], Alice=[Alice], Charlie=[Charlie], David=[David]} } } ``` ### Collectors.toMap ```java List<Person> persons = Arrays.asList( new Person("John", 20), new Person("Mary", 30), new Person("Peter", 25) ); Map<String, Integer> ageByName = persons.stream() .collect(Collectors.toMap( Person::getName, // 定義鍵 Person::getAge // 定義值 )); ``` ```java List<Person> persons = Arrays.asList( new Person("John", 20), new Person("Mary", 30), new Person("Peter", 25), new Person("John", 40) ); Map<String, Integer> ageByName = persons.stream() .collect(Collectors.toMap( Person::getName, Person::getAge, (age1, age2) -> age1 // 合併函數:選擇年齡較小的值 )); ``` ```java Map<String, Person> personMap = personList.stream() .collect(Collectors.toMap(Person::getName, Function.identity())); // Function.identity() 表示物件本身 ``` ### [Java 中的 Stream 的 reduce 操作](https://www.delftstack.com/zh-tw/howto/java/stream-reduce-in-java/#%e5%9c%a8-java-%e4%b8%ad%e4%bd%bf%e7%94%a8-reduce-%e9%81%8b%e7%ae%97%e6%b1%82%e5%92%8c) ```java import java.util.Arrays; public class SimpleTesting { public static void main(String args[]) { int[] numbers = {45, 56, 87, 323, 47, 20, 658, 985, 78, 123}; int sum = Arrays.stream(numbers).reduce(0, (a, b) -> a + b); System.out.print("sum: " +sum); // finding the min element int min = Arrays.stream(numbers).reduce(Integer.MAX_VALUE, (a, b) -> a < b ? a : b); // finding the max element int max = Arrays.stream(numbers).reduce(Integer.MIN_VALUE, (a, b) -> a > b ? a : b); } } ``` #### 將 List 轉換成 String,設定間隔符號、起始符號、結束符號 ```java import java.util.Arrays; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { String result = Arrays.asList("Apple", "Banana", "Cheery", "Orange", "WaterMelone").stream() .collect(Collectors.joining(",", "(", ")")); System.out.println(result); // (Apple,Banana,Cheery,Orange,WaterMelone) } } ``` #### [陣列中任一組符合](https://stackoverflow.com/questions/1128723/how-do-i-determine-whether-an-array-contains-a-particular-value-in-java) ```java String[] values = {"AB","BC","CD","AE"}; boolean contains = Arrays.stream(values).anyMatch("s"::equals); // flase ``` ``` import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); boolean hasEvenNumber = numbers.stream() .anyMatch(num -> num % 2 == 0); if(hasEvenNumber) { System.out.println("List contains at least one even number."); } else { System.out.println("List does not contain any even number."); } } } ``` #### map 轉換並收集成 List ```java import java.util.List; import java.util.stream.Stream; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> names = Stream.of("tony", "tom", "john") .map(name -> name.toUpperCase()) .collect(Collectors.toList()); System.out.println(names.toString()); // [TONY, TOM, JOHN] } } ``` #### 過濾內容 ```java import java.util.List; import java.util.stream.Stream; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> names2 = Stream.of("Tony", "Tom", "John", "Andy") .filter(name -> name.startsWith("T")) .collect(Collectors.toList()); System.out.println(names2.toString()); // [Tony, Tom] } } ``` #### flatMap 的應用 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Stream; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> allNames = Stream.of(Arrays.asList("Tony", "Tom", "John"), Arrays.asList("Amy", "Emma", "Iris")) .flatMap(names -> names.stream().map(a -> a.toUpperCase())) .collect(Collectors.toList()); System.out.println(allNames.toString()); // [TONY, TOM, JOHN, AMY, EMMA, IRIS] } } ``` #### 計數 ```java import java.util.stream.Stream; public class Main { public static void main(String[] args) { long count = Stream.of("Tony", "Tom", "John", "Amy", "Emma", "Iris").count(); System.out.println("count: " + count); // count: 6 } } ``` #### 最大值 ```java import java.util.Comparator; import java.util.stream.Stream; public class Main { public static void main(String[] args) { int max = Stream.of(120,24,59,63,11,74) .max(Comparator.comparing(n -> n)) .get(); System.out.println("max: " + max); // max: 120 } } ``` #### 最小值 ```java import java.util.Comparator; import java.util.stream.Stream; public class Main { public static void main(String[] args) { int min = Stream.of(120,24,59,63,11,74) .min(Comparator.comparing(n -> n)) .get(); System.out.println("min: " + min); // min: 11 } } ``` #### [flatMap](https://openhome.cc/zh-tw/java/functional-api/flatmap/) ```java var itemNames = new ArrayList<String>(); for(var order : orders) { for(var lineItem : order.lineItems()) { itemNames.add(lineItem.name()); } } ``` ```java List<String> itemNames = orders.stream() .flatMap(order -> order.lineItems().stream()) .map(LineItem::name) .collect(toList()); ``` #### 遞增排序 ASC ```java import java.util.List; import java.util.stream.Stream; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> sortedAsc = Stream.of(120,24,59,63,11,74) .sorted() .collect(Collectors.toList()); System.out.println("sorted asc: " + sortedAsc); // sorted asc: [11, 24, 59, 63, 74, 120] } } ``` #### 遞減排序 DESC ```java import java.util.List; import java.util.stream.Stream; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> sortedDesc = Stream.of(120,24,59,63,11,74) .sorted((n1, n2) -> n2 - n1) .collect(Collectors.toList()); System.out.println("sorted desc: " + sortedDesc); //sorted desc: [120, 74, 63, 59, 24, 11] } } ``` #### 依 String 類型排序 在使用 Java Stream 進行排序時,可以使用 `sorted()` 方法並傳入 `Comparator` 物件來進行比較。比較 String 類型的話,可以使用 `Comparator.comparing()` 方法,並指定要比較的屬性。 以下是一個排序字串列表的範例程式碼: ```java import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("apple", "banana", "cherry", "date", "fig"); List<String> sortedStrings = strings.stream() .sorted(Comparator.comparing(String::toString)) .collect(Collectors.toList()); sortedStrings.forEach(System.out::println); } } ``` 這段程式碼會將 `strings` 列表中的字串按照字母順序進行排序,並輸出排序後的結果。在`Comparator.comparing()` 中,我們使用 `String::toString` 來表示要比較的屬性為字串本身。如果要根據其他條件進行排序,只需要更改 `Comparator.comparing()` 中的函數即可。 #### 根據特定字串順序排序 ```java import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Main { public static void main(String[] args) { String order = "5, 9, 1, 2"; List<String> result = Stream.of("9", "6", "5", "3", "1", "7", "2", "4", "8") .sorted((a, b) -> order.indexOf(a) - order.indexOf(b)).collect(Collectors.toList()); System.out.println(result); // 注意 indexOf 未包含的項目取得的值為 -1,因為未包含的項目會在前方 // [6, 3, 7, 4, 8, 5, 9, 1, 2] } } ``` 將包含的項目移至前方的作法 ```java import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Main { public static void main(String[] args) { String order = "5, 9, 1, 2"; List<String> result = Stream.of("9", "6", "5", "3", "1", "7", "2", "4", "8") .sorted(Comparator.comparing((String a) -> (order.contains(a) ? 0 : 1)) .thenComparing((String a) -> order.indexOf(a))) .collect(Collectors.toList()); System.out.println(result); // [5, 9, 1, 2, 6, 3, 7, 4, 8] } } ``` ### [Removing all duplicates from a List in Java](https://www.baeldung.com/java-remove-duplicates-from-list) ```java public void givenListContainsDuplicates_whenRemovingDuplicatesWithJava8_thenCorrect() { List<Integer> listWithDuplicates = Lists.newArrayList(5, 0, 3, 1, 2, 3, 0, 0); List<Integer> listWithoutDuplicates = listWithDuplicates.stream() .distinct() .collect(Collectors.toList()); assertThat(listWithoutDuplicates, hasSize(5)); assertThat(listWithoutDuplicates, containsInAnyOrder(5, 0, 3, 1, 2)); } ``` ### Java stream List to Array ```java List<String> list = Arrays.asList("apple", "banana", "orange"); String[] array = list.stream().toArray(String[]::new); ``` ### IntStream ```java IntStream.range(0, 10).forEach(i -> System.out.print(i)); // 0123456789 IntStream.range(0, 10).forEach(System.out::print); // 0123456789 // boxed 方法是 IntStream 的一個方法,它將 IntStream 中的每個元素從基本類型 int 轉換為對象類型 Integer,並返回一個 Stream<Integer> IntStream intStream = IntStream.rangeClosed(1, 5); List<Integer> integerList = intStream.boxed().collect(Collectors.toList()); ``` ### 計算標準差 (Standard Deviation) ```java import java.util.List; public class StandardDeviationCalculator { public static void main(String[] args) { List<Double> data = List.of(2.0, 4.0, 6.0, 8.0, 10.0); // 這裡是你的數據集 // 計算平均值 double mean = data.stream() .mapToDouble(Double::doubleValue) .average() .orElse(0.0); // 計算每個數值與平均值的差的平方,然後計算它們的平均值 double variance = data.stream() .mapToDouble(Double::doubleValue) .map(x -> Math.pow(x - mean, 2)) .average() .orElse(0.0); // 計算標準差,即將方差的平方根 double standardDeviation = Math.sqrt(variance); System.out.println("平均值: " + mean); System.out.println("標準差: " + standardDeviation); } } ```