java stream按照多个字段排序 分组 java stream 顺序_java8

Java8 Stream 思维导图

目录

1、Stream 创建

 2、Stream 使用

2.1遍历/匹配(foreach/find/match)

 2.2筛选(filter)

2.3聚合(max/min/count)

2.4 映射(map/flatMap)

2.5归约(reduce)

2.6收集(collect)

2.6.1归集(toList/toSet/toMap)

2.6.2统计(count/averaging)

2.6.3分组(partitioningBy/groupingBy)

2.6.4接合(joining)

2.6.5归约(reducing)

2.7排序(sorted)

2.8提取/组合


1、Stream 创建

方式一:通过 java.util.Collection.stream() 方法用集合创建流

/**
		 * 创建方式一:通过 java.util.Collection.stream() 方法用集合创建流
		 */
		List<String> list = Arrays.asList("a", "b", "c", "d");
		
		// 创建一个顺序流
		Stream<String> stream = list.stream();
		stream.forEach(System.out::println);
		
		// 创建一个并行流
		Stream<String> parallelStream = list.parallelStream();
		parallelStream.forEach(System.out::println);

方式二:通过java.util.Arrays.stream(T[] array)方法用数组创建流

int[] array = {1,2,3,4,5,6};
		IntStream intStream = Arrays.stream(array);
		intStream.forEach(System.out::println);

方式三:通过Stream的静态方法:of()、iterate()、generate()

Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
		integerStream.forEach(System.out::println);

		Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
		stream2.forEach(System.out::println);

		Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
		stream3.forEach(System.out::println);

stream和parallelStream区分:

1、stream是顺序流,由主线程按顺序对流执行操作。
2、parallelStream是并行流,内部以多线程并行执行的方式对流进行操作,前提是流中的数据处理没有顺序要求。

 运行流程图说明:

java stream按照多个字段排序 分组 java stream 顺序_System_02

知识点拓展:

通过parallel()把顺序流转换成并行流。

 2、Stream 使用

员工类实体定义

package com.zzg.entity;

import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@SuppressWarnings("serial")
public class Person implements Serializable {
	private String name;  // 姓名
	private int salary; // 薪资
	private int age; // 年龄
	private String sex; //性别
	private String area;  // 地区
}

2.1遍历/匹配(foreach/find/match)

Stream支持类似集合的遍历和匹配元素。

java stream按照多个字段排序 分组 java stream 顺序_System_03

/**
		 * 温馨提示:Stream中的元素是以Optional类型存在
		 */

		// List<Integer> list = Arrays.asList(1,2,3,4,5);
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

		/**
		 * 遍历输出符合条件的元素
		 */
		list.stream().filter(x -> x > 6).forEach(System.out::println);
		/**
		 * 输出符合条件的第一个元素
		 */
		Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
		/**
		 * 输出符合条件的任意元素(适用于并行流)
		 */
		Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
		/**
		 * 判断是否包含符合特定条件的元素
		 */
		boolean anyMatch = list.stream().anyMatch(x -> x > 6);
		System.out.println("匹配第一个值:" + findFirst.orElse(0));
		System.out.println("匹配任意一个值:" + findAny.orElse(0));
		System.out.println("是否存在大于6的值:" + anyMatch);

 2.2筛选(filter)

筛选,按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

java stream按照多个字段排序 分组 java stream 顺序_List_04

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        /**
		 * 案例一:筛选出Integer集合中 大于8的元素,并打印出来
		 */
		list.stream().filter(x -> x > 8).forEach(System.out::println);

		/**
		 * 案例二:筛选薪资大于8000的员工名称,构建新的集合 温馨提示:map 用于获取指定对象的属性值 collect 用于构建新的集合
		 */
		List<Person> dataList = init();
		List<String> names = dataList.stream().filter(item -> item.getSalary() > 8000).map(item -> item.getName())
				.collect(Collectors.toList());
		names.stream().forEach(System.out::println);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.3聚合(max/min/count)

对集合、数组的数据进行统计操作。

java stream按照多个字段排序 分组 java stream 顺序_System_05

