你需要了解的Java快捷开发 stream的使用(二) stream对List集合进行分组、汇总、排序等操作 Android兼容

首先介绍一下Collectors 类的静态工厂方法

1.Collectors 类

工厂方法返回类型作用
toListList把流中所有项目收集到一个 List
toSetSet把流中所有项目收集到一个 Set,删除重复项
toCollectionCollection把流中所有项目收集到给定的供应源创建的集合menuStream.collect(toCollection(), ArrayList::new)
countingLong计算流中元素的个数
sumIntInteger对流中项目的一个整数属性求和
averagingIntDouble计算流中项目 Integer 属性的平均值
summarizingIntIntSummaryStatistics收集关于流中项目 Integer 属性的统计值,例如最大、最小、 总和与平均值
joiningString连接对流中每个项目调用 toString 方法所生成的字符串collect(joining(", "))
maxByOptional一个包裹了流中按照给定比较器选出的最大元素的 Optional, 或如果流为空则为 Optional.empty()
minByOptional一个包裹了流中按照给定比较器选出的最小元素的 Optional, 或如果流为空则为 Optional.empty()
reducing归约操作产生的类型从一个作为累加器的初始值开始,利用 BinaryOperator 与流 中的元素逐个结合,从而将流归约为单个值累加int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果应用转换函数int howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size))
groupingByMap>根据项目的一个属性的值对流中的项目作问组,并将属性值作 为结果 Map 的键
partitioningByMap>根据对流中每个项目应用谓词的结果来对项目进行分区

1.1流的其他操作

  • concat()–
    此方法创建一个延迟连接的流,其元素是firstStream的所有元素,后跟secondStream的所有元素。 如果两个输入流都是有序的,则对所得到的流进行排序。如果任一输入流是并行的,则得到的流是平行的。
  • peek()(Consumer<? super T> action)-------stream.peek的操作是返回一个新的stream的,主要是用来debug调试的,因此使用steam.peek()必须对流进行一次处理再产生一个新的stream
  • ofNullable(T t)-如果此流不为null,则ofNullable(T)方法将返回包含单个元素的顺序Stream,否则该方法将返回空Stream。
  • takeWhile()(Predicate<? super T> predicate)–takeWhile() 方法使用一个断言作为参数,获取满足断言条件的元素直到断言为false为止。丢弃后面的元素,如果第一个值不满足断言条件,将返回一个空的 Stream。
  • dropWhile()(Predicate<? super T> predicate)—dropWhile 方法和 takeWhile 作用相反的,使用一个断言作为参数,从Stream中依次删除满足断言条件的元素,直到不满足条件为止结束删除

1.2Spliterator接口

Spliterator用来遍历和分割序列,它是为了并行执行而设计的;集合实现了 Spliterator 接口,提供了一个spliterator()方法

  • tryAdvance() 方法的行为类似于普通的 Iterator ,因为它会按顺序一个一个使用 Spliterator 中的元素,并且如果还有其他元素要遍历就返回 true,否则返回false
  • trySplit() --Spliterator最核心的方法;把一些元素划出去分给第二个 Spliterator (由该方法返回且装载已分割的元素),分割的Spliterator被用于每个子线程进行处理,从而达到并发处理的效果。当分割器Spliterator不能继续分割,则返回null。
  • 如果两个或多个线程在同一个spliterator上并发运行,则拆分和遍历的行为是不确定的。如果原始线程将一个spliterator移交给另一个线程进行处理,最好是在使用tryAdvance()消费任何元素之前进行切换
  • 理想的trySplit()方法有效地(无遍历)将其元素精确地分成两半,允许平衡并行计算。许多偏离这种理想仍然非常有效;
  • forEachRemaining()–在当前线程中串行对剩余元素执行迭代操作,直到所有元素都被处理或抛出异常。 如果是串行的,则按相关顺序执行操作。异常被转发给调用者。
  • estimateSize()—该接口是返回forEachRemaining遍历所遇到的元素数量的估计值,如果为无穷大,未知数或计算成本太高,则返回Long.MAX_VALUE。

  2.分组方法

