參考文章:
https://www.runoob.com/java/java8-streams.html
Java 8 新特性
Java 8 (又稱爲 jdk 1.8) 是 Oracle 公司於 2014 年 3 月 18 日發佈的一個主要版本Java 語言開發的。支持函數式編程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
新特性
Java8 新增了非常多的特性,我們主要討論以下幾個:
-
Lambda 表達式 − Lambda 允許把函數作爲一個方法的參數。
-
Stream API −新添加的Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。
-
方法引用 − 方法引用提供了非常有用的語法,可以直接引用已有Java類或對象(實例)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗餘代碼。
-
Optional 類 − Optional 類已經成爲 Java 8 類庫的一部分,用來解決空指針異常。
-
Date Time API − 加強對日期與時間的處理。
-
默認方法 − 默認方法就是一個在接口裏面有了一個實現的方法。
-
Nashorn, JavaScript 引擎 − Java 8提供了一個新的Nashorn javascript引擎,它允許我們在JVM上運行特定的javascript應用。
Lambda 表達式,也可稱爲閉包,它是推動 Java 8 發佈的最重要新特性,允許把函數作爲一個方法的參數。使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。
語法
lambda 表達式的語法格式如下 parameters爲參數值,expression 爲接口執行結果表達式:
(parameters) -> expression 或 (parameters) ->{ statements; } 其中parameters不需要聲明參數類型,編譯器可統一識別參數值。
Lambda 表達式實例
// 1. 不需要參數,返回值爲 5
() -> 5
// 2. 接收一個參數(數字類型),返回其2倍的值
x -> 2 * x
// 3. 接受2個參數(數字),並返回他們的差值
(x, y) -> x – y
// 4. 接收2個int型整數,返回他們的和
(int x, int y) -> x + y
// 5. 接受一個 string 對象,並在控制檯打印,不返回任何值(看起來像是返回void)
(String s) -> System.out.print(s)
public class Java8Tester {
public static void main(String args[]){
List<String> names1 = new ArrayList<String>();
names1.add("Google ");
names1.add("Runoob ");
names1.add("Taobao ");
List<String> names2 = new ArrayList<String>();
names2.add("Google ");
names2.add("Runoob ");
names2.add("Taobao ");
System.out.println("使用 Java 7 語法: ");
Collections.sort(names1, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});
System.out.println(names1);
System.out.println("使用 Java 8 語法: ");
//Collections.sort(names, (s1,s2) -> s1.compareTo(s2) ); 不定義類型也是可以的
Collections.sort(names2, (String s1, String s2) -> s1.compareTo(s2) );
System.out.println(names2);
}
}
方法引用通過方法的名字來指向一個方法。方法引用中::後只是方法名,不能加(); 可以使語言的構造更緊湊簡潔,減少冗餘代碼,使用兩對冒號 : :。
list.forEach((s) -> System.out.println(s)); 使用方法引用後變成 list.forEach(Syetem.out::println);
https://www.runoob.com/java/java8-method-references.html
Java 8 API添加了一個新的抽象稱爲流Stream,可以讓你以一種聲明的方式處理數據,極大提高Java程序員的生產力。
Stream 使用一種類似用 SQL 語句從數據庫查詢數據的直觀方式來提供一種對 Java 集合運算和表達的高階抽象。
這種風格將要處理的元素集合看作一種流, 流在管道中傳輸, 並且可以在管道的節點上進行處理, 比如篩選, 排序,聚合等。
元素流在管道中經過中間操作(intermediate operation)的處理,最後由最終操作(terminal operation)得到前面處理的結果。
什麼是 Stream?
Stream(流)是一個來自數據源的元素隊列並支持聚合操作
- 元素是特定類型的對象,形成一個隊列。 Java中的Stream並不會存儲元素,而是按需計算。
- 數據源 流的來源。 可以是集合,數組,I/O channel, 產生器generator 等。
- 聚合操作 類似SQL語句一樣的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作還有兩個基礎的特徵:
- Pipelining: 中間操作都會返回流對象本身。 這樣多個操作可以串聯成一個管道, 如同流式風格(fluent style)。 這樣做可以對操作進行優化, 比如延遲執行(laziness)和短路( short-circuiting)。
- 內部迭代: 以前對集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進行迭代, 這叫做外部迭代。 Stream提供了內部迭代的方式, 通過訪問者模式(Visitor)實現。
List<Integer> transactionsIds = widgets.stream() .filter(b -> b.getColor() == RED) //過濾顏色爲紅色 .sorted((x,y) -> x.getWeight() - y.getWeight()) //通過weight排序 .mapToInt(Widget::getWeight) //getWeight通過這個方法獲得對應int值 .sum(); //求總和 List<SysUser> arrayList = new ArrayList<>(); SysUser sysUser1 = new SysUser(); sysUser1.setMailAddr("1"); SysUser sysUser2 = new SysUser(); sysUser2.setMailAddr(""); arrayList.add(sysUser1); arrayList.add(sysUser2); List<SysUser> userByRoleId = arrayList.stream().filter(sysUser -> StringUtils.isNotEmpty(sysUser.getMailAddr())).collect(Collectors.toList()); List<String> mailList = arrayList.stream().filter(sysUser -> StringUtils.isNotEmpty(sysUser.getMailAddr())).map(SysUser::getMailAddr).collect(Collectors.toList());
forEach Stream 提供了新的方法 'forEach' 來迭代流中的每個數據。以下代碼片段使用 forEach 輸出了10個隨機數:
Random random = new Random();
//ints創建的是無限流 通過limit限制個數
random.ints().limit(10).forEach(System.out::println); //System.out::println 作爲靜態方法來引用
map 中間操作map會將元素根據指定的Function接口來依次將元素轉成另外的對象( 將一個流中的值轉換成一個新的流 )
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());List<String> strings = Arrays.asList("Google", "Runoob", "Taobao");
//將元素變大寫 返回List<String>
List<String> collect = strings.stream().map(s -> s.toUpperCase()).collect(Collectors.toList());//lamda表達式 return返回值 List<String> collect22 = strings.stream().map(s -> { String concat = s.concat(" java"); return concat; }).collect(Collectors.toList());
//將元素變大寫 返回Set<String>
Set<String> collect = strings.stream().map(s -> s.toUpperCase()).collect(Collectors.toCollection(TreeSet::new));//string轉list<Integer>
List<Integer> caseIdsArr = Arrays.stream("1,2".split(",")).map(s -> Integer.valueOf(s.trim())).collect(Collectors.toList());
List<Integer> caseIdsArr = Arrays.asList((Integer[]) ConvertUtils.convert("1,2".split(","),Integer.class));
filter 用於通過設置的條件過濾出元素。以下代碼片段使用 filter 方法過濾出空字符串:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl", "2lm");
//獲取數字開頭的元素
List<String> list2 = strings .stream().filter((s) -> Character.isDigit(s.charAt(0))).collect(Collectors.toList());//集合去除空字符串 //Stream<T> filter(Predicate<? super T> predicate);
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());//等同於下面的表達式 stream() − 爲集合創建串行流。
List<String> filtered1 = strings.stream().filter(new Predicate<String>() {
@Override
public boolean test(String string) {
return !string.isEmpty();
}
}).collect(Collectors.toList());//獲取空字符串的數量
long count = strings.stream().filter(string -> string.isEmpty()).count();
//篩選字符串長度==3的字符串 string->string.length()==3其實就是test方法的方法體
List<String> filtered1 = strings.stream().filter(string->string.length()==3).collect(Collectors.toList());@FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); }
limit 用於獲取指定數量的流。 以下代碼片段使用 limit 方法打印出 10 條數據:
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted 用於對流進行排序。以下代碼片段使用 sorted 方法對輸出的 10 個隨機數進行排序:
random.ints().limit(10).sorted().forEach(System.out::println);
skip:與limit互斥,使用該方法跳過元素
// 跳過前三個元素,從第四個開始輸出
list.stream().skip(3).forEach(user -> System.out.println(user))
stream 流中的分頁操作
一個skip和一個limit,skip代表着要跳過結果集中的前幾個數據,limit也就是取結果集中的幾個數據
stream.skip(2).limit(2).forEach(s -> System.out.println(s));
Collectors Collectors 類實現了很多歸約操作,例如將流轉換成集合和聚合元素。Collectors 可用於返回列表或字符串:
List<String> strings = Arrays.asList("abc","","bc","efg","abcd","","jkl"); List<String> filtered = strings.stream().filter(string->!string.isEmpty()).collect(Collectors.toList()); System.out.println("篩選列表: "+filtered); String mergedString=strings.stream().filter(string->!string.isEmpty()).collect(Collectors.joining(", ")); System.out.println("合併字符串: "+mergedString);
統計 產生統計結果的收集器。它們主要用於int、double、long等基本類型上
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的數 : " + stats.getMax());
System.out.println("列表中最小的數 : " + stats.getMin());
System.out.println("所有數之和 : " + stats.getSum());
System.out.println("平均數 : " + stats.getAverage());
Optional
private static BigDecimal fetchMallprice(SkuVO skuVO) throws Exception { return Optional.ofNullable(skuVO) .map(s -> s.getPrice()) //此方法有個判空處理 如果爲null 則直接執行 orElseThrow方法 .map(p -> p.getMallPrice()) .filter(m -> m.compareTo(new BigDecimal("10")) == 1) //也有個判空處理 .orElseThrow(() -> new Exception("skuVO不合法")); }//String[]--->Integer[]
String ids =null; List<Integer> collect = Arrays.stream(Optional.ofNullable(ids).orElse("").split(",")) .filter(s -> StringUtils.isNotEmpty(s)) .map(s -> Integer.valueOf(s)).collect(Collectors.toList());
Optional是jdk1.8出的新特性,其實思想挺簡單的,就是把實體包裝了一層,包裝的時候,如果是實體爲空,則返回一個空的Optional,否則返回Optional。
Optional.ofNullable(skuVO)首先構造一個Optional,map(Function<? super T, ? extends U> mapper)接收一個Funtion,filter過濾map返回的值,最後通過orElseThrow拋出異常。
https://www.cnblogs.com/kobelieve/p/11265651.html
https://blog.csdn.net/zknxx/article/details/78586799