5.强大的Stream API

了解Stream

Java8
中有两大最为重要的改变。第一个是Lambda 表达式;另外一个则是Stream API(java.util.stream.*) 。
Stream
是Java8 中处理集合的关键抽象概念,它可以指定你希望对
集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL 执行的数
据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

什么是Stream

流(Stream)到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!"


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

Stream
的操作三个步骤

1.创建Stream
一个数据源(如:集合、数组),获取一个流
2.中间操作
一个中间操作链,对数据源的数据进行处理
3.终止操作 终端操作
一个终止操作,执行中间操作链,并产生结果

创建Stream
Java8中的Collection 接口被扩展,提供了两个获取流的方法:
1.default Stream stream() 返回一个顺序流
2.default Stream parallelStream() 返回一个并行流

由数组创建流

Java8中的Arrays 的静态方法stream() 可以获取数组流:
static < Stream stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)

由值创建流

可以使用静态方法Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。

public static Stream of(T... values): 返回一个流

由函数创建流:创建无限流

可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。
1.迭代
public static Stream iterate(final T seed, final UnaryOperator f)
2.生成
public static Stream generate(Supplier s):

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

筛选与切片

映射

排序

Stream的终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List 、IntegerInteger,甚至是void 。

查找与匹配

归约

备注:map 和reduce 的连接通常称为map reduce 模式,因Google 用它来进行网络搜索而出名。

收集

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

并行流与串行流

并行流就是把一个内容分成多个数据块,并用不同的线程分
别处理每个数据块的流。
Java8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过parallel() 与sequential() 在并行流与顺序流之间进行切换。

了解Fork/Join 框架

