Java8 学习笔记(二) —— Stream API

这里的Stream非io流,简单的说就是使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象

	/*
	 * 一、Stream API 的操作步骤:
	 * 1. 创建 Stream
	 * 2. 中间操作
	 * 3. 终止操作(终端操作)
	 */
	public static void main(String[] args) {
		//1. Collection 提供了两个方法  stream() 与 parallelStream()
		List<String> list = new ArrayList<>();
		Stream<String> stream = list.stream(); //获取一个顺序流(串行流)
		Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
		
		//2. 通过 Arrays 中的 stream() 获取一个数组流
		Integer[] nums = new Integer[10];
		Stream<Integer> stream1 = Arrays.stream(nums);
		
		//3. 通过 Stream 类中静态方法 of(T...t)
		Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
		
		//4. 创建无限流(迭代)
		//Stream.iterate的第一个参数可以看做是x的初始值
		//limit就是所谓的中间操作,如果不加中间操作,则会无穷输出
		//forEach就是指终止操作,不加终止操作,创建的Stream就无任何意义
		Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
		stream3.forEach((x)-> System.out.println(x));
		//stream3.forEach(System.out::println); //简单写法
		
		//5. 创建无限流(生成)
		Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
		stream4.forEach(System.out::println);
		
	}

Stream 中间操作

public class Tester {
	
	
	List<Employee> emps = Arrays.asList(
			//Employee(int id, String name, int age, double salary)
			new Employee(102, "李四", 59, 6666.66),
			new Employee(101, "张三", 18, 9999.99),
			new Employee(103, "王五", 28, 3333.33),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55)
	);
	
	/*
	 * 中间操作有哪些?
	 * filter:接收 Lambda , 从流中排除某些元素
	 * limit(n):截断流,使其元素不超过n个数量
	 * skip(n):跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
	 * distinct:通过流所生成元素的 hashCode() 和 equals()去除重复元素
	 * map:遍历集合,返回新的集合
	 * flatMap:同map,只不过参数有一定特殊性,具体看实例代码
	 * sorted()——自然排序,即按实现Comparable类后的compareTo方法进行排序
	 * sorted(Comparator com)——定制排序
	 */

}
	//filter
	@Test
	public void filterTest(){
		//emps.stream()返回的是一个新流,不会对源数据emps产生任何影响
		Stream<Employee> stream = emps.stream()
				.filter((e) -> {
					System.out.println(e.getName());
					return e.getAge() > 20;
				}); 
		//如果没有终止操作,中间操作是不会执行的,例如不会打印filter中的信息,这种方式被称为“惰性求值”
		stream.forEach(System.out::println);
	}
#控制台
李四 #这个是filter中的打印
Employee [id=102, name=李四, age=59, salary=6666.66] #这个是forEach中的打印,过滤后的实际结果
张三 
王五
Employee [id=103, name=王五, age=28, salary=3333.33]
赵六
赵六
赵六
田七
Employee [id=105, name=田七, age=38, salary=5555.55]
	//limit测试
	@Test
	public void limitTest(){
		emps.stream()
		//.filter((e) -> e.getAge() > 20)  //先过滤,在limit
		.limit(3)                        
		.forEach(System.out::println);
	}
#控制台
Employee [id=102, name=李四, age=59, salary=6666.66]
Employee [id=101, name=张三, age=18, salary=9999.99]
Employee [id=103, name=王五, age=28, salary=3333.33]
	//skip测试
	@Test
	public void skipTest(){
		emps.stream()
			.skip(3)
			.forEach(System.out::println);
	}
#控制台
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=105, name=田七, age=38, salary=5555.55]
	//distinct测试
	@Test
	public void distinctTest(){
		emps.stream()
			.distinct()        //Employee必须重写hashCode和equals,否则去重无效
			.forEach(System.out::println);
	}
