Java8新特性Stream流api实用的一些封装

对Java Stream流api进行一些实用的封装

    • 功能介绍
    • List分组
      • 根据字段简单分组
        • 简单分组测试
      • 选择返回字段分组
        • 选择返回字段分组测试
      • 合并结果集分组
        • 合并结果集分组测试
      • 分组后对结果集进行处理
        • 测试
      • 分组后统计每组的数量
        • 测试
    • 对List的操作
      • List的排序
        • 1. 单字段排序
        • 多字段排序
        • 排序测试
      • 从List中查找最大/最小值的元素
        • 测试
      • 合并List中某个属性值, 计算 总数/平均数
        • 测试
      • List统计数据
        • 测试
      • List转换为Map
        • 测试
      • List转其他集合, 数组转集合
        • 测试
      • List根据某个字段去重
        • 测试
      • Map的排序
        • 1. 对Map的key进行排序
        • 2. 对Map的值进行排序
        • 测试

在某些业务场景中, 我们经常会对集合中的数据进行处理, Java8 提供了 Stream API 可以让我们很方便地处理集合中的数据, 例如, 分组, 过滤, 排序等, 但是每次处理数据的时候都要开流去处理, 所以我们可以对stream api进行一些简单的封装, 这样的话一些通用场景下就不需要写重复的逻辑了.

功能介绍

经过一阵子的努力, 我简单的封装了一个工具类, 目前工具类中功能大概有以下几个:

  1. List分组, 可以整合分组后的结果, 例如根据dept对user进行分组后, value整合为user的分数之类的.
  2. List排序, 单字段 / 多字段排序.
  3. List根据字段寻找最小值 / 最大值 元素.
  4. List中某个对象的值合并, 例如求某个字段的总和 / 平均值
  5. List某个字段统计数据获取(最小值, 最大值, 平均值, 总和等)
  6. List转Map
  7. Map的排序, 可以根据key / value进行排序
  8. List转换为其他集合, 数组转换为集合.
  9. List根据某个字段去重.

List分组

根据字段简单分组

首先先准备两个函数, 用于判空, 一切都是从这两个函数开始的.

/**
     * list判空
     *
     * @param list 集合
     */
    private static void notEmptyCondition(List<?> list) {
   
        if (list == null || list.size() == 0) throw new NullPointerException("这就有点不讲武德了, 给我个空我怎么处理呢.");
    }

    /**
     * map 判空
     *
     * @param map map集合
     */
    private static void notEmptyCondition(Map<?, ?> map) {
   
        if (map == null || map.entrySet().size() == 0) throw new NullPointerException("这就有点不讲武德了, 给我个空我怎么处理呢.");
    }

接着准备分组函数

/**
     * 简单分组
     *
     * @param list       集合
     * @param classifier 分组字段选择函数
     * @param         输入类型
     * @param         Key的类型
     * @return 最后返回Map
     */
    public static <T, K> Map<K, List<T>> simpleGroupingBy(List<T> list, Function<? super T, ? extends K> classifier) {
   
        notEmptyCondition(list);
        return list.stream().collect(Collectors.groupingBy(classifier));
    }

对分组后的结果进行排序

  1. 首先准备排序函数
/**
     * 基本排序操作, 这里约定了排序字段的选择必须是实现了Comparable接口的.
     *
     * @param list      集合
     * @param desc      是否降序
     * @param keySelect 排序字段选择函数
     * @param        输入类型
     */
    private static <T, U extends Comparable<U>> void sortList
    (
            List<T> list, boolean desc, Function<? super T, ? extends U> keySelect
    ) {
   
    	// 这里如果是降序的话, 就将List进行反转
        if (desc) {
   
            list.sort(Comparator.comparing(keySelect));
            Collections.reverse(list); //反转List
        } else {
   
            list.sort(Comparator.comparing(keySelect));
        }
    }
  1. 分组函数, 和上一个没什么区别, 就是多了个排序.
/**
     * 简单分组 + 排序字段的选择
     *
     * @param list       集合
     * @param classifier 分组字段
     * @param keySelect  排序字段选择
     * @param desc       是否降序
     * @param         输入类型
     * @param         key的类型
     * @return 最后返回Map List为排序之后的List
     */
    public static <T, K, C extends Comparable<C>> Map<K, List<T>> simpleGroupingBy
    (
            List<T> list, Function<? super T, ? extends K> classifier, boolean desc,
            Function<? super T, ? extends C> keySelect
    ) {
   
        notEmptyCondition(list);
        sortList(list, desc, keySelect);
        return list.stream().collect(Collectors.groupingBy(classifier));
    }