Fork/Join框架:就是在必要的情况下,将一个大任务,进行拆分( 成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join 汇总

Fork/Join框架与传统线程池的区别

采用 工作窃取 模式(work stealingstealing):
当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。


相对于一般的线程池实现,fork/join 框架的优势体现在对其中包含的任务的处理方式上 在一般的线程池中 如果一个线程正在执行的任务由于某些原因无法继续运行 那么该线程会处于等待状态 而在fork/join 框架实现中 如果某个子问题由于等待另外一个子问题的完成而无法继续运行 那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行 这种方式减少了线程的等待时间 提高了性能

public class ForkJoinCalculate extends RecursiveTask<Long>{

	private static final long serialVersionUID = 1234567890L;//序列号

	private long start;
	private long end;
	private static final long THRESHOLD=10000L;//临界值
	
	public ForkJoinCalculate(long start,long end) {
		this.start=start;
		this.end=end;
	}
	@Override
	protected Long compute() {
		long length=end-start;
		if(length<=THRESHOLD){
			long sum=0;
			for(long i=start;i<=end;i++){
				sum+=i;
			}
			return sum;
		}else{
			long middle=(start+end)/2;
			ForkJoinCalculate left=new ForkJoinCalculate(start, middle);
			left.fork();
			
			ForkJoinCalculate right=new ForkJoinCalculate(middle+1, end);
			right.fork();
			
			return left.join()+right.join();
		}
	}

}

创建Stream

	//创建Stream
	@Test
	public void test1(){
		//1.可以通过Collection 系列集合提供的stream()或parallelStream()
		List<String> list = new ArrayList<>();
		Stream<String> stream1 = list.stream();
		
		//2.通过 Arrays 中的静态方法stream()获取数组流
		Employee[] emps=new Employee[10];
		Stream<Employee> stream2=Arrays.stream(emps);
		
		//3.通过Stream 类中的静态方法of()
		Stream<String> stream3=Stream.of("aa","bb","cc");
		
		//4.创建无限流
		//迭代
		Stream<Integer> stream4=Stream.iterate(0, (x) -> x+2);
		stream4.limit(10).forEach(System.out::println);
		
		//生成
		Stream.generate(() -> Math.random())
			  .limit(5)
			  .forEach(System.out::println);
	}

中间操作

	//中间操作
	
	List<Employee> employees=Arrays.asList(
			new Employee("张三",18,9999.99),
			new Employee("李四",58,5555.55),
			new Employee("王五",26,3333.33),
			new Employee("赵六",36,6666.66),
			new Employee("田七",12,8888.88),
			new Employee("田七",12,8888.88)
			);
	
	/*  筛选与切片
	 *  filter--接收Lambda,从流中排除某些元素。
	 *  limit--截断流,使其元素不超过给定数量。
	 *  skip(n)--跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n) 互补
	 *  distinct--筛选,通过流所生成元素的 hashCode() 和 equals() 去掉重复元素
	 */
	
	//内部迭代:迭代操作由 Stream API 完成
	@Test
	public void test1(){
		//中间操作:不会执行任何操作
		Stream<Employee> stream=employees.stream()
								.filter((e) -> e.getAge()>35 );
		//终止操作:一次性执行全部内容,即 惰性求值
		stream.forEach(System.out::println);
	}
	//外部迭代
	@Test
	public void test2(){
		Iterator<Employee> it=employees.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
	
	@Test
	public void test3(){//发现“短路”只输出了两次,说明只要找到 2 个 符合条件的就不再继续迭代
		employees.stream()
				 .filter((e)->{
					 System.out.println("短路!");
					 return e.getSalary()>5000;
				 })
				 .limit(2)
				 .forEach(System.out::println);
	}
	
	@Test
	public void test4(){
		employees.stream()
				 .filter((e)->e.getSalary()>5000)
				 .skip(2)//跳过前两个
				 .distinct()//去重,注意:需要Employee重写hashCode 和 equals 方法
				 .forEach(System.out::println);
	}

映射

	//中间操作
	/*
	 * 映射
	 * map--接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新元素。
	 * flatMap--接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
	 */
	@Test
	public void test5(){
		List<String> list=Arrays.asList("aaa","bbb","ccc","ddd");
		list.stream()
			 .map((str)->str.toUpperCase())
			 .forEach(System.out::println);
		
		System.out.println("------------------------");
		
		employees.stream()
			     .map(Employee::getName)
			     .forEach(System.out::println);
		
		System.out.println("------------------------");
		
		Stream<Stream<Character>> stream=list.stream()
											 .map(TestStreamAPI2::filterChatacter);
		stream.forEach((sm)->{
			sm.forEach(System.out::println);
		});
		
		System.out.println("------------------------");
		
		Stream<Character> sm=list.stream()
				                 .flatMap(TestStreamAPI2::filterChatacter);
		sm.forEach(System.out::println);
	}
	
	public static Stream<Character> filterChatacter(String str){
		List<Character> list=new ArrayList<>();
		for (Character ch : str.toCharArray()) {
			list.add(ch);
		}
		return list.stream();
	}
	
	@Test
	public void test6(){//map和flatMap的关系  类似于 add(Object)和addAll(Collection coll)
		List<String> list=Arrays.asList("aaa","bbb","ccc","ddd");
		List list2=new ArrayList<>();
		list2.add(11);
		list2.add(22);
		list2.addAll(list);
		System.out.println(list2);
	}

排序

	//中间操作
	/*
	 * 排序
	 * sorted()-自然排序(按照对象类实现Comparable接口的compareTo()方法 排序)
	 * sorted(Comparator com)-定制排序(Comparator)
	 */
	@Test
	public void test7(){
		List<String> list=Arrays.asList("ccc","bbb","aaa");
		list.stream()
			.sorted()
			.forEach(System.out::println);
		
		System.out.println("------------------------");
		
		employees.stream()
			     .sorted((e1,e2)->{
			    	 if(e1.getAge().equals(e2.getAge())){
			    		 return e1.getName().compareTo(e2.getName());
			    	 }else{
			    		 return e1.getAge().compareTo(e2.getAge());
			    	 }
			     }).forEach(System.out::println); 
	}

查询与匹配

	List<Employee> employees=Arrays.asList(
			new Employee("张三",18,9999.99,Status.FREE),
			new Employee("李四",58,5555.55,Status.BUSY),
			new Employee("王五",26,3333.33,Status.VOCATION),
			new Employee("赵六",36,6666.66,Status.FREE),
			new Employee("田七",12,8888.88,Status.BUSY)
			);
	/*
	 * 查找与匹配
	 * 
	 */
	
	@Test
	public void test1(){
		boolean b1=employees.stream()//allMatch-检查是否匹配所有元素
							.allMatch((e)->e.getStatus().equals(Status.BUSY));
		System.out.println(b1);//false
		
		boolean b2=employees.stream()//anyMatch-检查是否至少匹配一个元素
							.anyMatch((e)->e.getStatus().equals(Status.BUSY));
		System.out.println(b2);//true
		
		boolean b3=employees.stream()//noneMatch-检查是否没有匹配所有元素
		         			.noneMatch((e)->e.getStatus().equals(Status.BUSY));
		System.out.println(b3);//false
		
		Optional<Employee> op=employees.stream()//findFirst-返回第一个元素//Optional是Java8中避免空指针异常的容器类
				 .sorted((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary()))
				 .findFirst();
		System.out.println(op.get());//Employee [name=王五, age=26, salary=3333.33, Status=VOCATION]
		
		Optional<Employee> op2=employees.parallelStream()//findAny-返回当前流中的任意元素
										.filter((e)->e.getStatus().equals(Status.FREE))
										.findAny();
		System.out.println(op2.get());//Employee [name=赵六, age=36, salary=6666.66, Status=FREE]
		
		Long count=employees.stream()//count-返回流中元素的总个数
				            .count();
		System.out.println(count);//5
		
		Optional<Employee> op3=employees.stream()//max-返回流中最大值
				                        .max((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary()));
		System.out.println(op3.get());//Employee [name=张三, age=18, salary=9999.99, Status=FREE]
		
		Optional<Double> op4=employees.stream()//min-返回流中最小值
				                      .map(Employee::getSalary)
				                      .min(Double::compare);
		System.out.println(op4.get());//3333.33
	}

归约

	/*
	 * 归约
	 * reduce(T identity,BinaryOperator b) / reduce(BinaryOperator b)-可以将流中元素反复结合起来,得到一个值。
	 */
	@Test
	public void test3(){
		List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
		Integer sum=list.stream()//reduce(T identity,BinaryOperator b)
				        .reduce(0, (x,y)->x+y);//0为起始值
		System.out.println(sum);
		
		System.out.println("--------------------------");
		
		Optional<Double> op=employees.stream()//reduce(BinaryOperator b)//没有起始值,map返回可能为空,所以返回Optional类型
				                     .map(Employee::getSalary)
				                     .reduce(Double::sum);
		System.out.println(op.get());
	}

收集

	/*
	 * 收集
	 * collect-将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。
	 */
	@Test
	public void test4(){
		List<String> list=employees.stream()
				                   .map(Employee::getName)
				                   .collect(Collectors.toList());
		list.forEach(System.out::println);
		
		System.out.println("----------------------------");
		
		Set<String> set=employees.stream()
				                 .map(Employee::getName)
				                 .collect(Collectors.toSet());
		set.forEach(System.out::println);
		
		System.out.println("----------------------------");
		
		HashSet<String> hs=employees.stream()
				                    .map(Employee::getName)
				                    .collect(Collectors.toCollection(HashSet::new));
		hs.forEach(System.out::println);
		
		System.out.println("----------------------------");
		
		//总和
		Long count=employees.stream()
				            .collect(Collectors.counting());
		System.out.println(count);
		
		//平均值
		Double avg=employees.stream()
				            .collect(Collectors.averagingDouble(Employee::getSalary));
		System.out.println(avg);
		
		//总和
		Double sum=employees.stream()
				            .collect(Collectors.summingDouble(Employee::getSalary));
		System.out.println(sum);
		
		//最大值
		Optional<Employee> max=employees.stream()
				                        .collect(Collectors.maxBy((e1,e2)->Double.compare(e1.getSalary(), e2.getSalary())));
		System.out.println(max.get());
		
		//最小值
		Optional<Double> min=employees.stream()
				                      .map(Employee::getSalary)
				                      .collect(Collectors.minBy(Double::compare));
		System.out.println(min.get());
		
		System.out.println("----------------------------");
		
		//分组
		Map<Status,List<Employee>> map=employees.stream()
				                                .collect(Collectors.groupingBy(Employee::getStatus));
		System.out.println(map);//{FREE=[Employee [name=张三, age=18, salary=9999.99, Status=FREE], Employee [name=赵六, age=36, salary=6666.66, Status=FREE]], VOCATION=[Employee [name=王五, age=26, salary=3333.33, Status=VOCATION]], BUSY=[Employee [name=李四, age=58, salary=5555.55, Status=BUSY], Employee [name=田七, age=12, salary=8888.88, Status=BUSY]]}
		
		//多级分组
		Map<Status,Map<String,List<Employee>>> map2=employees.stream()
				                                            .collect( Collectors.groupingBy( Employee::getStatus,Collectors.groupingBy((e)->{
				                                            	if(e.getAge()<=35){
				                                            		return "青年";
				                                            	}else if(e.getAge()<=50){
				                                            		return "中年";
				                                            	}else{
				                                            		return "老年";
				                                            	}
				                                            }) ) );
		System.out.println(map2);//{FREE={青年=[Employee [name=张三, age=18, salary=9999.99, Status=FREE]], 中年=[Employee [name=赵六, age=36, salary=6666.66, Status=FREE]]}, VOCATION={青年=[Employee [name=王五, age=26, salary=3333.33, Status=VOCATION]]}, BUSY={青年=[Employee [name=田七, age=12, salary=8888.88, Status=BUSY]], 老年=[Employee [name=李四, age=58, salary=5555.55, Status=BUSY]]}}
		
		//分区
		Map<Boolean,List<Employee>> map3=employees.stream()
				                                 .collect(Collectors.partitioningBy((e)->e.getSalary()>8000));
		System.out.println(map3);//{false=[Employee [name=李四, age=58, salary=5555.55, Status=BUSY], Employee [name=王五, age=26, salary=3333.33, Status=VOCATION], Employee [name=赵六, age=36, salary=6666.66, Status=FREE]], true=[Employee [name=张三, age=18, salary=9999.99, Status=FREE], Employee [name=田七, age=12, salary=8888.88, Status=BUSY]]}
		
		System.out.println("--------------------------------");
		
		DoubleSummaryStatistics dss=employees.stream()
				                             .collect(Collectors.summarizingDouble(Employee::getSalary));
		System.out.println(dss.getSum());
		System.out.println(dss.getAverage());
		System.out.println(dss.getMax());
		
		System.out.println("--------------------------------");
		String strr=employees.stream()
				             .map(Employee::getName)
				             .collect(Collectors.joining(","));
		System.out.println(strr);//张三李四王五赵六田七
	 }

Stream练习

public class TestTransaction {
	List<Transaction> transaction=null;
	
	@Before
	public void before(){
		Trader raoul=new Trader("Raoul","Cambridge");
		Trader mario=new Trader("Mario","Milan");
		Trader alan=new Trader("Alan","Cambridge");
		Trader brian=new Trader("Brian","Cambridge");
		
		transaction=Arrays.asList(
				new Transaction(brian, 2011, 300),
				new Transaction(raoul, 2012, 1000),
				new Transaction(raoul, 2011, 400),
				new Transaction(mario, 2012, 710),
				new Transaction(mario, 2012, 700),
				new Transaction(alan, 2012, 950)
		);
	}
	
	//1.找出2011年发生的所有交易,并按交易额排序(从低到高)
	@Test
	public void test1(){
		transaction.stream()
		           .filter((e)->e.getYear()==2011)
		           .sorted((e1,e2)->Integer.compare(e1.getValue(), e2.getValue()))
		           .forEach(System.out::println);
	}
	
	//2.交易员都在哪些不同的城市工作过?
	@Test
	public void test2(){
		transaction.stream()
				   .map((e)->e.getTrader().getCity())
				   .distinct()//去重
				   .forEach(System.out::println);
	}
	
	//3.查找所有来自剑桥的交易员,并按姓名排序
	@Test
	public void test3(){
		transaction.stream()
				   .filter((e)->e.getTrader().getCity().equals("Cambridge"))
				   .map(Transaction::getTrader)
				   .sorted((e1,e2)->e1.getName().compareTo(e2.getName()))
				   .distinct()
				   .forEach(System.out::println);
	}
	
	//4.返回所有交易员的姓名字符串,按字母顺序排序
	@Test
	public void test4(){
		transaction.stream()
				   .map(Transaction::getTrader)
				   .map(Trader::getName)
				   .distinct()
				   .sorted()
				   .forEach(System.out::println);
		
		System.out.println("-------------------------");
		
		String str=transaction.stream()
							  .map((e)->e.getTrader().getName())
							  .distinct()
							  .sorted()
							  .reduce("", String::concat);
		System.out.println(str);//AlanBrianMarioRaoul
		
		System.out.println("-------------------------");
		
		 transaction.stream()
		 			.map((t)->t.getTrader().getName())
		 			.flatMap(TestTransaction::filterCharacter)//返回的每个String合成一个流
		 			.sorted((s1,s2)->s1.compareToIgnoreCase(s2))
		 			.forEach(System.out::print);//aaaaaAaBiiilllMMnnoooorRRrruu
	}
	public static Stream<String> filterCharacter(String str){
		List<String> list=new ArrayList<>();
		for(Character ch:str.toCharArray()){
			list.add(ch.toString());
		}
		return list.stream();
	}
	
	//5.有没有交易员是在米兰工作的?
	@Test
	public void test5(){
		boolean b1=transaction.stream()
			                  .anyMatch((t)->t.getTrader().getCity().equals("Milan"));
		System.out.println(b1);
	}
	
	//6.打印生活在剑桥的交易员的所有交易额
	@Test
	public void test6(){
		Optional<Integer> sum=transaction.stream()
										 .filter((e)->e.getTrader().getCity().equals("Cambridge"))
										 .map(Transaction::getValue)
										 .reduce(Integer::sum);
		System.out.println(sum.get());
	}
	
	//7.所有交易中,最高的交易额是多少
	@Test
	public void test7(){
		Optional<Integer> max=transaction.stream()
				                         .map((t)->t.getValue())
				                         .max(Integer::compare);
		System.out.println(max.get());
	}
	
	//8.找到交易额最小的交易
	@Test
	public void test8(){
		Optional<Transaction> op=transaction.stream()
				                            .min((t1,t2)->Integer.compare(t1.getValue(), t2.getValue()));
		System.out.println(op.get());
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值