#控制台
Employee [id=102, name=李四, age=59, salary=6666.66]
Employee [id=101, name=张三, age=18, salary=9999.99]
Employee [id=103, name=王五, age=28, salary=3333.33]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=105, name=田七, age=38, salary=5555.55]
	//map测试
	@Test
	public void mapTest(){
		
		//遍历集合中的Employee,返回新的集合,集合变为List<String>
		Stream<String> map = emps.stream().map((e)-> e.getName());
		map.forEach(System.out::println);
		
		//修改age,返回Employee
		Stream<Employee> map2 = emps.stream().map((e) -> {e.setAge(new Random().nextInt(50));return e;});
		map2.forEach(System.out::println);
		
		//简写版
		//emps.stream().map((e)-> e.getName()).forEach(System.out::println);    
		//emps.stream().map(Employee::getName).forEach(System.out::println);   //更简单的写法
		//emps.stream().map((e) -> {e.setAge(new Random().nextInt(50));return e;}).forEach(System.out::println);
			
	}
#控制台
李四
张三
王五
赵六
赵六
赵六
田七
	//flatMap测试
	@Test
	public void flatMapTest() {
		List<String> list = Arrays.asList("abc");  //第一个用来遍历的集合
		//flatMap的入参为:Function<? super T, ? extends Stream<? extends R>>
		list.stream().flatMap((str) -> { //遍历第一个集合
			List<Character> list2 = new ArrayList<>();
			for (Character character : str.toCharArray()) {
				list2.add(character);  //对第一集合的String拆分成Character
			}
			return list2.stream(); //将List<Character>作为流返回
		}).forEach(System.out::println); //这里实际打印的是list2,这就是同map的区别
		
		//将list2封装成一个方法后,更简单的写法
		list.stream().flatMap(this::filterCharacter).forEach(System.out::println);
	}
	
	//拆分string,返回char
	private Stream<Character> filterCharacter(String str){
		List<Character> list = new ArrayList<>();
		for (Character ch : str.toCharArray()) {
			list.add(ch);
		}
		return list.stream();
	}
#控制台
a
b
c
	//sorted测试
	@Test
	public void testSorted(){
		
		//自然排序,按字符串默认实现排序
		emps.stream()
			.map(Employee::getName)
			.sorted()
			.forEach(System.out::println);
		
		//定制排序
		emps.stream()
			.sorted((x, y) -> {
				if(x.getAge() == y.getAge()){
					return x.getName().compareTo(y.getName());
				}else{
					return Integer.compare(x.getAge(), y.getAge());
				}
			}).forEach(System.out::println);
	}
#控制台输出
张三
李四
王五
田七
赵六
赵六
赵六
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=104, name=赵六, age=8, salary=7777.77]
Employee [id=101, name=张三, age=18, salary=9999.99]
Employee [id=103, name=王五, age=28, salary=3333.33]
Employee [id=105, name=田七, age=38, salary=5555.55]
Employee [id=102, name=李四, age=59, salary=6666.66]

Stream 终止操作

public class Tester2 {

	List<Employee> emps = Arrays.asList(
			// Employee(int id, String name, int age, double salary)
			new Employee(102, "李四", 59, 6666.66), 
			new Employee(101, "张三", 18, 9999.99),
			new Employee(103, "王五", 28, 3333.33), 
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(104, "赵六", 8, 7777.77), 
			new Employee(104, "赵六", 8, 7777.77),
			new Employee(105, "田七", 38, 5555.55));

	/*
	 * 终止操作有哪些? 
	 * allMatch:检查是否匹配所有元素 
	 * anyMatch:检查是否至少匹配一个元素 
	 * noneMatch:检查是否没有匹配的元素
	 * findFirst:返回第一个元素 
	 * findAny:返回当前流中的任意元素 
	 * count:返回流中元素的总个数 
	 * max:返回流中最大值
	 * min:返回流中最小值 
	 * forEach:内部迭代,遍历元素 
	 * reduce:归约,可以将流中元素反复结合起来,得到一个值。具体看例子
	 * collect 收集,将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
	 */

