Java8 stream stream operation refactoring recursive code

original code:

 private static JSONArray produceTree(List<Resource> resources,boolean needPermission){
    JSONArray tree = new JSONArray();
    if(resources!=null&&resources.size()>Number.ZERO) {//
        for (Resource resource : resources) {
            List<Resource> resourceList=resourceService.queryChildTreeByPid(resource.getId());//id
            JSONArray children = produceTree(resourceList,needPermission,staffName,roleId);//,
            JSONObject node=TreeUtil.spellTree(resource);//
            if(children!=null&&children.size()>Number.ZERO){
                node.put("children",children);
            }else if(needPermission){//(,)
                node=toPermission(resource.getId(),node,staffName);
            }
            tree.add(node);
        }
    }
    return tree;
}

the structure of Resource is as follows:

        @Data
        public class Resource {
        private Integer id;//id
    
        private String resourceName;//
    
        private String url;// 
    
        private String icon;//
    
        private String clue;// 
    
        private Integer distance; //  
    
        private Integer parentId;// id
    
        private String description; //
    
        private Date createtime;//
    
        private Integer state;// 0 1
        
        List<Resource> children;
    
    }

now I want to rewrite this code with the java8 Stream stream, something like this:

        private static List<Resource> recursive(List<Resource> resources){
            return resources.stream()
                    .map(Resource::getId)//id
                    .map(parentId->resourceService.queryChildTreeByPid(parentId))//id(idparentId)
                    .map(child->Optional.ofNullable(child).filter(obj -> true).ifPresent(isExists->recursive(isExists)))// childrenListnull,
                    .toArray(childrenL->reReousce.setChildren());// List<Resource> resourcechildren , resource.setChildren(childrenList)
        }

compilation error after the third step
imagine that the third step should collect the child resources with the toArray method, and then the fourth step should put the collected child resources into the corresponding parent resource resource. How can it be implemented

-thanks for the advice of imanguo boss and some me boss to share my tree structure production source code-
-Any library suggestions/code samples/guidance would be greatly appreciated.-

private static ResourceService resourceService;
private static PermissionService permissionService;

@Autowired
public TreeUtil(ResourceService resourceService,PermissionService permissionService){
    this.resourceService=resourceService;
    this.permissionService=permissionService;
}
/**
 * @Author: zms
 * @Description: 
 *
 * clue  1-2-3  1 12 23
 * id  
 *   1 2 12 12 
 *
 * @Date: Create on  2018/11/12 14:59
 */
public static List<Resource> produceTree(List<Resource> resources,boolean needPermission){
    Map<Boolean,List<Resource>> listMap=partitionResource(resources);
    List<Resource> nodeTree=listMap.get(true);//
    List<Resource> duplicateChildTree=listMap.get(false);//
    String clue=nodeTree.stream().map(Resource::getId).map(String::valueOf).collect(joining("-","","-"));//
    List<Resource> childTree=duplicateChildTree.stream().filter(resource -> !clue.contains(resource.getClue())).collect(toList());//
    nodeTree.addAll(childTree);//
    List<Resource> downTree=TreeUtil.recursiveDown(nodeTree,needPermission);//
    List<Resource> upTree=TreeUtil.recursiveUp(downTree);//
    return merge(upTree);
}
/**
 * @Author: zms
 * @Description:  
 *
 *                   5 ---
 *            2 ---  6 ---
 *       1--- 3 ---  7 ---
 *            4 ---  8 ---
 *                   9 ---
 *
 *  12,3,4 2,3,4 2(5,6) 3(7) 4(8,9)  children
 *  ResourceGroup? resourceChildrenResource 
 *  Resource ResourceGroup  
 * @Date: Create on  2018/11/8 11:30
 */
