Java8新特性之Stream API

本文深入讲解了Java Stream API的基本概念、特点及操作流程,包括创建流、中间操作、终止操作等核心内容,并提供了丰富的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

       流(Stream):是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

      “集合讲的是数据,流讲的是计算”

StreamAPI特点

    ① Stream 自己不会存储元素。
    ② Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
    ③ Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

StreamAPI操作步骤

1. 创建Stream

	//创建 Stream
	@Test
	public void test1(){
		//1.Collection 提供了两个方法  stream() 与 parallelStream()
		List<String> list = new ArrayList<>();
		Stream<String> stream1 = list.stream();

		//2.通过 Arrays 中的 stream() 获取一个数组流
		Employee[] employees = new Employee[10];
		Stream<Employee> stream2 = Arrays.stream(employees);

		//3. 通过 Stream 类中静态方法 of()
		List<String> list1 = Arrays.asList("12", "as", "df");
		Stream stream3 = Stream.of(list1);

		//4. 创建无限流
		//迭代
		Stream stream4 = Stream.iterate(1, x -> x + 2);
		stream4.limit(10).forEach(System.out::println);
		//生成
		Stream stream5 = Stream.generate(Math::random);
		stream5.limit(5).forEach(System.out::println);
	}

 

2. 一系列流水史的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”


① 筛选与切片
方法描述
filter(Predicate p)接收Lambda ,从流中排除某些元素
distinct()筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素
limit(long maxSize)截断流,使其元素不超过给定数量
skip(long n)跳过元素,返回一个扔掉了前n 个元素的流。若流中元素不足n 个,则返回一个空流。与limit(n) 互补
	//2. 中间操作
	List<Employee> employees = Arrays.asList(
			new Employee("张三", 20),
			new Employee("李四", 50),
			new Employee("王五", 40),
			new Employee("王五", 40),
			new Employee("王五", 40),
			new Employee("赵六", 10),
			new Employee("王琦", 8),
			new Employee("李逵", 4)
	);

	/**
	 * 筛选与切片
	 * filter(Predicate p) :接收Lambda ,从流中排除某些元素。
	 * distinct() :筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素
	 * limit(long maxSize):截断流,使其元素不超过给定数量。
	 * skip(long n):跳过元素,返回一个扔掉了前n 个元素的流。若流中元素不足n 个,则返回一个空流。与limit(n) 互补
	 */
	//内部迭代:由StreamAPI自己完成
	//filter(Predicate p) :接收Lambda ,从流中排除某些元素。
	@Test
	public void test2() {
		/*多个中间操作可以连接起来形成一个流水线,除非流水
		线上触发终止操作,否则中间操作不会执行任何的处理!
		而在终止操作时一次性全部处理,称为“惰性求值”*/
		//中间操作:不会执行任何操作
		Stream<Employee> s = employees.stream().filter((e) -> {
			System.out.println("Stream API中间操作!");
			return e.getAge() > 25;
		});
		//终止操作:一次性操作全部操作
		s.forEach(System.out:: println);
	}

	//外部迭代
	@Test
	public void test3() {
		Iterator<Employee> it = employees.iterator();
		while (it.hasNext()) {
			Employee next = it.next();
			System.out.println(next);
		}
	}

	//limit(long maxSize):截断流,使其元素不超过给定数量。
	@Test
	public void test4() {
		employees.stream()
				.filter(e -> e.getAge() > 30)
				.limit(3)
				.forEach(System.out:: println);
		//运行结果
		/*Employee{name='李四', age=50}
		Employee{name='王五', age=40}
		Employee{name='王五', age=40}*/
	}

	//skip(long n):跳过元素,返回一个扔掉了前n 个元素的流。若流中元素不足n 个,则返回一个空流。与limit(n) 互补
	@Test
	public void test5() {
		employees.stream()
				.filter(e -> e.getAge() > 30)
				.skip(1)
				.forEach(System.out:: println);
		//运行结果
		/*Employee{name='王五', age=40}
		Employee{name='王五', age=40}
		Employee{name='王五', age=40}*/
	}

	//distinct() :筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素
	@Test
	public void test6() {
		employees.stream()
				.filter(e -> e.getAge() > 30)
				.distinct()
				.forEach(System.out:: println);
		//运行结果
		/*Employee{name='李四', age=50}
		  Employee{name='王五', age=40}*/
	}
