Lambda 允許把函數作為參數傳遞進方法中。
不是每個接口都可以縮寫成 Lambda 表達式。只有那些函數式接口(Functional Interface)才能縮寫成 Lambda 表示式。
所謂函數式接口(Functional Interface)就是只包含一個抽象方法的聲明。
只要接口中僅僅包含一個抽象方法,我們就可以將其改寫為 Lambda 表達式。為了保證一個接口明確的被定義為一個函數式接口(Functional Interface),我們需要為該接口添加注解:@FunctionalInterface。這樣,一旦你添加了第二個抽象方法,編譯器會立刻拋出錯誤提示。
Lambda表達式的重要特征:
可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
可選的大括號:如果主體包含了一個語句,就不需要使用大括號。
可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。
變量作用域
lambda 表達式只能引用標記了 final 的外層局部變量,這就是說不能在 lambda 內部修改定義在域外的局部變量,否則會編譯錯誤。
Lambda表達式的基本語法:
(parameters) -> expression 或 (parameters) ->{ statements; }
Lambda小程序,遍歷 List 集合
String[] array = {"a","b","c"}; List<String> list = Arrays.asList(array); System.out.println("方式一:原始方式"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } System.out.println("方式二:增強 for 循環"); for (String s : list) { System.out.println(s); } System.out.println("方式三:lambda 表達式"); list.forEach( e -> System.out.println(e) ); System.out.println("方式四:lambda 表達式"); list.forEach( (e) -> {System.out.println(e);} ); System.out.println("方式五:lambda 表達式 之 靜態方法引用"); list.forEach(System.out::println);
Lambda 小程序,使用 Lambda 表達式實現匿名內部類
System.out.println("方式一:匿名內部類實現 Runnable接口 run 方法,並使用多線程運行"); new Thread(new Runnable() { @Override public void run() { System.out.println("Hello world !"); } }).start(); System.out.println("方式一:Lambda 實現 Runnable接口,並使用多線程運行"); new Thread(() -> System.out.println("Hello world !")).start(); System.out.println("方式二:匿名內部類實現 Runnable接口 run 方法"); Runnable r1 = new Runnable() { @Override public void run() { System.out.println("Hello world !"); } }; r1.run(); System.out.println("方式二:Lambda 實現 Runnable接口"); Runnable r2 = () -> System.out.println("Hello world !"); r2.run();
真實應用示例(forEach):
// 遍歷比較 Set<DeptItem> itemList = entity.getRppDeptItem(); if(entity.getDatasource().equals(DeptDateSourceEnum.nc.getCode())){ itemList.forEach(item->{ if(item.getNcid() == null && item.getPersistStatus().equals(PersistStatus.ADDED)){ throw new RuntimeException("來源NC部門不允許在主數據新增崗位" ); } }); }
雙冒號 ::
雙冒號運算符在Java 8中被用作方法引用,方法引用是與 lambda 表達式相關的一個重要特性。它提供了一種不執行方法的方法。為此,方法引用需要由兼容的函數接口組成的目標類型上下文。
使用lambda表達式會創建匿名方法, 但有時候需要使用一個lambda表達式只調用一個已經存在的方法(不做其它), 所以這才有了方法引用!
以下是Java 8中方法引用的一些語法:
靜態方法引用語法:classname::methodname 例如:Person::getAge
對象的實例方法引用語法:instancename::methodname 例如:System.out::println
對象的超類方法引用語法: super::methodname
類構造器引用語法: classname::new 例如:ArrayList::new
數組構造器引用語法: typename[]::new 例如: String[]:new
簡要:https://www.cnblogs.com/maohuidong/p/11527681.html
詳細:https://blog.csdn.net/zhoufanyang_china/article/details/87798829
真實應用示例(stream、::):
// list轉換成數組 List<String> list = Arrays.asList("a","b","c"); String[] arrays = list.stream().toArray(String[]::new); for (String array : arrays) { System.out.println(array); }
Stream
采用java8 lambda表達式 實現 java list 交集 並集 差集 去重復並集
Java 8 中的 Stream 是對集合(Collection)對象功能的增強,使用的是函數式編程模式,它可以對集合進行鏈狀流式的操作,它專注於對集合對象進行各種非常便利、高效的聚合操作(aggregate operation),或者大批量數據操作 (bulk data operation)。Stream API 借助於同樣新出現的 Lambda 表達式,極大的提高編程效率和程序可讀性。
流的執行:
當存在終端操作時,中間操作操作才會被執行。
入門看我:https://www.jianshu.com/p/11c925cdba50
一般詳細:https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html#icomments
非常詳細:https://juejin.im/post/5cc124a95188252d891d00f2
真實應用示例(stream.map):
// 小寫字母轉換為大寫字母 List<String> collected1 = Arrays.asList("alpha","beta"); collected1 = collected1.stream().map(string -> string.toUpperCase()).collect(Collectors.toList()); System.out.println(collected1);
真實應用示例(stream.map):
// string轉換為list String ids = "1,2,3 ,4,5"; List<Long> listIds = Arrays.asList(ids.split(",")).stream().map(e -> Long.valueOf(e.trim())).collect(Collectors.toList()); System.out.println(listIds);
真實應用示例(stream.map):
// 獲取到所有商品ID // List<ProductSkuImageDto> resultList = updateProductSkuValues(addedList, modifiedList, deletedList); // 寫法一 List<String> productIdsList = resultList.stream().map(ProductSkuImageDto::getProductId).collect(Collectors.toList()); // 寫法二 List<String> productIdsList = resultList.stream().map(e -> e.getProductId()).collect(Collectors.toList());
真實應用示例(stream.forEach):
// 遍歷值放到map中 protected Map<String, GoodsBomDto> getBomInfos(Set<String> parentGoodsIds){ if(CollectionUtils.isEmpty(parentGoodsIds)){ return new HashMap<>(0); } List<GoodsBomDto> goodsBomDtos = goodsBomApi.goodsBomByParentGoodId(String.join(",", parentGoodsIds)).getBody(); if(CollectionUtils.isEmpty(goodsBomDtos)){ return new HashMap<>(0); } Map<String, GoodsBomDto> parentGoodsId_bomMap = new HashMap<>(goodsBomDtos.size()); goodsBomDtos.stream().forEach(goodsBomDto -> parentGoodsId_bomMap.put(goodsBomDto.getParentGoodsId(), goodsBomDto)); return parentGoodsId_bomMap;
真實應用示例(stream.forEach):
// 給實體里面的數字,設置一個值 protected void set_Status(List<UnitAdapter> data, String operation) { data.stream().forEach(unitAdapter -> unitAdapter.set_status(operation));
入門小程序:
List<String> list = Arrays.asList("abc", "def", "1234"); System.out.println("統計字符長度"); System.out.println("方式一:lambda表達式"); list.stream().map(e -> e.length()).forEach(e -> System.out.println(e)); System.out.println("方式二:函數引用"); list.stream().map(String :: length).forEach(System.out::println); System.out.println("mapToInt 將數據流中的元素結果轉換為 int 類型"); list.stream().mapToInt(e -> e.length()).forEach(e -> System.out.println(e)); System.out.println("mapToDouble 將數據流中的元素結果轉換為 Double 類型"); list.stream().mapToDouble(e -> e.length()).forEach(e -> System.out.println(e)); List<String> list2 = Arrays.asList("a-b-c-d","e-f-i-g-h"); System.out.println("flatmap 作用就是將元素拍平拍扁"); // flatmapToInt、flatmapToLong、flatmapToDouble 跟flatMap 都類似的,只是類型被限定了 list2.stream().flatMap(e -> Stream.of(e.split("-"))).forEach(e -> System.out.println(e)); System.out.println("limit 限制顯示元素的個數"); List<Integer> list3 = Arrays.asList(1,2,3,4,5,6); list3.stream().limit(3).forEach(e -> System.out.println(e)); System.out.println("distinct 去重"); List<Integer> list4 = Arrays.asList(1,2,3,1,2,5,6,7,8,0,0,1,2,3,1); list4.stream().distinct().forEach(e -> System.out.println(e)); System.out.println("filter 過濾"); list4.stream().filter(e -> e<3).forEach(e -> System.out.println(e)); System.out.println("skip 跳過前幾個元素"); List<String> list5 = Arrays.asList("a","b","c"); list5.stream().skip(2).forEach(e -> System.out.println(e)); System.out.println("sorted 排序,底層依賴Comparable 實現"); list4.stream().sorted().forEach(e -> System.out.println(e)); System.out.println("collect(Collectors.toSet()) 將元素收集到 Set 中"); List<String> list6 = Arrays.asList("apple", "banana", "orange", "waltermaleon", "grape"); list6.stream().collect(Collectors.toSet()).forEach(e -> System.out.println(e)); System.out.println("count 統計數據流中的元素個數"); System.out.println(list6.stream().count()); System.out.println("findFirst 獲取第一個元素"); System.out.println(list6.stream().findFirst()); System.out.println("findAny 隨機獲取一個元素"); System.out.println(list6.stream().parallel().findAny()); System.out.println("noneMatch 集合中是否不存在指定字符,如果不存在返回 true,否則返回 false"); System.out.println(list6.stream().noneMatch(e -> e.equals("orange"))); System.out.println("anayMatch 集合中是否存在指定字符,如果存在返回 true,否則返回 false"); System.out.println(list6.stream().anyMatch(e -> e.equals("orange"))); System.out.println("min 查找最小的元素"); List<Integer> list7 = Arrays.asList(1,2,3,4,5,6); System.out.println(list7.stream().min((e1, e2) -> e1.compareTo(e2))); System.out.println("max 查找最大的元素"); System.out.println(list7.stream().max((e1, e2) -> e1.compareTo(e2))); System.out.println("reduce 是一個規約操作,所有的元素歸約成一個,比如對所有元素求和"); System.out.println(list7.stream().reduce(0, (e1, e2) -> e1+e2)); System.out.println("forEachOrdered 適用用於並行流的情況下進行迭代,能保證迭代的有序性"); Stream.of(0,2,6,5,4,9,8,-1) .parallel() .forEach(e->{ System.out.println(Thread.currentThread().getName()+": "+e);});