• Java8的Stream用法


    Java8 API新增了一个新的抽象流Stream,它可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。Stream就是把集合数据看作流,流在管道中传输,我们可在管道中进行排序聚合等操作。

    在平时写代码的过程中,涉及到集合操作时候,Stream API可以极大的提高我们的生产力,让我们写出高效率、干净、简洁的代码。Stream API有很多操作可供使用,这里主要介绍常用的几个方法。

    基础Stream API

    forEach

    forEach是迭代流中的每一个元素。

    @Test
    public void testForeach() {
    	Random random = new Random();
    	List list= new ArrayList<>();
    	//random.ints(-100,100).limit(10).forEach(System.out::println);
    	random.ints(-100,100).limit(10).forEach(t->list.add(t));
    	System.out.println(list);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    上述是用forEach迭代输出每一个-100至100的随机值,输出10个,还可以迭代进入一个新的List集合。

    map

    map对流中每个元素进行操作,返回一个新的流

    @Test
    public void testMap(){
    	// 只是对流操作并不会改变原List中的数据
    	//Stream fruit=Stream.of("apple","orange","banner","pear");
    	List fruit = Arrays.asList("apple","orange","banner","pear");
    	fruit.stream().sorted().map(String::toUpperCase).forEach(System.out::println);
    	System.out.println(fruit);
    
    	// 返回新的流
    	List newfruit = fruit.stream().map(v->v.toUpperCase()).collect(Collectors.toList());
    	System.out.println(newfruit);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    上述是对每个元素进行大写字母化,或输出或返回到新的集合中

    filter

    filter 方法用于通过设置的条件过滤出元素

    /**
     * Long 数组选取不为Null和大于0的值
     * @param t
     * @return
     */
    public static Long[] removeNullAndZero(Long[] t) {
    	List list = Arrays.asList(t);
    	return list.stream().filter(v->v!=null && v>0).toArray(Long[] :: new);	
    }
    
    /**
     * 选取String数组 不为Null的值
     * @param t
     * @return
     */
    public static String[] removeNullAndZero(String[] t) {
    	List list = Arrays.asList(t);
    	return list.stream().filter(v->v!=null).toArray(String[] :: new);	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    过滤Null或者大于0的元素

    @Test
    public void testFilter() {
    	List intList = Arrays.asList(8,2,4,1,8,3,10,6,6,15);
    	List newIntList=intList.stream().filter(i->i>5).sorted().distinct().collect(Collectors.toList());
    	System.out.println(newIntList);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上述是过滤大于5的值,并且排序,取唯一的数字输出到新的集合。

    parallelStream

    parallelStream 是流并行处理程序的代替方法,相比较Stream是多管道操作。它就是基于ForkJoinPool执行并发任务的。

    特点

    • 使用parallelStream可以简洁高效的写出并发代码。
    • parallelStream并行执行是无序的。
    • parallelStream提供了更简单的并发执行的实现,但并不意味着更高的性能,它是使用要根据具体的应用场景。如果cpu资源紧张parallelStream不会带来性能提升;如果存在频繁的线程切换反而会降低性能。
    • 任务之间最好是状态无关的,因为parallelStream默认是非线程安全的,可能带来结果的不确定性。

    Github上对Parallel做了增强,有兴趣可以点击访问

    @Test
    public void testParallel() {
    	Random random = new Random();
    	List list= new ArrayList<>();
    	random.ints(-10000,10000).limit(10000).forEach(t->list.add(t));
    	
    	
    	long start = System.currentTimeMillis();
    	list.stream().filter(e -> e > 1000 && e< 2000).collect(Collectors.toList());
    	System.out.println("stream : " + (System.currentTimeMillis() - start) + "ms");
    	
    	start = System.currentTimeMillis();
    	list.parallelStream().filter(e -> e > 1000 && e < 2000).collect(Collectors.toList());
    	System.out.println("parallelStream : " + (System.currentTimeMillis() - start) + "ms");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试并发处理速度,上述代码对此做了测试,测试结果parallelStream速度是稍快一点。

    Count

    Stream API还提供简单的统计操作。

    @Test
    public void testCount() {
    	List numList = Arrays.asList(6, 2, 4, 3, 7, 3, 5, 9);
    	 
    	DoubleSummaryStatistics stats = numList.stream().mapToDouble((x) -> x).summaryStatistics();
    	System.out.println("总个数 : " + stats.getCount());
    	System.out.println("列表中最大的数 : " + stats.getMax());
    	System.out.println("列表中最小的数 : " + stats.getMin());
    	System.out.println("所有数之和 : " + stats.getSum());
    	System.out.println("平均数 : " + stats.getAverage());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    简单的统计的功能。

    实际应用

    我在实际项目对会有集合进行操作,使用Stream API能够帮我简洁的解决问题。下面是我实际使用场景。

    对象类

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Person {
    	
    	private String name;
    	private Integer gender;
    	private int age;
    	private double height;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    使用场景

    构造数据
    static List createPeople(){
    	List people=new ArrayList();
    	Person person=new Person("张三",0,30,2.8);
    	people.add(person);
    	person=new Person("李四",0,32,1.6);
    	people.add(person);
    	person=new Person("王五",1,32,2.0);
    	people.add(person);
    	person=new Person("王五",1,33,1.6);
    	people.add(person);
    	return people;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    连接某一属性

    需要并行显示,用,连接某一属性

    @Test
    public void CollectionStreamJoin(){
    	List people=createPeople();
    	Stream stream=people.stream();
    	// 取出对象的name值,并用,连接
    	String names = stream.map(v->v.getName()).collect(Collectors.joining(","));
    	System.out.println(names);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    获取某属性唯一值

    根据某一个属性值,删选对象。只保留唯一的属性值

    @Test
    public void distinctList() {
    	List people=createPeople();
    	List distinctlist = people.stream()
    			.collect(Collectors.collectingAndThen(
    					Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName))),
    					ArrayList::new));
    	System.out.println(distinctlist);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    多属性排序

    需要用多个属性去进行排序

    @Test
    public void sortField() {
    	List people=createPeople();
    	people.sort(Comparator.comparing(Person::getAge).reversed().thenComparing(Person::getHeight));
    	System.out.println(JSON.toJSONString(people));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    分组后排序

    对象列表先按照一个字段分组,并根据另一个字段的大小来排序,取第一个对象

    @Test
    public void getOnlyOneByField() {
    	List people=createPeople();
    	Map map =new HashMap<>();
    	map = people.parallelStream()
    				.collect(Collectors.groupingBy(Person::getName,
    						Collectors.collectingAndThen(
    								Collectors.reducing((c1, c2) -> c1.getAge()>c2.getAge()?c1:c2),
    								Optional::get)));
    	System.out.println(map);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    累加求和

    根据某个属性值累加

    @Test
    public void accumulation(){
    	List people=createPeople();
    	int sumAge = people.stream().mapToInt(Person::getAge).sum();
    	System.out.println(sumAge);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    分组求和

    根据某个属性分组,然后另外一个值求和

    /**
     * 分组求和
     */
    @Test
    public void groupSum(){
    	List people=createPeople();
    	Map summaryStatisticsMap = people.stream()
    			.collect(
    					Collectors.groupingBy(Person::getGender,
    							Collectors.summarizingDouble(Person::getHeight))
    			);
    	System.out.println(JSON.toJSONString(summaryStatisticsMap));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    总结

    使用Stream API可以让集合操作的代码更为简洁,提高生产力。而且本人在写Stream操作的时候,思想就跟写SQL语句类似,包括分组、聚合、过滤等操作,遇到难的可以在思维上借鉴下。

  • 相关阅读:
    Vue封装路由跳转方法,vue-router对query传参进行加密解密
    解锁学习电路设计的正确姿势!
    SIP中继与VoIP:有何不同?
    搞透 IOC,Spring IOC 看这篇就够了!
    JS上传文件(base64字符串和二进制文件流)
    【spring】SpringBoot与SpringCloud的版本对应
    【论文分享】异质图上的小样本学习:HG-Meta: Graph Meta-learning over Heterogeneous Graphs
    棒球省队建设实施办法·棒球1号位
    隐语 Meetup 北京站|精彩时刻大盘点!新品发布、行业案例、专家解读......欢迎围观
    TSN中流的路由与调度的研究
  • 原文地址:https://blog.csdn.net/flash_love/article/details/132840584