②映射
方法   描述
map(Functionf)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
mapToDouble(ToDoubleFunction f) 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream
mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream
mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream
flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
   /**
	 * 映射
	 * map(Functionf) :接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
	 * mapToDouble(ToDoubleFunction f) :接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream。
	 * mapToInt(ToIntFunction f) :接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。
	 * mapToLong(ToLongFunction f) :接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream。
	 * flatMap(Function f) :接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
	 */
	@Test
	public void test7() {
		//map(Functionf) :接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
		List<String> list = Arrays.asList("aaa", "bbb", "ccc");
		list.stream()
				.map(str -> str.toUpperCase())
				.forEach(System.out:: print);//AAABBBCCC

		System.out.println("-------------------------");

		employees.stream()
				.map(Employee:: getName)
				.forEach(System.out:: print);//张三李四王五王五王五赵六王琦李逵

		System.out.println("-------------------------");
		//mapToInt(ToIntFunction f) :接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。
		IntStream is = employees.stream()
								.mapToInt(Employee:: getAge);
		is.forEach(System.out::println);

		System.out.println("-------------------------");
		//flatMap(Function f) :接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
		list.stream()
				.flatMap(TestStreamAPI1:: filterCharacter)
				.forEach(System.out:: println);

	}

	public static Stream<Character> filterCharacter(String str) {
		List<Character> list = new ArrayList<>();
		for (Character c : str.toCharArray()) {
			list.add(c);
		}
		return list.stream();
	}
③排序
方法描述
sorted()产生一个新流,其中按自然顺序排序
sorted(Comparator comp)产生一个新流,其中按比较器顺序排序
	/**
	 * 排序
	 * sorted() 产生一个新流,其中按自然顺序排序(Comparable)
	   sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序(	Comparator)
	 */
	@Test
	public void test8(){
		//sorted() 产生一个新流,其中按自然顺序排序(Comparable)
		List<String> list = Arrays.asList("aaa", "eee", "ccc","yyy");
		list.stream()
				.sorted()
				.forEach(System.out::print);//aaaccceeeyyy

		System.out.println("-----------------");
		//sorted(Comparator comp) 产生一个新流,其中按比较器顺序排序(	Comparator)
		employees.stream()
				.sorted((e1,e2)->{
					if (e1.getAge() == e2.getAge()){
						return e1.getName().compareTo(e2.getName());
					}else{
						return Integer.compare(e1.getAge(), e2.getAge());
					}
				}).forEach(System.out::println);
	}

3. 终止操作

