美文网首页
Java 8 中的 Streams API-高级集合类和收集器(

Java 8 中的 Streams API-高级集合类和收集器(

作者: 在下喵星人 | 来源:发表于2019-07-17 16:12 被阅读0次

    对集合排序

    流的目的不仅是在集合类之间做转换, 而且同时提供了一组处理数据的通用操作。 有些集合本身是无序的, 但可以在流中进行顺序。

     @Test
        public void lambdaCollectOrder(){
            Set<Integer> numbers = new HashSet<>(Arrays.asList(4 , 3 , 2 , 1));
    
            List<Integer> sameOrder = numbers.stream().sorted().collect(Collectors.toList());
            Assert.assertEquals(asList(1 , 2 , 3 , 4) , sameOrder);
        }
    

    转换成其他集合

    有一些收集器可以生成其他集合。 比如前面已经见过的 toList,生成了 java.util.List 类的实例。 还有 toSet 和 toCollection, 分别生成 Set 和 Collection 类的实例。

    你希望使用一个特定的集合收集值, 而且你可以稍后指定该集合的类型。 比如, 你可能希望使用 TreeSet, 而不是由框架在背后自动为你指定一种类型的Set。 此时就可以使用 toCollection, 它接受一个函数作为参数, 来创建集合。

    @Test
        public void lambdaCollectOrder(){
            Set<Integer> numbers = new HashSet<>(Arrays.asList(4 , 3 , 2 , 1));
    
            List<Integer> sameOrder = numbers.stream().sorted().collect(Collectors.toCollection(ArrayList::new));
            Assert.assertEquals(asList(1 , 2 , 3 , 4) , sameOrder);
        }
    

    转换成值

    查找最大最小值

    还可以利用收集器让流生成一个值。 maxBy 和 minBy 允许用户按某种特定的顺序生成一个最大和最小值。

     @Test
        public void lambdaGetValueFromCollect() {
            Artist artist1 = new Artist("zzl-1", Collections.EMPTY_LIST, "china");
            Artist artist2 = new Artist("zzl-2", Collections.EMPTY_LIST, "china");
            Artist artist3 = new Artist("zzl-3", Collections.EMPTY_LIST, "china");
            Artist artist4 = new Artist("zzl-4", Collections.EMPTY_LIST, "china");
            Artist artist5 = new Artist("zzl-5", Collections.EMPTY_LIST, "china");
            Artist artist6 = new Artist("zzl-6", Collections.EMPTY_LIST, "china");
            Artist artist7 = new Artist("zzl-7", Collections.EMPTY_LIST, "china");
            List<Artist> members1 = Stream.of(artist1, artist2).collect(Collectors.toList());
            List<Artist> members2 = Stream.of(artist3, artist4, artist5, artist6).collect(Collectors.toList());
    
            List<Artist> members3 = Stream.of(artist7).collect(Collectors.toList());
            Artist artist9 = new Artist("zzl-mid", members1, "china");
            Artist artist10 = new Artist("zzl-max", members2, "china");
            Artist artist11 = new Artist("zzl-min", members3, "china");
    
    
            //最大值
            Stream<Artist> artists1 = Stream.of(artist9 , artist10 , artist11);
            Optional<Artist> optionalArtist1 = biggestGroup(artists1);
            System.out.println(optionalArtist1.get());
    
            //最小值
            Stream<Artist> artists2 = Stream.of(artist9 , artist10 , artist11);
            Optional<Artist> optionalArtist2 = minimumGroup(artists2);
            System.out.println(optionalArtist2.get());
    
        }
    
        public Optional<Artist> biggestGroup(Stream<Artist> artists) {
            Function<Artist, Long> getCount = artist -> artist.getMembers().count();
            return artists.collect(Collectors.maxBy(Comparator.comparing(getCount)));
        }
        public Optional<Artist> minimumGroup(Stream<Artist> artists) {
            Function<Artist, Long> getCount = artist -> artist.getMembers().count();
            return artists.collect(Collectors.minBy(Comparator.comparing(getCount)));
        }
    

    求平均数

    @Test
        public void lambdaAverage(){
            Track track1 = new Track("zzl-1" , 20);
            Track track2 = new Track("zzl-2" , 30);
            Track track3 = new Track("zzl-3" , 40);
            Track track4 = new Track("zzl-4" , 50);
            Track track5 = new Track("zzl-5" , 60);
            Track track6 = new Track("zzl-6" , 70);
    
            List<Track> tracks1 = Stream.of(track1 , track2).collect(Collectors.toList());
            List<Track> tracks2 = Stream.of(track3 , track4 , track5).collect(Collectors.toList());
            List<Track> tracks3 = Stream.of(track6 ).collect(Collectors.toList());
            
            Album album1= new Album("zzl-8" ,tracks1 , Collections.EMPTY_LIST );
            Album album2= new Album("zzl-9" ,tracks2 , Collections.EMPTY_LIST );
            Album album3= new Album("zzl-10" ,tracks3 , Collections.EMPTY_LIST );
    
            List<Album>  albums = Stream.of(album1 , album2 , album3).collect(Collectors.toList());
            double avg = averageNumberOfTracks(albums);
            System.out.println(avg);
    
        }
    
    public double averageNumberOfTracks(List<Album> albums) {
            return albums.stream()
                    .collect(Collectors.averagingInt(album -> album.getTrackList().size()));
        }
    

    数据分块

    你可能希望将其分成两个部分,可以使用两次过滤操作, 分别过滤两种数据。
    但是这样操作起来有问题。 首先, 为了执行两次过滤操作, 需要有两个流。 其次, 如果过滤操作复杂, 每个流上都要执行这样的操作, 代码也会变得冗余。

    有这样一个收集器 partitioningBy, 它接受一个流, 并将其分成两部分。它使用 Predicate 对象判断一个元素应该属于哪个部分, 并根据布尔值返回一个 Map 到列表。 因此, 对于 true List 中的元素,Predicate 返回 true; 对其他 List 中的元素, Predicate 返回 false。

       @Test
        public void lambdaPartitioningBy(){
            Artist artist1 = new Artist("zzl-1", Collections.EMPTY_LIST, "china");
            Artist artist2 = new Artist("zzl-2", Collections.EMPTY_LIST, "china");
            Artist artist3 = new Artist("zzl-3", Collections.EMPTY_LIST, "china");
            Artist artist4 = new Artist("zzl-4", Collections.EMPTY_LIST, "china");
            Artist artist5 = new Artist("zzl-5", Collections.EMPTY_LIST, "china");
            Artist artist6 = new Artist("zzl-6", Collections.EMPTY_LIST, "china");
            Artist artist7 = new Artist("zzl-7", Collections.EMPTY_LIST, "china");
    
            List<Artist> members1 = Stream.of(artist1, artist2).collect(Collectors.toList());
            List<Artist> members2 = Stream.of(artist3, artist4).collect(Collectors.toList());
    
            Artist artist9 = new Artist("zzl-9", members1, "china");
            Artist artist10 = new Artist("zzl-10", members2, "china");
    
            Stream<Artist> artists = Stream.of(artist9 , artist10 ,artist5 , artist6 , artist7 );
    
            Map<Boolean , List<Artist>> map = bandsAndSolo1(artists);
    
        }
    
        public Map<Boolean, List<Artist>> bandsAndSolo1(Stream<Artist> artists) {
            return  artists.collect(Collectors.partitioningBy(artist -> artist.isSolo()));
        }
    

    也可以使用方法引用代替 Lambda 表达式

       public Map<Boolean, List<Artist>> bandsAndSolo2(Stream<Artist> artists) {
            return  artists.collect(Collectors.partitioningBy(Artist::isSolo));
        }
    
    

    数据分组

    数据分组是一种更自然的分割数据操作, 与将数据分成 ture 和 false 两部分不同, 可以使用任意值对数据分组。

     @Test
        public void lambdaGroupingBy() {
            Artist artist1 = new Artist("zzl-1", Collections.EMPTY_LIST, "china");
            Artist artist2 = new Artist("zzl-2", Collections.EMPTY_LIST, "china");
            Artist artist3 = new Artist("zzl-3", Collections.EMPTY_LIST, "china");
            Album album1 = new Album("zzl-8", Collections.EMPTY_LIST, Stream.of(artist1).collect(Collectors.toList()));
            Album album2 = new Album("zzl-9", Collections.EMPTY_LIST, Stream.of(artist2).collect(Collectors.toList()));
            Album album3 = new Album("zzl-10", Collections.EMPTY_LIST, Stream.of(artist3).collect(Collectors.toList()));
            Album album4 = new Album("zzl-11", Collections.EMPTY_LIST, Stream.of(artist1).collect(Collectors.toList()));
    
    
            Stream<Album> albums = Stream.of(album1 , album2 , album3 , album4);
    
            Map<Artist, List<Album>> map = albumsByArtist(albums);
    
        }
    
        public Map<Artist, List<Album>> albumsByArtist(Stream<Album> albums) {
            return albums.collect(Collectors.groupingBy(Album::getMainMusician));
        }
    

    字符串

    很多时候, 收集流中的数据都是为了在最后生成一个字符串。 期望的输出
    为名字格式: "[George Harrison, John Lennon, Paul McCartney, Ringo Starr, The Beatles]"。

    在 Java 8 还未发布前, 实现该功能的代码可能如下所示。 通过不断迭代列表, 使用一个 StringBuilder 对象来记录结果。 每一步都取出一个艺术家的名字, 追加到 StringBuilder对象

    StringBuilder builder = new StringBuilder("[");
            for (Artist artist : artists) {
                if (builder.length() > 1)
                    builder.append(", ");
                String name = artist.getName();
                builder.append(name);
            } 
            builder.append("]");
            String result = builder.toString();
    

    显然, 这段代码不是非常好。 如果不一步步跟踪, 很难看出这段代码是干什么的。

    使用Java 8 提供的流和收集器就能写出更清晰的代码

    String result =
                    artists.stream()
                            .map(Artist::getName)
                            .collect(Collectors.joining(", ", "[", "]"));
    
    
     @Test
        public void lambdaFormatterStr(){
    
            Artist artist1 = new Artist("zzl-1", Collections.EMPTY_LIST, "china");
            Artist artist2 = new Artist("zzl-2", Collections.EMPTY_LIST, "china");
            Artist artist3 = new Artist("zzl-3", Collections.EMPTY_LIST, "china");
            Artist artist4 = new Artist("zzl-4", Collections.EMPTY_LIST, "china");
            Artist artist5 = new Artist("zzl-5", Collections.EMPTY_LIST, "china");
            Artist artist6 = new Artist("zzl-6", Collections.EMPTY_LIST, "china");
            Artist artist7 = new Artist("zzl-7", Collections.EMPTY_LIST, "china");
    
            List<Artist> members1 = Stream.of(artist1, artist2).collect(Collectors.toList());
            List<Artist> members2 = Stream.of(artist3, artist4).collect(Collectors.toList());
    
            Artist artist9 = new Artist("zzl-9", members1, "china");
            Artist artist10 = new Artist("zzl-10", members2, "china");
    
            List<Artist> artists = Stream.of(artist9, artist10, artist5, artist6, artist7).collect(Collectors.toList());
            String result =
                    artists.stream()
                            .map(Artist::getName)
                            .collect(Collectors.joining(", ", "[", "]"));
            System.out.println(result);
        }
    

    相关文章

      网友评论

          本文标题:Java 8 中的 Streams API-高级集合类和收集器(

          本文链接:https://www.haomeiwen.com/subject/cadzkctx.html