【Java8特性】

根据属性过滤list中存放的对象

Students stu1=new Students();
stu1.SetId(“123”);
stu1.SetName(“张三”);
stu1.SetAge(18);
Students stu2=new Students();
stu2.SetId(“123”);
stu2.SetName(“李四”);
stu2.SetAge(19);
Students stu3=new Students();
stu3.SetId(“123”);
stu3.SetName(“李四”);
stu3.SetAge(19);
List stuList=new ArrayList<>();
stuList.add(stu1);
stuList.add(stu2);
List newList=stuList.stream.collect(
Collectors.collectingAndThen(
Collectors.toCollection(()->new TreeSet<>(
Comparator.comparing(Students::getName))),ArrayList::new)
.collect(Collectors.toList);

规约(reduce)

对流中的元素按照一定的策略计算。终止操作的底层逻辑都是由 reduce 实现的。

终止操作

收集(collect)将流中的中间(计算)结果存储到集合中,方便后续进一步使用。为了方便对收集操作的理解,方便读者掌握收集操作,将收集分为普通收集和高级收集。
1、普通收集
(1)收集为List
默认返回的类型为ArrayList,可通过Collectors.toCollection(LinkedList::new)显示指明使用其它数据结构作为返回值容器。
例子:
List collect = stream.collect(Collectors.toList());
由集合创建流的收集需注意:仅仅修改流字段中的内容,没有返回新类型,如下操作直接修改原始集合,无需处理返回值。
例子:
// 直接修改原始集合
userVos.stream().map(e -> e.setDeptName(hashMap.get(e.getDeptId()))).collect(Collectors.toList());
(2)收集为Set
默认返回类型为HashSet,可通过Collectors.toCollection(TreeSet::new)显示指明使用其它数据结构作为返回值容器。
例子:
Set collect = stream.collect(Collectors.toSet());
2、高级收集
(1)收集为Map
默认返回类型为HashMap,可通过Collectors.toCollection(LinkedHashMap::new)显示指明使用其它数据结构作为返回值容器。
收集为Map的应用场景更为强大,下面对这个场景进行详细介绍。希望返回结果中能够建立ID与NAME之间的匹配关系,最常见的场景是通过ID批量到数据库查询NAME,返回后再将原数据集中的ID替换成NAME。
ID 到 NAME 映射

@Data
public class ItemEntity {
private Integer itemId;
private String itemName;
}
准备集合数据,此部分通常是从数据库查询的数据
例子:
// 模拟从数据库中查询批量的数据
List entityList = Stream.of(new ItemEntity(1,“A”), new ItemEntity(2,“B”), new ItemEntity(3,“C”)).collect(Collectors.toList());

将集合数据转化成 ID 与 NAME 的 Map
例子:
// 将集合数据转化成ID与NAME的Map
Map<Integer, String> hashMap = entityList.stream().collect(Collectors.toMap(ItemEntity::getItemId, ItemEntity::getItemName));

ID与Object类映射

@Data
public class ItemEntity {
private Integer itemId;
private String itemName;
private Boolean status;
}
将集合数据转化成 ID 与实体类的 Map
例子:
// 将集合数据转化成ID与实体类的Map
Map<Integer, ItemEntity> hashMap = entityList.stream().collect(Collectors.toMap(ItemEntity::getItemId, e -> e));

其中Collectors类中的toMap参数是函数式接口参数,能够自定义返回值。
例子:
public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper) {
return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}

分组收集

流的分组收集操作在内存层次模拟了数据库层面的group by操作,下面演示流的分组操作。[Collectors]类提供了各种层次的分组操作支撑。流的分组能力对应数据库中的聚合函数,目前大部分能在数据库中操作的聚合函数,都能在流中找到相应的能力。

// 默认使用List作为分组后承载容器
Map<Integer, List> hashMap = xUsers.stream().collect(Collectors.groupingBy(XUser::getDeptId));

// 显示指明使用List作为分组后承载容器
Map<Integer, List> hashMap = xUsers.stream().collect(Collectors.groupingBy(XUser::getDeptId, Collectors.toList()));

映射后再分组

Map<Integer, List> hashMap = xUsers.stream().collect(Collectors.groupingBy(XUser::getDeptId,Collectors.mapping(XUser::getUserName,Collectors.toList())));

Stream 拓展

