JDK8新特性

  • 2019 年 12 月 31 日
  • 筆記

文章目錄

1. JDk8新特性

1.1. 函數式編程

1.1.1. 集合的foreach

1.1.2. lambda表達式輕鬆創建介面實例

1.1.3. 介面的默認方法和靜態方法

1.1.4. Stream

1.1.4.1. filter

1.1.4.2. sorted

1.1.4.3. 查找和匹配

1.1.4.4. 歸約

1.1.4.4.1. map

1.1.4.4.2. reduce

1.1.4.5. 分組

1.2. Optional

1.3. Collectors

1.3.1. toMap

1.3.2. toList

1.3.3. toSet

1.3.4. groupingBy

JDk8新特性

函數式編程

集合的foreach

  • List
    • 這裡的表示List中每一個元素,可以不指定類型,JDK會自動推測出類型,但是也是可以使用()加上類型
    • 如果有一條語句可以直接在後面輸出,如果有多行,那麼可以在後面使用{}指定
Arrays.asList(1,2,4,1,76).forEach(e-> System.out.println(e));    Arrays.asList(1,2,4,1,76).forEach((Integer e)-> System.out.println(e)); 
  • Set
Set<Object> set=new HashSet<>(Arrays.asList(1,2,4,1,76));     set.forEach(e-> System.out.println(e));
  • Map
Map<Object,Object> map=new HashMap<>();        map.put("2",2);        map.put("4",5);        //a,b兩個元素分別是key和value        map.forEach((a,b)->{            System.out.println(a+"---"+b);        });

lambda表達式輕鬆創建介面實例

  • 條件:該介面只能有一個需要實現的方法(默認方法除外)
    • ()->{}:無參數的實現
    • item->{}:單個參數的實現,jdk能夠默認推斷出參數的類型
    • (String item1,String item2):指定參數的類型
  • FunctionalInterface:標記這個介面只能定義一個方法(除了默認的方法)
@FunctionalInterface  public interface UserService {      String display(String name);  }  @Test     public void test1(){         UserService userService=name -> {             return name;         };         userService.display("che");     }

介面的默認方法和靜態方法

  • 默認方法不需要實現,但是可以被覆蓋
public interface Demo1 {    	/**  	 * 介面的靜態方法  	 */  	static void display() {  		System.out.println("cdc");  	}    	/**  	 * 默認方法可以不實現,但是可以被覆蓋  	 */  	default void play() {  		System.out.println("cdddd");  	}  }

Stream

  • Stream介面中包含許多對流操作的方法,這些方法分別為:
    • filter():對流的元素過濾
    • map():將流的元素映射成另一個類型
    • distinct():去除流中重複的元素
    • sorted():對流的元素排序
    • forEach():對流中的每個元素執行某個操作
    • peek():與forEach()方法效果類似,不同的是,該方法會返回一個新的流,而forEach()無返回
    • limit():截取流中前面幾個元素
    • skip():跳過流中前面幾個元素
    • toArray():將流轉換為數組
    • reduce():對流中的元素歸約操作,將每個元素合起來形成一個新的值
    • collect():對流的匯總操作,比如輸出成List集合
    • anyMatch():匹配流中的元素,類似的操作還有allMatch()和noneMatch()方法
    • findFirst():查找第一個元素,類似的還有findAny()方法
    • max():求最大值
    • min():求最小值
    • count():求總數

filter

  • 過濾集合,實際是實現其中的test方法,返回的是一個Boolean類型的值,我們可以使用lambda表達式可以很輕鬆的實現集合的過濾
@Test     public void test2(){         User user1 = new User();         user1.setName("chen");         user1.setAge(22);         User user3 = new User();         user3.setName("zheng");         user3.setAge(22);         User user2 = new User();         user2.setName("zhou");         user2.setAge(30);         List<User> users=new ArrayList<>();         users.add(user1);         users.add(user2);         users.add(user3);  /* 下面的語句類似如下          *   users.stream().filter(item->item.getAge()>25).collect(Collectors.toList());          */         List<User> collect = users.stream().filter(user -> {             if (user.getAge() > 25) {                 return true;             } else {                 return false;             }         }).collect(Collectors.toList());     }

sorted

  • 有兩個實現的方法,如下:
Stream<T> sorted(Comparator<? super T> comparator);  Stream<T> sorted();
例子如下:  Stream.of(1, 8, 5, 2, 1, 0, 9, 2, 0, 4, 8)      .filter(n -> n > 2)     // 對元素過濾,保留大於2的元素      .distinct()             // 去重,類似於SQL語句中的DISTINCT      .skip(1)                // 跳過前面1個元素      .limit(2)               // 返回開頭2個元素,類似於SQL語句中的SELECT TOP      .sorted()               // 對結果排序      .forEach(System.out::println);  
//按照age排序,實際上就是實現Comparator的介面方法compareTo        users.sort((item1,item2)->{            return item1.getAge()-item2.getAge();        });

查找和匹配

  • Stream中提供的查找方法有anyMatch()、allMatch()、noneMatch()、findFirst()、findAny(),這些方法被用來查找或匹配某些元素是否符合給定的條件:
// 檢查流中的任意元素是否包含字元串"Java"  boolean hasMatch = Stream.of("Java", "C#", "PHP", "C++", "Python")          .anyMatch(s -> s.equals("Java"));  // 檢查流中的所有元素是否都包含字元串"#"  boolean hasAllMatch = Stream.of("Java", "C#", "PHP", "C++", "Python")          .allMatch(s -> s.contains("#"));  // 檢查流中的任意元素是否沒有以"C"開頭的字元串  boolean hasNoneMatch = Stream.of("Java", "C#", "PHP", "C++", "Python")          .noneMatch(s -> s.startsWith("C"));  // 查找元素  Optional<String> element = Stream.of("Java", "C#", "PHP", "C++", "Python")          .filter(s -> s.contains("C"))          // .findFirst()     // 查找第一個元素          .findAny();         // 查找任意元素