public static List<Resource> recursiveDown(List<Resource> resources, boolean needPermission){
    return resources
            .parallelStream()
            .map(resource -> TreeUtil.toResourceGroup(resource,needPermission))
            .peek(ResourceGroup::autoSet)
            .map(ResourceGroup::getParent)
            .collect(Collectors.toList());
}
/**
 * @Author: zms
 * @Description: resouceGroup
 * @Date: Create on  2018/11/8 11:30
 */
private static ResourceGroup toResourceGroup(Resource resource, boolean needPermission) {
    ResourceGroup resourceGroup=new ResourceGroup();
    resourceGroup.setParent(resource);
    List<Resource> children = findChildren(resource.getId(),needPermission);
    if(Objects.equals(0,children.size())&&needPermission){
        List<Permission> permissions=permissionService.getPermissionByResourceId(resource.getId());
        resourceGroup.setPermissions(permissions);
        return resourceGroup;
    }
    resourceGroup.setChildren(children);
    return resourceGroup;
}
/**
 * @Author: zms
 * @Description: 
 * @Date: Create on  2018/11/8 11:30
 */
private static List<Resource> findChildren(Integer parentId,boolean needPermission){
    List<Resource> chidren=resourceService.queryChildTreeByPid(parentId);
    recursiveDown(chidren,needPermission);
    return chidren;
}
/**
 * @Author: zms
 * @Description:  
 * @Date: Create on  2018/11/8 18:32
 */
private static List<Resource> recursiveUp(List<Resource> resources){
    return resources.stream()
                    .map(TreeUtil::toResource)
                    .map(ResourceGroup::getParent)
                    .collect(Collectors.toList());
}

/**
 *@Author: zms
 *@Description: 
 *@Date: Create On 2018/11/10 14:33
 */
private static ResourceGroup toResource(Resource resource){
    ResourceGroup resourceGroup=new ResourceGroup();
    Resource parent=findParent(resource);
    resourceGroup.setParent(parent);
    return resourceGroup;
}
/**
 * @Author: zms
 * @Description: 
 * @Date: Create on  2018/11/8 18:37
 */
private static Resource findParent(Resource resource){
    if(Objects.equals(0,resource.getParentId())){
        return resource;
    }
    Resource parent=resourceService.getResourceById(resource.getParentId());
    List<Resource> children=new ArrayList<>();
    children.add(resource);
    parent.setChildren(children);
    return recursiveUp(Collections.singletonList(parent)).stream().filter(Objects::nonNull).findFirst().orElse(resource);
}
/**
 * @Author: zms
 * @Description:
 *
 *  : id1 2,3,4    23
 *  2 -->1
 *  dulipcate
 *  3 -->1
 *  2 3  1 
 * @Date: Create on  2018/11/12 11:44
 */
private static List<Resource> merge(List<Resource> duplicateTree){
    return duplicateTree
            .stream()
            .collect(toMap(Resource::getId, Function.identity(),TreeUtil::mergeChildResource))
            .entrySet()
            .stream()
            .map(Map.Entry::getValue)
            .collect(Collectors.toList());
}

/**
 * @Author: zms
 * @Description:
 *
 *  id:1                     id:1                      id:1
 *  children:[               children:[                children:[
 *          {                        {                         {
 *              id=2                    id=3                id=2
 *          }                        }                         },
 *  ]                        ]                                 {
 *                                                               id=3
 *                                                             }
 *
 * @Date: Create on  2018/11/12 12:00
 */
private static Resource mergeChildResource(Resource resource1,Resource resource2){
    resource1.getChildren().add(resource2.getChildren().get(0));
    return resource1;
}

/**
 * @Author: zms
 * @Description: resource
 * @Date: Create on  2018/11/12 15:01
 */
private static Map<Boolean,List<Resource>> partitionResource(List<Resource> resources){
    return resources.stream().collect(partitioningBy(resource-> Objects.equals(0,resource.getParentId())));
}
/**
 * @Author: zms
 * @Description: 
 * @Date: Create on  2018/8/10 10:13
 */

public static String removeDuplicateString(String str){
    return Stream.of(str.split(",")).distinct().collect(Collectors.joining(","));
}
Oct.26,2021