简单分组测试
public static void main(String[] args) {
   
        ArrayList<TestUser> list = new ArrayList<TestUser>() {
   {
   
            add(new TestUser("用户11111", 1L, 120.0, 11, 20L));
            add(new TestUser("用户2", 1L, 110.0, 12, 20L));
            add(new TestUser("用户3", 2L, 130.0, 13, 200L));
            add(new TestUser("用户4", 2L, 150.0, 14, 20L));
        }};
		//根据TestUser的DeptId进行分组, 这里返回的Key为DeptId, value为List
        Map<Long, List<TestUser>> result = FunctionalUtil.simpleGroupingBy(list, TestUser::getDeptId);
        System.err.println("result = " + result);
		
		//根据TestUser的DeptId进行分组, 并对List进行排序, 排序字段为TestUser的winningCount字段
        Map<Long, List<TestUser>> result2 = FunctionalUtil.simpleGroupingBy(list, TestUser::getDeptId, true, TestUser::getWinningCount);
        System.err.println("result2 = " + result2);
}

控制台打印的结果:

result = {1=[TestUser{username='用户11111', deptId=1, score=120.0, count=11, winningCount=20}, TestUser{username='用户2', deptId=1, score=110.0, count=12, winningCount=20}], 2=[TestUser{username='用户3', deptId=2, score=130.0, count=13, winningCount=200}, TestUser{username='用户4', deptId=2, score=150.0, count=14, winningCount=20}]}
result2 = {1=[TestUser{username='用户2', deptId=1, score=110.0, count=12, winningCount=20}, TestUser{username='用户11111', deptId=1, score=120.0, count=11, winningCount=20}], 2=[TestUser{username='用户3', deptId=2, score=130.0, count=13, winningCount=200}, TestUser{username='用户4', deptId=2, score=150.0, count=14, winningCount=20}]}

选择返回字段分组

在分组后从对象中选取字段进行返回

/**
     * 可选返回字段函数式分组
     *
     * @param list            列表
     * @param classifier      分组字段选择
     * @param mappingFunction 返回字段
     * @param              输入类型
     * @param              key类型
     * @param              最后返回的元素类型
     * @return 最后返回Map
     */
    public static <T, K, U> Map<K, List<U>> customizingFieldGroupingBy
    (
            List<T> list, Function<? super T, ? extends K> classifier,
            Function<? super T, ? extends U> mappingFunction
    ) {
   
        notEmptyCondition(list);
        return list.stream()
                .collect(Collectors.groupingBy(classifier, Collectors.mapping(mappingFunction, Collectors.toList())));
    }

排序结果: 和上面用的排序函数一致.

/**
     * 可选返回字段函数式分组 + 排序字段选择
     *
     * @param list            列表
     * @param classifier      分组字段选择
     * @param mappingFunction 返回字段
     * @param keySelect       排序字段选择
     * @param desc            是否降序
     * @param              输入类型
     * @param              key类型
     * @param              最后返回的元素类型
     * @return 最后返回Map
     */
    public static <T, K, U, C extends Comparable<C>> Map<K, List<U>> customizingFieldGroupingBy
    (
            List<T> list, Function<? super T, ? extends K> classifier,
            Function<? super T, ? extends U> mappingFunction, boolean desc,
            Function<? super T, ? extends C> keySelect
    ) {
   
        notEmptyCondition(list);
        sortList(list, desc, keySelect);
        return list.stream()
                .collect(Collectors.groupingBy(classifier, Collectors.mapping(mappingFunction, Collectors.toList())));
    }
选择返回字段分组测试
public static void main(String[] args) {
   
        ArrayList<TestUser> list = new ArrayList<TestUser>() {
   {
   
            add(new TestUser("用户11111", 1L, 120.0, 11, 20L));
            add(new TestUser("用户2", 1L, 110.0, 12, 20L));
            add(new TestUser("用户3", 2L, 130.0, 13, 200L));
            add(new TestUser("用户4", 2L, 150.0, 14, 20L));
        }};

		//根据deptId字段进行分组, 选择score字段进行返回
        Map<Long, List<Double>> resultMap = FunctionalUtil.customizingFieldGroupingBy(list, TestUser::getDeptId, TestUser::getScore);
        System.err.println("resultMap = " + resultMap);
		
		//根据deptId字段进行分组, 选择score字段进行返回, 按照score降序进行排序
        Map<Long, List<Double>> resultMap2 = FunctionalUtil.customizingFieldGroupingBy(list, TestUser::getDeptId, TestUser::getScore, true, TestUser

你可能感兴趣的:(笔记,java,stream,流处理,封装)