歸約

map
  • map 方法用於映射每個元素到對應的結果,以下程式碼片段使用 map 輸出了元素對應的平方數:
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);  // 獲取對應的平方數  List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
  • map使用lambda表達式返回的類型就是最後的類型,下面我們將用戶的年齡設置成兩倍
@Test     public void test2(){         User user1 = new User();         user1.setName("chen");         user1.setAge(22);         User user3 = new User();         user3.setName("zheng");         user3.setAge(22);         User user2 = new User();         user2.setName("zhou");         user2.setAge(40);         List<User> users=new ArrayList<>();         users.add(user1);         users.add(user2);         users.add(user3);         List<User> list = users.stream().map(item -> {             item.setAge(item.getAge() * 2);             return item;         }).collect(Collectors.toList());     }
reduce
  • 將兩個元素進行歸約操作,比如兩個元素相加,但是這個操作的返回值一定要和操作之前的類型相同//歸約操作,返回的是一個Optional類型的
//歸約操作,返回的是一個Optional類型的          Optional<Integer> optional = users.stream().map(item -> item.getAge()).reduce((item1, item2) -> item1 + item2);          if (optional.isPresent()){              System.out.println(optional.get());          }

分組

  • 和關係資料庫一樣,流也提供了類似於資料庫中GROUP BY分組的特性,由Collectors.groupingBy()方法提供:
/根據age進行分組,返回的是Map集合,key就是分組後的age,value是user對象          Map<Integer, List<User>> listMap = users.parallelStream().collect(Collectors.groupingBy(item -> item.getAge()));          listMap.forEach((key,value)->{              System.out.println(key+"--->"+value);          });
  • 但實際情況可能比這複雜,比如將價格在0-50之間的書籍分成一組,50-100之間的分成一組,超過100的分成一組,這時候,我們可以直接使用Lambda表達式來表示這個分組邏輯:
//根據age進行分組,返回的是Map集合,key就是分組後的age,value是user對象          Map<String, List<User>> listMap = users.parallelStream().collect(Collectors.groupingBy(item -> {              if (item.getAge() > 20) {                  return "A";              } else {                  return "B";              }          }));          listMap.forEach((key,value)->{              System.out.println(key+"--->"+value);          });

Optional

  • 文檔
  • https://zhuanlan.zhihu.com/p/40966718
  • 創建方法:
    • public static <T> Optional<T> of(T value):value的值不能為null
    • public static <T> Optional<T> ofNullable(T value):value允許為空
  • 常用方法
    • public Optional<T> filter(Predicate<? super T> predicate):過濾其中的元素,如果返回true,那麼保留,返回false去除該元素
    • public T orElse(T other):如果該元素的值為null,那麼指定該值為other
User user = new User(22, "chenjiabing");  User user2 = Optional.ofNullable(user).filter(item->{  	return item.getAge()>30;  }).orElse(null);
  • public T orElseGet(Supplier<? extends T> other):如果該值為空,那麼就調用other的get方法,其中返回一個同種類型的對象
Optional.ofNullable(user).filter(item->{  	return item.getAge()>30;  }).orElseGet(()->{  	System.out.println("該值為空");  	return new User(44, "zhengjiahe");  });
  • public boolean isPresent():判斷當前的元素是否為null,如果為null返回false,否則返回true
  • public void ifPresent(Consumer<? super T> consumer):如果不為空調用其中的方法
  • public <U> Optional<U> map(Function<? super T,? extends U> mapper):如果為空直接返回一個空的Optional,不會調用map中的apply方法,如果不為空,那麼調用apply方法
Optional<Integer> map = Optional.ofNullable(null).map(item->{  	System.out.println(item);  	//返回值也決定著你的類型  	return Integer.MAX_VALUE;  });

Collectors

  • 針對集合操作的封裝類,結合Stream編程客可以很簡單的實現

toMap

  • List直接轉換為Map,使用JDK1.8的Stream編程
  • Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper):簡單的將集合轉換成Map,出現key重複的將直接拋出異常
    • keyMapper:指定的
    • valueMapper:指定的value
   Map<Integer, String> map = users.stream().collect(Collectors.toMap(User::getAge, User::getName));  `
  • public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper,BinaryOperator<U> mergeFunction):用於解決key衝突的情況
    • mergeFunction:用於當出現key衝突的情況下解決方法,其中只需要實現apply方法即可,兩個參數分別是重複的map的value值,返回值是指定的值
Map<Integer, String> map = users.stream().collect(Collectors.toMap(User::getAge, User::getName,(v1,v2)->v1+","+v2));  toList
  • 將結果轉換成一個List集合
List<Integer> list = Stream.of(1, 2, 3, 4).collect(Collectors.toList()); 

toSet

  • 將結果轉換成一個Set集合Set
<Integer> set = Stream.of(1, 2, 3, 4).collect(Collectors.toSet()); 

groupingBy

  • 將所得的結果根據指定的內容進行分組,所得結果是一個Map類型的數據
  • public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
    • 指定的key,value的默認類型為
Map<Integer, List<Integer>> map = Stream.of(1, 1, 3, 10, 2, 3, 4).collect(             Collectors.groupingBy(Integer::intValue));

`public static    Collector> groupingBy(Function<? super T, ? extends K> classifier,   Collector<? super T, A, D> downstream)`  
  • 第一個參數是指定的key,第二個參數是指定的value的類型
Map<Integer, Set<Integer>> map = Stream.of(1, 1, 3, 10, 2, 3, 4).collect(             Collectors.groupingBy(Integer::intValue, Collectors.toSet()));