【必看】原創聲明:轉載請註明作者 & 文章來源:Stream流!
hello,我是小索奇,這次講解JDK 8新特性的重點!Stream流,到後期學習框架時候你會發現大量的Stream流出現,如果你不瞭解,相信索奇,你一定會再次回來的(索奇學習框架時也是..)
內容雖然很乾貨,但代碼比較枯燥,現在不想看的可收藏備看~
為什麼要用Stream APIStream流是Java 8中引入的一種新的API,它主要是用於對集合數據進行處理的工具。Stream流可以用於對集合進行過濾、排序、映射、歸約等操作,這些操作可以通過鏈式調用來完成,使得代碼更加簡潔和易於閲讀。Stream流還支持並行處理,可以幫助我們更快地處理大量數據。Stream流的強大之處便是在於提供了豐富的中間操作,相比集合或數組這類容器,極大的簡化源數據的計算複雜度實際開發中,項目中多數數據源都來自於MySQL、Oracle等。但現在數據源可以更多了,有MongDB,Radis等,而這些NoSQL的數據就需要Java層面去處理。非關係型數據庫(NOSQL):MongDB,Radis,採用非傳統的表格結構,比如文檔、鍵-值對、圖形等,這些結構不需要使用SQL語句進行查詢和操作
舉例比例客户端發送請求->Java後台(寫SQL語句)->DB查詢,結果返回給Java後台->客户端顯示對於非關係型數據庫,我們可以在內存層面使用StreamAPI進行過濾 在內存層面,非關係型數據庫通常採用鍵-值存儲方式,可以直接將數據存儲在內存中,這樣可以大大提高數據的讀取和寫入速度。此外,非關係型數據庫通常採用分佈式架構來實現高可用性和可擴展性使用關係型數據庫進行數據過濾可能會比使用非關係型數據庫慢一些,因為關係型數據庫需要進行表格結構的轉換和查詢優化等操作。但是,關係型數據庫也有其優點,比如支持事務、數據一致性等。因此,在選擇數據庫時,需要根據具體的應用場景和需求來進行選擇。Stream它主要是用於對集合數據進行處理的工具。Stream流可以用於對集合進行過濾、排序、映射、歸約等操作Stream API vs 集合框架Stream API 關注的是多個數據的計算(排序、查找、過濾、映射、遍歷等),面向CPU的。集合關注的數據的存儲,面向內存的。Stream API 之於集合,類似於SQL之於數據表的查詢。使用説明①Stream 自己不會存儲元素。②Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream。③Stream 操作是延遲執行的。這意味着他們會等到需要結果的時候才執行。即一旦執行終止操作,就執行中間操作鏈,併產生結果。④ Stream一旦執行了終止操作,就不能再調用其它中間操作或終止操作了。Stream 執行流程步驟1:Stream的實例化一個數據源,如集合、數組,獲取一個流步驟2:一系列的中間操作每次處理都會返回一個持有結果的新Stream,即中間操作的方法返回值仍然是Stream類型的對象。因此中間操作可以是個操作鏈,可對數據源的數據進行次處理,但是在終結操作前,並不會真正執行。步驟3:執行終止操作(終端操作)終止操作的方法返回值類型就不再是Stream了,因此一旦執行終止操作,就結束整個Stream操作了。一旦執行終止操作,就執行中間操作鏈,最終產生結果並結束Stream。拓展stream方法在Java 8中,集合類(如List、Set等)新增了一個stream()方法,可以返回一個Stream對象。Stream是一個Java 8中新增的API,用於操作集合數據,可以實現函數式編程的方式來處理集合數據。List的默認方法default Stream<E>stream()forEach方法forEach()是Java 8中新增的一個方法,它是Stream API的一部分,可以對集合中的每個元素執行指定的操作。forEach()方法接受一個Lambda表達式或者方法引用作為參數,Lambda表達式中定義了對每個元素要執行的操作。下面分別用Lambda和方法引用輸出,結果相同 List<String> list2 = Arrays.asList("apple", "banana", "orange"); System.out.println("方法引用"); list2.forEach(System.out::println); System.out.println("Lambda表達式"); list2.forEach(s-> System.out.println(s));Arrays.asList() 方法可以方便地將一個數組轉換為一個List集合代碼演示員工表Employee
Stream的所有方法都給大家截了下來,見下圖
StreamAPITest public class StreamAPITest { / 創建 Stream方式一:通過集合 / @Test public void test1(){ List<Employee> list = EmployeeData.getEmployees(); // default Stream<E> stream() : 返回一個順序流 Stream<Employee> stream = list.stream(); // default Stream<E> parallelStream() : 返回一個並行流 Stream<Employee> stream1 = list.parallelStream(); System.out.println(stream); System.out.println(stream1); } / 創建 Stream方式二:通過數組 / @Test public void test2(){ //調用Arrays類的static <T> Stream<T> stream(T[] array): 返回一個流 Integer[] arr = new Integer[]{1,2,3,4,5}; // 先得到Stream的示例 Stream<Integer> stream = Arrays.stream(arr); int[] arr1 = new int[]{1,2,3,4,5}; IntStream stream1 = Arrays.stream(arr1); } / 創建 Stream方式三:通過Stream的of() / @Test public void test3(){ Stream<String> stream = Stream.of("AA", "BB", "CC", "SS", "DD"); } }StreamAPITest1 public class StreamAPITest01 { //1-篩選與切片 @Test public void test1() { // filter(Predicate p)——接收 Lambda,從流中排除某些元素。 //練習:查詢員工表中薪資大於7000的員工信息 List<Employee> list = EmployeeData.getEmployees(); Stream<Employee> stream = list.stream(); // forEach遍歷是終止操作 stream.filter(emp -> emp.getSalary() > 7000).forEach(System.out::println); System.out.println(); // limit(n)——截斷流,使其元素不超過給定數量。 //這裏報錯,因為stream已經執行了終止操作,就不可以再調用其它的中間操作或終止操作了。要重新調用 // stream.limit(2).forEach(System.out::println); list.stream().filter(emp -> emp.getSalary() > 7000).limit(2).forEach(System.out::println); System.out.println(); // skip(n) —— 跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit(n) 互補 list.stream().skip(5).forEach(System.out::println); System.out.println(); // distinct()——篩選,通過流所生成元素的 hashCode() 和 equals() 去除重複元素 list.add(new Employee(1009, "馬斯克", 40, 12500.32)); list.add(new Employee(1009, "馬斯克", 40, 12500.32)); list.add(new Employee(1009, "馬斯克", 40, 12500.32)); list.add(new Employee(1009, "馬斯克", 40, 12500.32)); list.stream().distinct().forEach(System.out::println); } //2-映射 @Test public void test2() { //map(Function f)——接收一個函數作為參數,將元素轉換成其他形式或提取信息,該函數會被應用到每個元素上,並將其映射成一個新的元素。 //練習:轉換為大寫 List<String> list = Arrays.asList("aa", "bb", "cc", "dd"); //方式1: list.stream().map(str -> str.toUpperCase()).forEach(System.out::println); //方式2: list.stream().map(String :: toUpperCase).forEach(System.out::println); //練習:獲取員工姓名長度大於3的員工。 List<Employee> employees = EmployeeData.getEmployees(); employees.stream().filter(emp -> emp.getName().length() > 3).forEach(System.out::println); //練習:獲取員工姓名長度大於3的員工的姓名。 //方式1: employees.stream().filter(emp -> emp.getName().length() > 3).map(emp -> emp.getName()).forEach(System.out::println); //方式2: employees.stream().map(emp -> emp.getName()).filter(name -> name.length() > 3).forEach(System.out::println); //方式3: employees.stream().map(Employee::getName).filter(name -> name.length() > 3).forEach(System.out::println); } //3-排序 @Test public void test3() { //sorted()——自然排序 Integer[] arr = new Integer[]{345,3,64,3,46,7,3,34,65,68}; String[] arr1 = new String[]{"GG","DD","MM","SS","JJ"}; Arrays.stream(arr).sorted().forEach(System.out::println); System.out.println(Arrays.toString(arr));//arr原數組並沒有因為升序,做調整。 Arrays.stream(arr1).sorted().forEach(System.out::println); //因為Employee沒有實現Comparable接口,所以報錯!使用Collections.sort()或者Arrays.sort()方法對一個對象集合進行排序時,需要使用對象的自然排序規則進行比較。而默認情況下,Java並不知道如何比較一個自定義對象的大小,因此需要我們自己定義比較規則。 // List<Employee> list = EmployeeData.getEmployees(); // list.stream().sorted().forEach(System.out::println); //sorted(Comparator com)——定製排序 List<Employee> list = EmployeeData.getEmployees(); list.stream().sorted((e1,e2) -> e1.getAge() - e2.getAge()).forEach(System.out::println); //針對於字符串從大大小排列 Arrays.stream(arr1).sorted((s1, s2) -> -s1.compareTo(s2)).forEach(System.out::println); // Arrays.stream(arr1).sorted(String :: compareTo).forEach(System.out::println); } }精準練習 public class StreamAPITest2 { @Test public void test01(){ // boolean allMatch(Predicate<? super T> predicate); List<Employee> list = EmployeeData.getEmployees(); //是否所有員工可以匹配到age>100 System.out.println(list.stream().allMatch(employee -> employee.getAge() > 100)); //是否存在一個員工age>99 System.out.println(list.stream().anyMatch(employee -> employee.getAge() > 99)); // findFirst()返回第一個元素,獲取到的是第一個Optional,再調用get方法才可以獲取第一個員工: // Employee{id=1001, name='開心', age=100, salary=666888.0} System.out.println(list.stream().findFirst().get()); } @Test public void test02(){ // count 返回流中元素的總個數 // 返回流中工資大於1w的員工的總個數 List<Employee> list = EmployeeData.getEmployees(); System.out.println(list.stream().filter(employee -> employee.getSalary()>10000).count()); // max(Comparator c) 返回流中的最大值 // 打算獲取最高工資 //先返回最高(最低min)工資的員工 System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); //Method-1 獲取到員工,在獲取自身的工資即可 System.out.println(list.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).get().getSalary()); //Method-2 先映射工資在調用最高工資 Double.compare是返回一個int,只要返回int就行()--int compare(T o1, T o2); System.out.println(list.stream().map(employee -> employee.getSalary()).max((s1, s2) -> Double.compare(s1, s2)).get()); // 改為方法引用 System.out.println(list.stream().map(employee -> employee.getSalary()).max(Double::compare).get()); // forEach 內部迭代 list.stream().forEach(System.out::println); // 針對集合jdk8 增加一個遍歷的方法 -- Iterator迭代器、增強for、一般for、ForEach list.forEach(System.out::println); } @Test public void test03(){ / 歸約操作,可以將流中元素反覆結合起來,得到一個值。返回T / //T reduce(T identity, BinaryOperator<T> accumulator); //BinaryOperator 繼承 BiFunction , 其中的方法: R apply(T t, U u); List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // identity 是一個累計函數的恆等值,可以把它理解為種子,在此基礎上進行相加,比如10,x1+x2為55,則共65 System.out.println(list.stream().reduce(0, (x1, x2) -> x1 + x2)); // 改為函數式接口 System.out.println(list.stream().reduce(0, (x1, x2) -> Integer.sum(x1,x2))); System.out.println(list.stream().reduce(0, Integer::sum)); // 獲取所有員工工資總和 List<Employee> list1 = EmployeeData.getEmployees(); // 利用reduce將所有員工工資相加 System.out.println(list1.stream().map(emp -> emp.getSalary()).reduce((salary1, salary2) -> Double.sum(salary1, salary2))); System.out.println(list1.stream().map(emp -> emp.getSalary()).reduce(Double::sum)); } @Test public void test04(){ // collect(Collector c) 將流轉換為其它形式,接收一個 Collector接口的實現,用於給Stream中元素做彙總的方法 // 練習1:查找工資大於666888的員工,結果返回為一個List或Set List<Employee> list = EmployeeData.getEmployees(); List<Employee> list1 = list.stream().filter(emp -> emp.getSalary() > 666888).collect(Collectors.toList()); list1.forEach(System.out::println); System.out.println("------list2------"); // 練習2:按照員工的年齡進行排序,返回到一個新的List中 List<Employee> list2 = list.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).collect(Collectors.toList()); list2.forEach(System.out::println); } } 新特性新的語法結構,為我們勾勒出了Java語法進化的一個趨勢,將開發者從複雜、繁瑣的低層次抽象中逐漸解放出來,以更高層次、更優雅的抽象,既降低代碼量,又避免意外編程錯誤的出現,進而提高代碼質量和開發效率。
即興語錄
世界就像人類掌控螞蟻、多維掌控三維一樣簡單而又複雜且又微妙(以前的個性簽名,放到這裏做個記錄)