2.1groupingBy

使用 groupingBy() 将数据进行分组,最终返回一个 Map 类型。

根据部门对用户列表进行分组。

/**
 * 使用 groupingBy() 分组 by 青冘
 */
@Test
public void groupingByTest()
{
    //获取用户列表
    List<User> userList = UserService.getUserList();
 
    //根据部门对用户列表进行分组
    Map<String,List<User>> userMap = userList.stream().collect(Collectors.groupingBy(User::getDepartment));
 
    //遍历分组后的结果
    userMap.forEach((key, value) -> {
        System.out.println(key + ":");
        value.forEach(System.out::println);
        System.out.println("--------------------------------------------------------------------------");
    });
}

执行结果:

2.2多级分组

groupingBy 可以接受一个第二参数实现多级分组。

根据部门和性别对用户列表进行分组。

/**
 * 使用 groupingBy() 多级分组  by 青冘
 */
@Test
public void multGroupingByTest()
{
    //获取用户列表
    List<User> userList = UserService.getUserList();
 
    //根据部门和性别对用户列表进行分组
    Map<String,Map<String,List<User>>> userMap = userList.stream()
            .collect(Collectors.groupingBy(User::getDepartment,Collectors.groupingBy(User::getSex)));
 
    //遍历分组后的结果
    userMap.forEach((key1, map) -> {
        System.out.println(key1 + ":");
        map.forEach((key2,user)->
        {
            System.out.println(key2 + ":");
            user.forEach(System.out::println);
        });
        System.out.println("--------------------------------------------------------------------------");
    });
}

执行结果:

2.3分组汇总

根据部门进行分组,汇总各个部门用户的平均年龄。

/**
 * 使用 groupingBy() 分组汇总  by 青冘
 */
@Test
public void groupCollectTest()
{
    //获取用户列表
    List<User> userList = UserService.getUserList();
 
    //根据部门进行分组,汇总各个部门用户的平均年龄
    Map<String, Double> userMap = userList.stream().collect(Collectors.groupingBy(User::getDepartment, Collectors.averagingInt(User::getAge)));
 
    //遍历分组后的结果
    userMap.forEach((key, value) -> {
        System.out.println(key + "的平均年龄:" + value);
    });
}

执行结果:

3.排序方法

3.1 sorted() / sorted((T, T) -> int)

如果流中的元素的类实现了 Comparable 接口,即有自己的排序规则,那么可以直接调用 sorted() 方法对元素进行排序,如 Stream。反之, 需要调用 sorted((T, T) -> int) 实现 Comparator 接口。

根据用户年龄进行排序。

/**
 * 使用 sorted() 排序  by 青冘
 */
@Test
public void sortedTest()
{
    //获取用户列表
    List<User> userList = UserService.getUserList();
 
    //根据年龄排序(升序)
    userList = userList.stream().sorted((u1, u2) -> u1.getAge() - u2.getAge()).collect(Collectors.toList());
    //推荐:userList = userList.stream().sorted(Comparator.comparingInt(User::getAge)).collect(Collectors.toList());
    //降序:userList = userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).collect(Collectors.toList());
 
    //遍历用户列表
    userList.forEach(System.out::println);
}

执行结果:

4.安卓兼容

如果是安卓使用stream会报错提示SDK必须大于24才能使用

但是有用户的机型SDK是小于24的,这样肯定不行的。

可以在app\build.gradle中添加引用的库;如下:

implementation 'com.annimon:stream:1.2.1'

注意:

在导包的时候,要导如下:

import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;

在使用的时候有一些不同

是使用Stream.of()

ArrayList<Person> arrayList = new ArrayList<>();
List<String> names = Stream.of(arrayList)
	.map(Person::getName)
	.collect(Collectors.toList());

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值