JDK8新特性
- 2019 年 12 月 31 日
- 筆記
文章目錄
JDk8新特性
函數式編程
集合的foreach
- List
- 這裡的表示List中每一個元素,可以不指定類型,JDK會自動推測出類型,但是也是可以使用
()
加上類型 - 如果有一條語句可以直接在後面輸出,如果有多行,那麼可以在後面使用{}指定
- 這裡的表示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的值不能為nullpublic 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,否則返回truepublic 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()));