Java 8 отсутствует так долго, а как насчет Stream API?

Java

Адрес фактического проекта электронной коммерции SpringBoot (20k+star):GitHub.com/macro-positive/…

Резюме

Java 8 представляет новый Stream API, который может обрабатывать данные декларативным способом, что значительно упрощает операции сбора и позволяет нам использовать меньше кода для реализации более сложной логики.Эта статья в основном посвящена некоторым часто используемым Stream API.

Что такое поток?

Поток — это очередь элементов из источника данных, которая может поддерживать операции агрегирования.

  • Источник данных: источник данных потока, источник данных для построения объекта Stream, например, для построения объекта Stream через список, этот список является источником данных;
  • Операция агрегирования: после обработки объекта Stream операция, которая заставляет объект Stream возвращать указанные данные правила, называется операцией агрегирования.Например, фильтрация, сопоставление, ограничение, сортировка и т. д. — все операции агрегирования.

Операции агрегации потоков

Введение

В этой статье в качестве примера будет использоваться объект UmsPermission в торговом центре, чтобы представить общие операции Stream API. UmsPermission — это объект разрешений, в основном разделенный на три вида разрешений: каталог, меню и кнопку. Объект определяется следующим образом.

public class UmsPermission implements Serializable {
    private Long id;

    @ApiModelProperty(value = "父级权限id")
    private Long pid;

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

    @ApiModelProperty(value = "权限值")
    private String value;

    @ApiModelProperty(value = "图标")
    private String icon;

    @ApiModelProperty(value = "权限类型:0->目录;1->菜单;2->按钮(接口绑定权限)")
    private Integer type;

    @ApiModelProperty(value = "前端资源路径")
    private String uri;

    @ApiModelProperty(value = "启用状态;0->禁用;1->启用")
    private Integer status;

    @ApiModelProperty(value = "创建时间")
    private Date createTime;

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

    private static final long serialVersionUID = 1L;
    
    //省略所有getter及setter方法
}

Создание объектов потока

Объекты потока делятся на два типа: объект последовательного потока и объект параллельного потока.

// permissionList指所有权限列表
// 为集合创建串行流对象
Stream<UmsPermission> stream = permissionList.stream();
// 为集合创建并行流对象
tream<UmsPermission> parallelStream = permissionList.parallelStream();

filter

Отфильтруйте элементы в потоке и верните соответствующий элемент, когда заданное условие возвращает значение true.

// 获取权限类型为目录的权限
List<UmsPermission> dirList = permissionList.stream()
    .filter(permission -> permission.getType() == 0)
    .collect(Collectors.toList());

map

Получается после преобразования элементов в Stream. Например, объект UmsPermission можно преобразовать в объект Long. У нас часто возникает такое требование: нам нужно извлечь id одних объектов, а потом запросить другие объекты по этим id, тогда можно использовать этот метод.

// 获取所有权限的id组成的集合
List<Long> idList = permissionList.stream()
    .map(permission -> permission.getId())
    .collect(Collectors.toList());

limit

Получить указанное количество элементов из потока.

// 获取前5个权限对象组成的集合
List<UmsPermission> firstFiveList = permissionList.stream()
    .limit(5)
    .collect(Collectors.toList());

count

Получите только количество элементов в потоке.

// count操作:获取所有目录权限的个数
long dirPermissionCount = permissionList.stream()
    .filter(permission -> permission.getType() == 0)
    .count();

sorted

Отсортируйте элементы в потоке в соответствии с указанными правилами.

// 将所有权限按先目录后菜单再按钮的顺序排序
List<UmsPermission> sortedList = permissionList.stream()
    .sorted((permission1,permission2)->{return permission1.getType().compareTo(permission2.getType());})
    .collect(Collectors.toList());

skip

Пропустить указанное количество элементов в потоке и получить следующие элементы.

// 跳过前5个元素,返回后面的
List<UmsPermission> skipList = permissionList.stream()
    .skip(5)
    .collect(Collectors.toList());

Преобразование списка в карту с методом сбора

Иногда нам нужно многократно запрашивать объекты в списке по id.Мы можем сначала преобразовать список в структуру карты с id в качестве ключа, а затем получить объект через map.get(id), что более удобно.

// 将权限列表以id为key,以权限对象为值转换成map
Map<Long, UmsPermission> permissionMap = permissionList.stream()
    .collect(Collectors.toMap(permission -> permission.getId(), permission -> permission));

применение

У нас часто возникает необходимость возвращать древовидные данные. Например, разрешения здесь, первый уровень — это разрешения каталога, разрешения меню находятся под разрешениями каталога, а разрешения кнопок — под разрешениями меню. Если мы хотим вернуть коллекцию, содержащую разрешения каталога, разрешения меню вложены в разрешения каталога, а разрешения кнопок вложены в разрешения меню. Использование Stream API может легко решить эту проблему.

Примечание. Здесь наши разрешения связаны с верхним и нижним уровнями по pid, pid относится к идентификатору разрешения верхнего уровня, а идентификатор разрешения верхнего уровня равен 0.

Определите объект, который содержит подчиненные разрешения

Унаследовано от объекта UmsPermission, который добавляет дочернее свойство для хранения разрешений более низкого уровня.

/**
 * 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;
    }
}

Определите метод для получения древовидной структуры

Сначала мы отфильтровываем разрешения верхнего уровня с pid 0, а затем устанавливаем разрешения подуровня для каждого разрешения верхнего уровня.Основная цель скрытого метода — найти разрешения подуровня соответствующих разрешений из все разрешения.

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

Установите дочерние разрешения для каждого разрешения

Здесь мы используем операцию фильтра, чтобы отфильтровать разрешения подуровня каждого разрешения.Поскольку могут быть разрешения подуровня под разрешениями подуровня, здесь мы используем рекурсию для ее решения. Но когда рекурсивная операция останавливается? Здесь метод рекурсивного вызова помещается в операцию карты. Когда нет разрешения подуровня, операция карты под фильтром не будет выполняться снова, тем самым останавливая рекурсию.

/**
* 将权限转换为带有子级的权限对象
* 当找不到子级权限的时候map操作不会再递归调用covert
*/
private UmsPermissionNode covert(UmsPermission permission, List<UmsPermission> permissionList) {
    UmsPermissionNode node = new UmsPermissionNode();
    BeanUtils.copyProperties(permission, node);
    List<UmsPermissionNode> children = permissionList.stream()
           .filter(subPermission -> subPermission.getPid().equals(permission.getId()))
           .map(subPermission -> covert(subPermission, permissionList)).collect(Collectors.toList());
    node.setChildren(children);
    return node;
}

Адрес исходного кода проекта

GitHub.com/macro-positive/…

публика

проект торгового центраПолный набор учебных пособий сериализуется,Обратите внимание на публичный аккаунтПолучите это прямо сейчас.

公众号图片