Java 8 has been out for so long. How about the Stream API?

Java 8 introduces a new Stream API, which can process data in a declarative way, which greatly facilitates the collection operation, so that we can use less code to realize more complex logic. This paper mainly introduces some commonly used stream APIs.

What is Stream?

A Stream is a queue of elements from a data source that supports aggregation operations.

  • Data source: the data source of the Stream. Construct the data source of the Stream object. For example, construct the Stream object through a List, which is the data source;
  • Aggregation operation: the operation that causes the Stream object to return the specified rule data after processing the Stream object is called aggregation operation. For example, filter, map, limit, sorted, etc. are aggregation operations.

Stream aggregation operation

Background introduction

This article will take the UmsPermission object in mall as an example to introduce the common operations of Stream API. UmsPermission is a permission object, which is mainly divided into three types: directory, menu and button. The object definition is as follows.

public class UmsPermission implements Serializable {
    private Long id;

    @ApiModelProperty(value = "Parent permission id")
    private Long pid;

    @ApiModelProperty(value = "name")
    private String name;

    @ApiModelProperty(value = "Permission value")
    private String value;

    @ApiModelProperty(value = "Icon")
    private String icon;

    @ApiModelProperty(value = "Permission type: 0->catalogue one->Menu; two->Button (interface binding permission)")
    private Integer type;

    @ApiModelProperty(value = "Front end resource path")
    private String uri;

    @ApiModelProperty(value = "Enable status; 0->Disable; one->Enable")
    private Integer status;

    @ApiModelProperty(value = "Creation time")
    private Date createTime;

    @ApiModelProperty(value = "sort")
    private Integer sort;

    private static final long serialVersionUID = 1L;

    //Omit all getter and setter methods

Creation of Stream object

Stream objects are divided into two types: a serial stream object and a parallel stream object.

// permissionList refers to the list of all permissions
// Create a serial stream object for the collection
Stream<UmsPermission> stream =;
// Create a parallel flow object for the collection
tream<UmsPermission> parallelStream = permissionList.parallelStream();


Filter the elements in the Stream, and return the corresponding elements when the setting condition returns true.

// Get permission with permission type of directory
List<UmsPermission> dirList =
    .filter(permission -> permission.getType() == 0)


Obtained after converting the elements in the Stream. For example, you can convert the UmsPermission object to a Long object. We often need to extract the IDs of some objects, and then query other objects according to these IDs. This method can be used at this time.

// A collection of IDs that get all permissions
List<Long> idList =
    .map(permission -> permission.getId())


Gets the specified number of elements from the Stream.

// Get the collection composed of the first five permission objects
List<UmsPermission> firstFiveList =


Only get the number of elements in the Stream.

// count operation: get the number of all directory permissions
long dirPermissionCount =
    .filter(permission -> permission.getType() == 0)


Sorts the elements in the Stream according to the specified rules.

// Sort all permissions in the order of directory, menu and button
List<UmsPermission> sortedList =
    .sorted((permission1,permission2)->{return permission1.getType().compareTo(permission2.getType());})


Skip the specified number of elements in the Stream and get the following elements.

// Skip the first five elements and return to the following
List<UmsPermission> skipList =

Use the collect method to convert a List into a map

Sometimes we need to repeatedly query the objects in the List according to the id. we can first convert the List into a map structure with id as the key, and then obtain the objects through map.get(id).

// Convert the permission list to map with id as key and permission object as value
Map<Long, UmsPermission> permissionMap =
    .collect(Collectors.toMap(permission -> permission.getId(), permission -> permission));


We often need to return tree data. For example, the first level of permissions here is directory permissions. There are menu permissions under directory permissions and button permissions under menu permissions. If we want to return a collection containing directory permissions, menu permissions are nested under directory permissions, and button permissions are nested under menu permissions. Using Stream API can easily solve this problem.

Note: here, the upper and lower levels of permissions are associated by pid. pid refers to the id of the upper level permission, and the id of the top-level permission is 0.

Define objects that contain subordinate permissions

Inherited from the UmsPermission object, which adds a children attribute to store subordinate permissions.

 * Created by macro on 2018/9/30.
public class UmsPermissionNode extends UmsPermission {
    private List<UmsPermissionNode> children;

    public List<UmsPermissionNode> getChildren() {
        return children;

    public void setChildren(List<UmsPermissionNode> children) {
        this.children = children;

Define the method to get the tree structure

We first filter out the top-level permissions with pid 0, and then set its child permissions for each top-level permission. The main purpose of the covert method is to find the child permissions of the corresponding permissions from all permissions.

public List<UmsPermissionNode> treeList() {
    List<UmsPermission> permissionList = permissionMapper.selectByExample(new UmsPermissionExample());
    List<UmsPermissionNode> result =
            .filter(permission -> permission.getPid().equals(0L))
            .map(permission -> covert(permission, permissionList)).collect(Collectors.toList());
    return result;

Set child permissions for each permission

Here, we use the filter operation to filter out the child permissions of each permission. Since there may be child permissions under the child permissions, we use recursion to solve this problem. However, when the recursive operation stops, the recursive calling method is put into the map operation. When there is no child permission, the map operation under the filter will not be executed again, so as to stop the recursion.

* Convert permissions to permission objects with children
* When the child permission cannot be found, the map operation will not call covert recursively
private UmsPermissionNode covert(UmsPermission permission, List<UmsPermission> permissionList) {
    UmsPermissionNode node = new UmsPermissionNode();
    BeanUtils.copyProperties(permission, node);
    List<UmsPermissionNode> children =
           .filter(subPermission -> subPermission.getPid().equals(permission.getId()))
           .map(subPermission -> covert(subPermission, permissionList)).collect(Collectors.toList());
    return node;

Tags: Java Back-end

Posted on Sat, 06 Nov 2021 03:59:11 -0400 by PLaT