/**
		 * 案例三:获取员工集合中姓名字符串最长。
		 */
		String name = dataList.stream().map(item -> item.getName()).collect(Collectors.toList()).stream()
				.max(Comparator.comparing(String::length)).orElse("");
		System.out.println("用户名称:" + name);

		/**
		 * 案例四: 获取Integer 最大值
		 */
		List<Integer> sortList = Arrays.asList(7, 6, 9, 4, 11, 6);

		// 自然排序
		Optional<Integer> max = sortList.stream().max(Integer::compareTo);
		// 自定义排序
		Optional<Integer> max2 = sortList.stream().max(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return o1.compareTo(o2);
			}
		});
		System.out.println("自然排序的最大值:" + max.orElse(0));
		System.out.println("自定义排序的最大值:" + max2.orElse(0));

		/**
		 * 案例五: 获取员工集合中工资最高
		 */
		Optional<Person> salary = dataList.stream().max(Comparator.comparingInt(Person::getSalary));
		/**
		 * 基于lombok 创建模式构建Person 对象并赋值Salary 初始值
		 */
		System.out.println("员工工资最大值:" + salary.orElse(Person.builder().salary(0).build()).getSalary());

		/**
		 * 案例六:统计Integer集合中大于6的元素的个数
		 */
		List<Integer> integerList = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
		long integerCount = integerList.stream().filter(item -> item >= 6).count();
		System.out.println("integer 集合大于6个数:" + integerCount);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.4 映射(map/flatMap)

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为mapflatMap

  • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。

java stream按照多个字段排序 分组 java stream 顺序_java8_06

/**
		 * 案例七:遍历字符串列表,通过','逗号分隔符构建新列表
		 */
		List<String> strList = Arrays.asList("A,B,C", "D,E,F");
		List<String> newStrList = strList.stream().flatMap(item -> {
			return Arrays.stream(item.split(","));
		}).collect(Collectors.toList());
		newStrList.stream().forEach(System.out::println);

2.5归约(reduce)

实现对集合求和、求乘积和求最值操作

java stream按照多个字段排序 分组 java stream 顺序_java8_07

/**
		 * 案例八: 统计员工集合工资总数 温馨提示: 通过reduce 实现数值归纳总结,实现对集合求和、求乘积和求最值操作
		 */
		Integer totalSalary = dataList.stream().map(Person::getSalary).collect(Collectors.toList()).stream()
				.reduce(Integer::sum).orElse(0);
		System.out.println("员工集合工资总数:" + totalSalary);

		/**
		 * reduce 归纳统计使用匿名函数
		 */
		Integer totalSalaryTwo = dataList.stream().map(Person::getSalary).collect(Collectors.toList()).stream()
				.reduce((x, y) -> x + y).orElse(0);
		System.out.println("员工集合工资总数:" + totalSalaryTwo);

		/**
		 * reduce 归纳统计求最大值
		 */
		Integer totalSalaryThree = dataList.stream().map(Person::getSalary).collect(Collectors.toList()).stream()
				.reduce(Integer::max).orElse(0);
		System.out.println("员工工资最高:" + totalSalaryThree);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.6收集(collect)

collect就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。

collect主要依赖java.util.stream.Collectors类内置的静态方法。

2.6.1归集(toList/toSet/toMap)

List<String> nameList = dataList.stream().map(Person::getName).collect(Collectors.toList());
		nameList.stream().forEach(System.out::println);
		Map<String, Person> mapNameObject = dataList.stream().collect(Collectors.toMap(Person::getName, item -> item));
		/**
		 * java8 遍历map
		 */
		mapNameObject.forEach((k, v) -> {
			System.out.println("员工姓名:" + k);
			System.out.println("toString():" + v.toString());
		});

		Set<Person> setObject = dataList.stream().collect(Collectors.toSet());
		/**
		 * java8 遍历set
		 */
		setObject.forEach(item -> {
			System.out.println("toString():" + item.toString());
		});
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.6.2统计(count/averaging)

Collectors提供了一系列用于数据统计的静态方法:

  • 计数:count
  • 平均值:averagingInt、averagingLong、averagingDouble
  • 最值:maxBy、minBy
  • 求和:summingInt、summingLong、summingDouble
  • 统计以上所有:summarizingInt、summarizingLong、summarizingDouble
// 求总数
		Long count = dataList.stream().collect(Collectors.counting());
		// 求平均工资
		Double average = dataList.stream().collect(Collectors.averagingDouble(Person::getSalary));
		// 求最高工资
		Optional<Integer> max3 = dataList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compare));
		// 求工资之和
		Integer sum = dataList.stream().collect(Collectors.summingInt(Person::getSalary));
		// 一次性统计所有信息
		DoubleSummaryStatistics collect = dataList.stream().collect(Collectors.summarizingDouble(Person::getSalary));

		System.out.println("员工总数:" + count);
		System.out.println("员工工资最高:" + max3);
		System.out.println("员工平均工资:" + average);
		System.out.println("员工工资总和:" + sum);
		System.out.println("员工工资所有统计:" + collect);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.6.3分组(partitioningBy/groupingBy)

  • 分区:将stream按条件分为两个Map,比如员工按薪资是否高于8000分为两部分。
  • 分组:将集合分为多个Map,比如员工按性别分组。有单级分组和多级分组。