①查找与匹配
方法描述
allMatch(Predicate p)检查是否匹配所有元素
anyMatch(Predicate p)检查是否至少匹配一个元素
noneMatch(Predicatep)检查是否没有匹配所有元素
findFirst()返回第一个元素
findAny()返回当前流中的任意元素
count()返回流中元素总数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c)内部迭代(使用Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
	/**
	 * 查找与匹配
	 * allMatch(Predicate p) 检查是否匹配所有元素
	 anyMatch(Predicate p) 检查是否至少匹配一个元素
	 noneMatch(Predicatep) 检查是否没有匹配所有元素
	 findFirst() 返回第一个元素
	 findAny() 返回当前流中的任意元素
	 count() 返回流中元素总数
	 max(Comparator c) 返回流中最大值
	 min(Comparator c) 返回流中最小值
	 forEach(Consumer c) 内部迭代(使用Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
	 */
	@Test
	public void test9(){
		boolean b1 = employees.stream()
				.allMatch(e -> e.getAge() > 20);
		System.out.println(b1);//false

		boolean b2 = employees.stream()
				.anyMatch(e -> e.getAge() > 20);
		System.out.println(b2);//true

		boolean b3 = employees.stream()
				.noneMatch(e -> e.getAge() > 20);
		System.out.println(b3);//false

		Optional<Employee>  op1 = employees.stream()
				.findFirst();
		System.out.println(op1.get());//Employee{name='张三', age=20}
		//并行流与串行流
		/*并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
		Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。
		Stream API 可以声明性地通过parallel() 与sequential() 在并行流与顺序流之间进行切换。*/
		Optional<Employee> op2 = employees.stream().parallel()
				.findAny();
		System.out.println(op2.get());//Employee{name='赵六', age=10}
		Optional<Employee> op3 = employees.stream().sequential()
				.findAny();
		System.out.println(op3.get());//Employee{name='张三', age=20}

		long num = employees.stream()
				.count();
		System.out.println(num);//8

		Optional<Employee> op4 = employees.stream()
				.max(Comparator.comparingInt(Employee:: getAge));
		System.out.println(op4.get());//Employee{name='李四', age=50}

		Optional<Employee> op5 = employees.stream()
				.min(Comparator.comparingInt(Employee:: getAge));
		System.out.println(op5.get());//Employee{name='李逵', age=4}
	}
②归约
方法描述
reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回T
reduce(BinaryOperator b)可以将流中元素反复结合起来,得到一个值。返回Optional<T>
	/**
	 * 归约
	 * reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回T
	 reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。返回Optional<T>
	 */
	@Test
	public void test10(){
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
		Integer sum = list.stream()
				.reduce(0, (x, y) -> x + y);
		System.out.println(sum); //21

		System.out.println("-----------------------------");

		Optional<Integer> op = employees.stream()
				.map(Employee:: getAge)
				.reduce(Integer:: sum);
		System.out.println(op.get());//212
	}
③收集
方法描述
collect(Collector c)将流转换为其他形式。接收一个Collector接口的
实现,用于给Stream中元素做汇总的方法

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

方法  返回类型作用
toListList<T>把流中元素收集到List
List<Employee>emps=list.stream().collect(Collectors.toList());
toSetSet<T>把流中元素收集到Set
Set<Employee>emps=list.stream().collect(Collectors.toSet());
toCollectionCollection<T>把流中元素收集到创建的集合
Collection<Employee>emps=list.stream().collect(Collectors.toCollection(ArrayList::new));
countingLong计算流中元素的个数
long count=list.stream().collect(Collectors.counting());
summingIntInteger对流中元素的整数属性求和
inttotal=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingIntDouble计算流中元素Integer属性的平均值
doubleavg=list.stream().collect(Collectors.averagingInt(Employee::getSalary));
summarizingIntIntSummaryStatistics收集流中Integer属性的统计值。如:平均值
IntSummaryStatisticsiss=list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
joiningString连接流中每个字符串
Stringstr=list.stream().map(Employee::getName).collect(Collectors.joining());
maxByOptional<T>根据比较器选择最大值
Optional<Emp>max=list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minByOptional<T>根据比较器选择最小值
Optional<Emp>min=list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing归约产生的类型从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值
inttotal=list.stream().collect(Collectors.reducing(0,Employee::getSalar,Integer::sum));
collectingAndThen转换函数返回的类型包裹另一个收集器,对其结果转换函数
inthow=list.stream().collect(Collectors.collectingAndThen(Collectors.toList(),List::size));
groupingByMap<K,List<T>>根据某属性值对流分组,属性为K,结果为V
Map<Emp.Status, List<Emp>> map= list.stream().collect(Collectors.groupingBy(Employee::getStatus));
partitioningByMap<Boolean,List<T>>根据true或false进行分区
Map<Boolean,List<Emp>>vd=list.stream().collect(Collectors.partitioningBy(Employee::getManage));
	/**
	 * 收集
	 * collect(Collector c) 将流转换为其他形式。接收一个Collector接口实现,用于给Stream中元素做汇总的方法
	 */
	@Test
	public void test11(){
		List<String> list = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.toList());
		list.forEach(System.out::print);//张三李四王五王五王五赵六王琦李逵

		System.out.println("-----------------------");

		Set<String> set = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.toSet());
		set.forEach(System.out::print);//李四张三王琦王五赵六李逵

		System.out.println("-----------------------");

		HashSet hset = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.toCollection(HashSet::new));
		hset.forEach(System.out::print);//李四张三王琦王五赵六李逵
	}

	@Test
	public void test12(){
		//总数
		long count = employees.stream()
							.collect(Collectors.counting());
		System.out.println(count);//8
		//平均值
		Double avg = employees.stream()
				.collect(Collectors.averagingInt(Employee::getAge));
		System.out.println(avg);//26.5

		//总和
		int sum = employees.stream()
							.collect(Collectors.summingInt(Employee:: getAge));
		System.out.println(sum);//212
		//最大值
		Optional<Employee> max = employees.stream()
				.collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())));
		System.out.println(max.get());//Employee{name='李四', age=50}
		//最小值
		Optional<Integer> min = employees.stream()
				.map(Employee:: getAge)
				.collect(Collectors.minBy(Integer:: compare));
		System.out.println(min.get());//4
	}
    //分组
	@Test
	public void test13(){
		Map<String,List<Employee>> map = employees.stream()
				.collect(Collectors.groupingBy(Employee:: getName));
		System.out.println(map.toString());
		/*{李四=[Employee{name='李四', age=50}],
		 张三=[Employee{name='张三', age=20}],
		 王琦=[Employee{name='王琦', age=8}],
		 王五=[Employee{name='王五', age=40}, Employee{name='王五', age=40}, Employee{name='王五', age=40}],
		 赵六=[Employee{name='赵六', age=10}],
		 李逵=[Employee{name='李逵', age=4}]}*/
	}

	//分区
	@Test
	public void test14() {
		Map<Boolean, List<Employee>> map = employees.stream()
				.collect(Collectors.partitioningBy((e) ->e.getAge() > 30));
		System.out.println(map);
		/*{
		false=[Employee{name='张三', age=20},
		       Employee{name='赵六', age=10},
		       Employee{name='王琦', age=8},
		       Employee{name='李逵', age=4}],
		 true=[Employee{name='李四', age=50},
		       Employee{name='王五', age=40},
		       Employee{name='王五', age=40},
		       Employee{name='王五', age=50}]}*/
	}

	//summarizingInt IntSummaryStatistics 收集流中Integer属性的统计值。如:平均值
	@Test
	public void test15(){
		DoubleSummaryStatistics ds = employees.stream()
				.collect(Collectors.summarizingDouble(Employee:: getAge));
		System.out.println(ds.getAverage());//27.75
		System.out.println(ds.getCount());//8
		System.out.println(ds.getMax());//50.0
		System.out.println(ds.getMin());//4.0
		System.out.println(ds.getSum());//222.0
	}

	//joining连接流中每个字符串
	@Test
	public void test16(){
		String str = employees.stream()
				.map(Employee:: getName)
				.collect(Collectors.joining(",", "---", "==="));
		System.out.println(str);//---张三,李四,王五,王五,王五,赵六,王琦,李逵===
	}

 

转载于:https://my.oschina.net/u/2289161/blog/854397

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值