	@Test
	public void test1() {
		boolean b1 = emps.stream().allMatch((e) -> e.getAge() > 20); // 检查否全部的年龄都超过20
		System.out.println(b1); // 返回false

		boolean b2 = emps.stream().anyMatch((e) -> e.getAge() > 20); // 检查至少有一条年龄超过20
		System.out.println(b2); // 返回true

		boolean b3 = emps.stream().noneMatch((e) -> e.getAge() > 60); // 超过60岁,没有被匹配到的
		System.out.println(b3); // 超过60岁的一个也没有,所有未匹配上,返回true

		// 找出第一个元素,Optional是什么,后面会讲,这里只需要知道结果有可能为null,就会返回Optional
		Optional<Employee> op = emps.stream().findFirst();
		Employee employee = op.get();

		Optional<Employee> op2 = emps.stream().findAny(); // 随机找出一个元素
		Employee employee2 = op2.get();

		long count = emps.stream().count(); // 总个数

		Optional<Employee> op3 = emps.stream().max((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())); // 最大值
		Employee employee3 = op3.get();

		Optional<Double> op4 = emps.stream().map(Employee::getSalary).min(Double::compare); // 取出salary,然后求最小值
		Double dou = op4.get();

		emps.stream().forEach(System.out::println); // 遍历元素
	}

	// reduce测试
	@Test
	public void testReduce() {
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
		//0为初始值时,x=初始值,y=1(集合中的第一个元素),第一次执行0+1
		//此时x=1(x+y的结果),y=2(集合中的第二个元素),第二次执行1+2
		Integer sum = list.stream().reduce(1, (x, y) -> {System.out.println(x+","+y);return x + y;}); 
		System.out.println(sum);
		
		//结果和上面一致,只是没有初始值,没有初始值时,x=0,y=1(集合中的第一个元素),第一次执行0+1
		System.out.println(list.stream().reduce(Integer::sum).get()); 
		
		//薪资求和
		Optional<Double> op = emps.stream().map(Employee::getSalary).reduce(Double::sum);
		System.out.println(op.get());
	}
	
	// collect测试
	@Test
	public void testCollect1() {
		List<String> list = emps.stream()
				.map(Employee::getName)
				.collect(Collectors.toList());
		
		System.out.println(list); //[李四, 张三, 王五, 赵六, 赵六, 赵六, 田七]
		
		Set<String> set = emps.stream()
				.map(Employee::getName)
				.collect(Collectors.toSet());
		System.out.println(set);  //[李四, 张三, 王五, 赵六, 田七]
			
		HashSet<String> hs = emps.stream()
				.map(Employee::getName)
				.collect(Collectors.toCollection(HashSet::new));
		System.out.println(hs);  //[李四, 张三, 王五, 赵六, 田七]
	}
	
	@Test
	public void testCollect2(){
		//薪资求最大
		Optional<Double> max = emps.stream()
			.map(Employee::getSalary)
			.collect(Collectors.maxBy(Double::compare)); 
		System.out.println(max.get()); //9999.99
		
		//薪资求最小
		Optional<Employee> op = emps.stream()
			.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
		System.out.println(op.get()); //Employee [id=103, name=王五, age=28, salary=3333.33]
		
		//薪资求和
		Double sum = emps.stream()
			.collect(Collectors.summingDouble(Employee::getSalary));
		System.out.println(sum); //48888.840000000004
		
		//薪资求平均值
		Double avg = emps.stream()
			.collect(Collectors.averagingDouble(Employee::getSalary));
		System.out.println(avg); //6984.120000000001
		
		//求总数
		Long count = emps.stream()
			.collect(Collectors.counting());
		System.out.println(count); //7
		
		
		//薪资汇总统计
		DoubleSummaryStatistics dss = emps.stream()
				.collect(Collectors.summarizingDouble(Employee::getSalary));
		System.out.println(dss.getMax());
		System.out.println(dss.getAverage());
		System.out.println(dss.getCount());
		System.out.println(dss.getMin());
	}
	