java stream按照多个字段排序 分组 java stream 顺序_java_08

// 将员工按薪资是否高于8000分组
		Map<Boolean, List<Person>> part = dataList.stream()
				.collect(Collectors.partitioningBy(x -> x.getSalary() > 8000));
		// 将员工按性别分组
		Map<String, List<Person>> group = dataList.stream().collect(Collectors.groupingBy(Person::getSex));
		// 将员工先按性别分组,再按地区分组
		Map<String, Map<String, List<Person>>> group2 = dataList.stream()
				.collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
		System.out.println("员工按薪资是否大于8000分组情况:" + part);
		System.out.println("员工按性别分组情况:" + group);
		System.out.println("员工按性别、地区:" + group2);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.6.4接合(joining)

joining将stream中的元素用特定的连接符连接成一个字符串。

String nameJoin = dataList.stream().map(Person::getName).collect(Collectors.joining(","));
		System.out.println("拼接员工姓名:" + nameJoin);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.6.5归约(reducing)

Collectors类提供的reducing方法,相比于stream本身的reduce方法,增加了对自定义归约的支持。

Integer sum1 = dataList.stream().collect(Collectors.reducing(0, Person::getSalary, (i, j) -> (i + j - 5000)));
		System.out.println("员工扣税薪资总和:" + sum1);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));
		return personList;
	}

2.7排序(sorted)

sorted,排序操作。支持两种排序:

  • sorted():自然排序,流中元素需实现 Comparable 接口
  • sorted(Comparator com):Comparator 排序器自定义排序
// 按工资升序排序(自然排序)
		List<String> newList = dataList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
				.collect(Collectors.toList());
		// 按工资倒序排序
		List<String> newList2 = dataList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
				.map(Person::getName).collect(Collectors.toList());
		// 先按工资再按年龄升序排序
		List<String> newList3 = dataList.stream()
				.sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
				.collect(Collectors.toList());
		// 先按工资再按年龄自定义排序(降序)
		List<String> newList4 = dataList.stream().sorted((p1, p2) -> {
			if (p1.getSalary() == p2.getSalary()) {
				return p2.getAge() - p1.getAge();
			} else {
				return p2.getSalary() - p1.getSalary();
			}
		}).map(Person::getName).collect(Collectors.toList());

		System.out.println("按工资升序排序:" + newList);
		System.out.println("按工资降序排序:" + newList2);
		System.out.println("先按工资再按年龄升序排序:" + newList3);
		System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
public static List<Person> init() {
		List<Person> personList = new ArrayList<Person>();
		personList.add(new Person("Tom", 8900, 25, "male", "New York"));
		personList.add(new Person("Jack", 7000, 21, "male", "Washington"));
		personList.add(new Person("Lily", 7800, 29, "female", "Washington"));
		personList.add(new Person("Anni", 8200, 31, "female", "New York"));
		personList.add(new Person("Owen", 9500, 35, "male", "New York"));
		personList.add(new Person("Alisa", 7900, 51, "female", "New York"));

2.8提取/组合

流也可以进行合并、去重、限制、跳过等操作。

java stream按照多个字段排序 分组 java stream 顺序_java_09

String[] arr1 = { "a", "b", "c", "d" };
		String[] arr2 = { "d", "e", "f", "g" };

		Stream<String> stream1 = Stream.of(arr1);
		Stream<String> stream2 = Stream.of(arr2);
		// concat:合并两个流 distinct:去重
		List<String> newList1 = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
		// limit:限制从流中获得前n个数据
		List<Integer> collect1 = Stream.iterate(1, x -> x + 2).limit(10).collect(Collectors.toList());
		// skip:跳过前n个数据
		List<Integer> collect2 = Stream.iterate(1, x -> x + 2).skip(1).limit(5).collect(Collectors.toList());

		System.out.println("流合并:" + newList1);
		System.out.println("limit:" + collect1);
		System.out.println("skip:" + collect2);