emmm, I took down the code, but there are all kinds of errors in compilation, so I don't care about the source code, so this answer may not give you an answer code that you can use directly. There is only one way of thinking.

according to your last question, combined with your code, take a brief look at the effect you want to achieve

clipboard.png

ListidparentIdListchildren

:stream

clipboard.png

Why? the scene that stream itself has to deal with is the process of constant data transformation and mapping and Filter, and the data contained in stream is also constantly changing during this process, so there is a key point here, that is, according to the parent Resource , it can be converted into a child List < Resource > , but a child List < Resource > < / code. So you can no longer use the data from stream to do set actions

.

Let's take a look again in conjunction with your code (when writing stream operations, always pay attention to what the current data is in stream so that you won't make mistakes)

resources.stream()

the stream is generated according to resources , which is Stream < Resource >

.
.map(Resource::getId)

uses the map operation, which is the mapping transformation operation, which has become Stream < Long > . In fact, this step already means that you can no longer use Resource.setChildren , because the stream is already Long , its resource id , and then it can be converted into a child node List < Resource > with id . Of course,

does not mean that it is impossible to solve it. If you understand the properties of stream , you can still write it, but in the end, you may not use too much stream syntax

.

because you finally need to use the previous parent Resource , you need to keep the previous parent Resource , so you can try to write

the cycle parent Resource and find its child Resource , and finally set > back to the parent Resource , the three processes write

separately.
private static List<Resource> recursive(List<Resource> resources){
        resources.forEach(resource -> addChildren(resource));
        return resources;
    }

    private static void addChildren(Resource resource) {
        // idResource
        List<Resource> children = findChildren(resource.getId());
        // Resourceresource
        resource.setChildren(children);
    }

    private static List<Resource> findChildren(Integer id) {
        List<Resource> children = resourceService.queryChildTreeByPid(id);
        recursive(children);
        return children;
    }

this is just a modified way of writing according to the code you write later, with two points

  1. this may not be written as stream as you might imagine, but business decision code (no forced nesting of any structure or framework, finding the most appropriate code that belongs to the business, and the clearest code is the best)
  2. this writing method personally feels very different from your source code, of course, because it is modified according to the way you wrote it last. There is too much code missing in the source code, so ignoring what to do may affect the final writing method
  3. .

the above is for reference only

= minor changes =

according to the comments just now, I remember what I didn't know before: referencing new programming elements makes it easier to organize business processes

A ResourceGroup class is added here to determine the relationship between parent and child

@Data
public class ResourceGroup {

    private Resource parent;
    private List<Resource> children;

    public ResourceGroup autoSet(){
        this.parent.setChildren(this.children);
        return this;
    }
}
The attribute in

is a parent Resource and a child List < Resource > , so you can express

completely with stream .
private static List<Resource> recursive(List<Resource> resources){
        List<Resource> newResources = resources.stream()
                                               .map(Test::toResourceGroup)
                                               .peek(ResourceGroup::autoSet)
                                               .map(ResourceGroup::getParent)
                                               .collect(Collectors.toList());
        return newResources;
    }

A toResourceGroup method has been added

private static ResourceGroup toResourceGroup(Resource resource) {
        ResourceGroup resourceGroup = new ResourceGroup();

        resourceGroup.setParent(resource);

        List<Resource> children = findChildren(resource.getId());
        resourceGroup.setChildren(children);

        return resourceGroup;
    }

the rest are the previous methods, so you can supplement the methods you still need to deal with in stream

.
private static List<Resource> recursive(List<Resource> resources){
    return resources.stream()
            .map(Resource::getId)//id
            .map(parentId->resourceService.queryChildTreeByPid(parentId))//id(idparentId)
            .filter(obj -> obj != null)// childrenListnull,
            .toArray(childrenL->reReousce.setChildren());// List<Resource> resourcechildren , resource.setChildren(childrenList)
}
Menu