	@Test
	public void testCollect3(){
		//按年龄分组
		Map<Integer, List<Employee>> map = emps.stream()
				.collect(Collectors.groupingBy(Employee::getAge));
		System.out.println(map);
//		{
//			18=[Employee [id=101, name=张三, age=18, salary=9999.99]], 
//			38=[Employee [id=105, name=田七, age=38, salary=5555.55]], 
//			8=[Employee [id=104, name=赵六, age=8, salary=7777.77], Employee [id=104, name=赵六, age=8, salary=7777.77], Employee [id=104, name=赵六, age=8, salary=7777.77]], 
//			59=[Employee [id=102, name=李四, age=59, salary=6666.66]], 
//			28=[Employee [id=103, name=王五, age=28, salary=3333.33]]
//		}
		
		//多级分组
		Map<Integer, Map<String, List<Employee>>> map2 = emps.stream()
				.collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> {
					if (e.getAge() >= 60)
						return "老年";
					else if (e.getAge() >= 35)
						return "中年";
					else
						return "成年";
				})));
		System.out.println(map2);
//		{
//			101={成年=[Employee [id=101, name=张三, age=18, salary=9999.99]]}, 
//			102={中年=[Employee [id=102, name=李四, age=59, salary=6666.66]]}, 
//			103={成年=[Employee [id=103, name=王五, age=28, salary=3333.33]]}, 
//			104={成年=[Employee [id=104, name=赵六, age=8, salary=7777.77], Employee [id=104, name=赵六, age=8, salary=7777.77], Employee [id=104, name=赵六, age=8, salary=7777.77]]}, 
//			105={中年=[Employee [id=105, name=田七, age=38, salary=5555.55]]}
//		}
		

	}
	
	@Test
	public void testCollect4(){
		//分区
		Map<Boolean, List<Employee>> map = emps.stream()
				.collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
		System.out.println(map);
//		{
//			false=[Employee [id=103, name=王五, age=28, salary=3333.33]], 
//			true=[Employee [id=102, name=李四, age=59, salary=6666.66], Employee [id=101, name=张三, age=18, salary=9999.99], Employee [id=104, name=赵六, age=8, salary=7777.77], Employee [id=104, name=赵六, age=8, salary=7777.77], Employee [id=104, name=赵六, age=8, salary=7777.77], Employee [id=105, name=田七, age=38, salary=5555.55]]
//		}
		
		//连接
		String str = emps.stream().map(Employee::getName)
				.collect(Collectors.joining());          //李四张三王五赵六赵六赵六田七
//				.collect(Collectors.joining(","));       //李四,张三,王五,赵六,赵六,赵六,田七
//				.collect(Collectors.joining(",", "首", "尾")); //首李四,张三,王五,赵六,赵六,赵六,田七尾
		System.out.println(str);
		
		//collect也可以算薪资求和
		Optional<Double> sum = emps.stream()
				.map(Employee::getSalary)
				.collect(Collectors.reducing(Double::sum));
		System.out.println(sum.get());
	}
}

并行流

	//并行流测试
	@Test
	public void parallelStreamTest(){
		//并行流把一个任务拆分成多个任务,利用多线程来处理,底层原理用的是ForkJoin
		Stream<Employee> stream = emps.parallelStream();
		stream.forEach(System.out::println); //并行流输出的结果,顺序是乱的
		
		//0至1000亿累加
		long start = System.currentTimeMillis();
		Long sum = LongStream.rangeClosed(0L, 10000000000L).parallel().sum();
		System.out.println(sum);
		long end = System.currentTimeMillis();
		System.out.println("耗费的时间为: " + (end - start));
		
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值