JAVA8新特性 Lambda表达式、双冒号、streamm详解
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);});