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

本文介绍了对Java8 Stream API的封装,包括List的分组、排序、查找最大/最小值、统计数据、转换为Map等功能,并提供了详细的测试案例。通过这些封装,可以更方便地处理Java集合数据。
摘要由CSDN通过智能技术生成

在某些业务场景中, 我们经常会对集合中的数据进行处理, 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 <T>        输入类型
     * @param <K>        Key的类型
     * @return 最后返回Map<K, List < T>
     */
    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 <T>       输入类型
     */
    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 <T>        输入类型
     * @param <K>        key的类型
     * @return 最后返回Map<K, List < T> 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<TestUser>
        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 <T>             输入类型
     * @param <K>             key类型
     * @param <U>             最后返回的元素类型
     * @return 最后返回Map<K, List < U>
     */
    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 <T>             输入类型
     * @param <K>             key类型
     * @param <U>             最后返回的元素类型
     * @return 最后返回Map<K, List < U>
     */
    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::getScore);
        System.err.println("resultMap2 = " + resultMap2);
}

控制台打印的结果:

resultMap = {1=[120.0, 110.0], 2=[130.0, 150.0]}
resultMap2 = {1=[120.0, 110.0], 2=[150.0, 130.0]}

合并结果集分组

最后返回Map<K, Double>, 将对象的某个值进行合并操作, 求和/求平均值操作.

  1. 准备枚举MergingOperation
/**
 * @author nathan
 * @date 3/23/2021 9:34 AM
 * @description: 合并操作符
 */
public enum MergingOperation {
   

    // 相加   求平均值
    SUMMING, AVERAGING
}
  1. 函数
/**
     * 分组后合并操作
     *
     * @param list              集合List
     * @param classifier        分组字段
     * @param mergingClassifier 合并字段选择, 支持多字段选择, 限制只能是数字 Integer/Long/Double
     * @param <T>               输入类型
     * @param <K>               key类型
     * @return Map<Long, ? extends Number>
     */
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值