(一)集合与对象互转
将对象包装成集合的形式和将集合拆解为对象的形式是常见的操作。
1、对象转集合
返回默认类型的集合实例
/**

  • 将单个对象转化为集合
  • @param t 对象实例
  • @param 对象类型
  • @param 集合类型
  • @return 包含对象的集合实例
    */
    public static <T, C extends Collection> Collection toCollection(T t) {
    return toCollection(t, ArrayList::new);
    }

用户自定义返回的集合实例类型
/**

  • 将单个对象转化为集合
  • @param t 对象实例
  • @param supplier 集合工厂
  • @param 对象类型
  • @param 集合类型
  • @return 包含对象的集合实例
    */
    public static <T, C extends Collection> Collection toCollection(T t, Supplier supplier) {
    return Stream.of(t).collect(Collectors.toCollection(supplier));
    }

2、集合转对象

使用默认的排序规则,注意此处不是指自然顺序排序。

/**

  • 取出集合中第一个元素
  • @param collection 集合实例
  • @param 集合中元素类型
  • @return 泛型类型
    */
    public static E toObject(Collection collection) {
    // 处理集合空指针异常
    Collection coll = Optional.ofNullable(collection).orElseGet(ArrayList::new);
    // 此处可以对流进行排序,然后取出第一个元素
    return coll.stream().findFirst().orElse(null);
    }

上述方法巧妙的解决两个方面的异常问题:一是集合实例引用空指针异常;二是集合下标越界异常。
(二)其它
1、并行计算
基于流式计算中的并行流,能够显著提高大数据下的计算效率,充分利用 CPU 核心数。

// 通过并行流实现数据累加
LongStream.rangeClosed(1,9999999999999999L).parallel().reduce(0,Long::sum);

2、序列数组

生成指定序列的数组或者集合。

// 方式一:生成数组
int[] ints = IntStream.rangeClosed(1, 100).toArray();
// 方式二:生成集合
List list = Arrays.stream(ints).boxed().collect(Collectors.toList());

其它

(一)新日期时间 API

1、LocalDateTime
// 获取当前日期(包含时间)
LocalDateTime localDateTime = LocalDateTime.now();
// 获取当前日期
LocalDate localDate = localDateTime.toLocalDate();
// 获取当前时间
LocalTime localTime = localDateTime.toLocalTime();

日期格式化:

// 月份MM需要大写、小时字母需要大写(小写表示12进制)
DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”)
// 获取当前时间(字符串)
String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”));
System.out.println("dateTime = " + dateTime);

2、Duration

Duration duration = Duration.between(Instant.now(), Instant.now());
System.out.println("duration = " + duration);

3、获取当前时间戳

如下方式获取的是 13 位时间戳,单位是毫秒。

// 方式一
long now = Timestamp.valueOf(LocalDateTime.now()).getTime();
// 方式二
long now = Instant.now().toEpochMilli();

Optional

在[Optional]类出现之前,null异常几乎折磨着每一位开发者,为了构建健壮的应用程序,不得不使用繁琐的if逻辑判断来回避空指针异常。解锁Optional类,让你编写的应用健壮性更上一层楼。

1、先判断后使用
ifPresent方法提供了先判断是否为空,后进一步使用的能力。

2、链式取值
链式取值是指,层层嵌套对象取值,在上层对象不为空的前提下,才能读取其属性值,然后继续调用,取出最终结果值。有时候只关心链末端的结果状态,即使中间状态为空,直接返回空值。如下提供了一种无 if 判断,代码简介紧凑的实现方式:

Optional optional = Optional.ofNullable(tokenService.getLoginUser(ServletUtils.getRequest()))
.map(LoginUser::getUser).map(SysUser::getUserId);
// 如果存在则返回,不存在返回空
Long userId = optional.orElse(null);

流的应用

(一)列表转树
传统方式下构建树形列表需要反复递归调用查询数据库,效率偏低。对于一棵结点较多的树,效率更低。这里提供一种只需调用一次数据库,通过流将列表转化为树的解决方式。

/**

  • 列表转树
  • @param rootList 列表的全部数据集
  • @param parentId 第一级目录的父ID
  • @return 树形列表
    */
    public List getChildNode(List rootList, String parentId) {
    List lists = rootList.stream()
    .filter(e -> e.getParentId().equals(parentId))
    .map(IndustryNode::new).collect(toList());
    lists.forEach(e -> e.setChilds(getChildNode(rootList, e.getId())));
    return lists;
    }
    ##参考
    [1]: https://www.cnblogs.com/javazhishitupu/p/15820963.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值