jdk8 StreamAPI 的使用

本文将以UmsMenu对象为例来介绍Stream API的常用操作。UmsMenu是一个菜单对象,具有树形结构,对象定义如下

Stream对象的创建

Stream对象分为两种,一种串行的流对象,一种并行的流对象。

1 // menuList指所有菜单列表
2 // 为集合创建串行流对象
3 Stream<UmsMenu> stream = menuList.stream();
4 // 为集合创建并行流对象
5 Stream<UmsMenu> parallelStream = menuList.parallelStream();

filter

对Stream中的元素进行过滤操作,当设置条件返回true时返回相应元素。

1 @Test
2 public void filterTest(){
3     //filter操作:获取所有一级菜单
4     List<UmsMenu> oneLevelList = menuList.stream()
5     .filter(menu -> menu.getParentId() == 0L)
6     .collect(Collectors.toList());
7     LOGGER.info("filter操作:{}",oneLevelList);
8 }

map

对Stream中的元素进行转换处理后获取,比如可以将UmsMenu对象转换成Long对象。我们经常会有这样的需求:需要把某些对象的id提取出来,然后根据这些id去查询其他对象,这时可以使用此方法。

1 @Test
2 public void mapTest(){
3     //map操作:获取所有菜单的id
4     List<Long> idList = menuList.stream()
5     .map(menu -> menu.getId())
6     .collect(Collectors.toList());
7     LOGGER.info("map操作:{}",idList);
8 }

limit

从Stream中获取指定数量的元素。

1 @Test
2 public void limitTest(){
3     //limit操作:获取前5个菜单
4     List<UmsMenu> firstFiveList = menuList.stream()
5             .limit(5)
6             .collect(Collectors.toList());
7     LOGGER.info("limit操作:{}",firstFiveList);
8 }

count

仅获取Stream中元素的个数。

1 @Test
2 public void countTest(){
3     //count操作:获取所有一级菜单的个数
4     long count = menuList.stream()
5     .filter(menu -> menu.getParentId() == 0L)
6     .count();
7     LOGGER.info("count操作:{}",count);
8 }

sorted

对Stream中元素按指定规则进行排序。

1 @Test
2 public void sortedTest(){
3     //sorted操作:将所有菜单按照sort字段进行排序
4     List<UmsMenu> sortedList = menuList.stream()
5             .sorted((menu1,menu2)->{return menu2.getSort().compareTo(menu1.getSort());})
6             .collect(Collectors.toList());
7     LOGGER.info("sorted操作:{}",sortedList);
8 }

skip

跳过指定个数的Stream中元素,获取后面的元素。

1 @Test
2 public void skipTest(){
3     //skip操作:跳过前5个元素,返回后面的
4     List<UmsMenu> skipList = menuList.stream()
5             .skip(5)
6             .collect(Collectors.toList());
7     LOGGER.info("skip操作:{}",skipList);
8 }

用collect方法将List转成map

有时候我们需要反复对List中的对象根据id进行查询,我们可以先把该List转换为以id为key的map结构,然后再通过map.get(id)来获取对象,这样比较方便。

1 @Test
2 public void collect2mapTest(){
3     //collect转map操作:将菜单列表以id为key,以菜单对象为值转换成map
4     Map<Long, UmsMenu> menuMap = menuList.stream()
5             .collect(Collectors.toMap(menu -> menu.getId(), menu -> menu));
6     LOGGER.info("collect转map操作:{}",menuMap);
7 }

应用

我们经常会有返回树形结构数据的需求。比如这里的菜单,具有一级菜单、二级菜单、三级菜单这样的结构。如果我们要返回一个集合,包含菜单以及菜单下面嵌套的子菜单,使用Stream API可以很方便的解决这个问题。

注意:这里我们的菜单上下级之间以parentId来关联,parentId是指上一级菜单的id,顶级菜单的parentId为0。

定义获取树形结构的方法

我们先过滤出parentId为0的顶级菜单,然后给每个顶级菜单设置其子级菜单,covertMenuNode方法的主要用途就是从所有菜单中找出相应子级菜单。

1 @Override
2 public List<UmsMenuNode> treeList() {
3     List<UmsMenu> menuList = menuMapper.selectByExample(new UmsMenuExample());
4     List<UmsMenuNode> result = menuList.stream()
5     .filter(menu -> menu.getParentId().equals(0L))
6     .map(menu -> covertMenuNode(menu, menuList)).collect(Collectors.toList());
7     return result;
8 }

为每个菜单设置子级菜单

这里我们使用filter操作来过滤出每个菜单的子级菜单,由于子级菜单下面可能还会有子级菜单,这里我们使用递归来解决。但是递归操作什么时候停止,这里把递归调用方法放到了map操作中去,当没有子级菜单时filter下的map操作便不会再执行,从而停止递归。

/**
 * 将UmsMenu转化为UmsMenuNode并设置children属性
 */
private UmsMenuNode covertMenuNode(UmsMenu menu, List<UmsMenu> menuList) {
    UmsMenuNode node = new UmsMenuNode();
    BeanUtils.copyProperties(menu, node);
    List<UmsMenuNode> children = menuList.stream()
            .filter(subMenu -> subMenu.getParentId().equals(menu.getId()))
            .map(subMenu -> covertMenuNode(subMenu, menuList)).collect(Collectors.toList());
    node.setChildren(children);
    return node;
}

 

 

 

posted @ 2024-04-03 20:00  哥伦布杰  阅读(83)  评论(0)    收藏  举报