Together to learn Java8 (seven) - Stream (in)

In 一起来学Java8(七)——Stream(上), we learned a Stream object common methods and usage. Now take a deep knowledge of the Stream.collect()use of

collect basic usage

means to collect the collection, which is the Stream elements collected and grouped, a new collection of objects returned. First look at a simple example:

public class CollectTest {

    @Data
    @AllArgsConstructor
    static class Goods {
        private String goodsName;
        private int price;
    }
    
    public static void main(String[] args) {
        List<Goods> list = Arrays.asList(
                new Goods("iphoneX", 4000)
                , new Goods("mate30 pro", 5999)
                , new Goods("redmek20", 2999)
                );
        List<String> nameList = list.stream()
            .map(Goods::getGoodsName)
            .collect(Collectors.toList());
    }

}复制代码

In this example, the trade name returned by the map method, and then put all the trade names into the List object.

View source found, collect process consists of two overloaded methods composition.

  • method 1:
<R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);复制代码

  • Method 2:
<R, A> R collect(Collector<? super T, A, R> collector);复制代码

Wherein the most widely used is a method 2, this method can be seen as a shortcut method, because Collector likewise provided these three parameters, it is easy to guess, or to use the underlying process corresponding implementation.Supplier supplier, BiConsumer accumulator, BiConsumer combiner

We can start with collect(Collector collector)the beginning to start, go through this process of getting to know the usage.

Collectors

Stream.collect(Collector collector)Collector Parameters object method mainly Collectorsprovides classes. Collectors class which contains a series of static method, returns Collector for the object, a method commonly used as listed below:

Method name description
averagingXX Averaging
counting Seeking the number of elements in the set
groupingBy The collection group
joining Collection element splicing
mapping Can be re-mapped values ​​during packet
maxBy Seeking maximum
minBy For the minimum
partitioningBy Partition the elements
reducing induction
summarizingXX Gather
toCollection Converted into a collection of objects
toConcurrentMap Converted into ConcurrentMap
toList Convert List
toMap Converted into a Map
toSet Converted into a Set

Here we turn off his usefulness in terms of each method.

averagingXX

averagingXX including averagingDouble, averagingInt, averagingLong. They represent averaged.

double averagingInt = Stream.of(1, 2, 3)
        .collect(Collectors.averagingInt(val -> val));
System.out.println("averagingInt:" + averagingInt);

double averagingLong = Stream.of(10L, 21L, 30L)
        .collect(Collectors.averagingLong(val -> val));
System.out.println("averagingLong:" + averagingLong);

double averagingDouble = Stream.of(0.1, 0.2, 0.3)
        .collect(Collectors.averagingDouble(val -> val));
System.out.println("averagingDouble:" + averagingDouble);复制代码

Their parameters are a function interface, you can be prepared using a Lambda expression, wherein expression Lambda Stream parameters of elements, returns a value to be averaged. This is below the average of commodity Liezi is seeking:

List<Goods> list = Arrays.asList(
                new Goods("iphoneX", 4000)
                , new Goods("mate30 pro", 5999)
                , new Goods("redmek20", 2999)
                );
        
double avgPrice = list.stream()
    .collect(Collectors.averagingInt(goods -> goods.getPrice()));
System.out.println("商品的平均价格:" + avgPrice);复制代码

summingXX

And averagingXX Similarly, summingXX element method is used to find the sum of the values ​​set.

double summingInt = Stream.of(1, 2, 3)
        .collect(Collectors.summingInt(val -> val));
System.out.println("summingInt:" + summingInt);

double summingLong = Stream.of(10L, 21L, 30L)
        .collect(Collectors.summingLong(val -> val));
System.out.println("summingLong:" + summingLong);

double summingDouble = Stream.of(0.1, 0.2, 0.3)
        .collect(Collectors.summingDouble(val -> val));
System.out.println("summingDouble:" + summingDouble);复制代码

print:

summingInt:6.0
summingLong:61.0
summingDouble:0.6复制代码

counting()

Counting () returns the number of elements in a collection.

long count = Stream.of(1,2,3,4,5)
        .collect(Collectors.counting());
System.out.println("count:" + count); // 5复制代码

summarizingXX

The above talked about averagingXX (averaging), summingXX (sum), counting (total demand), if I want to get all three at the same time the number of how to do it, you can use summarizingXX.

IntSummaryStatistics summarizingInt = Stream.of(1, 2, 3)
                .collect(Collectors.summarizingInt(val -> val));
System.out.println("平均值:" + summarizingInt.getAverage());
System.out.println("总个数:" + summarizingInt.getCount());
System.out.println("总和:" + summarizingInt.getSum());
System.out.println("最大值:" + summarizingInt.getMax());
System.out.println("最小值:" + summarizingInt.getMin());复制代码

print:

平均值:2.0
总个数:3
总和:6
最大值:3
最小值:1复制代码

summarizingInt the statistical results into a IntSummaryStatistics objects inside, it can obtain different statistical information in the object.

groupingBy()

groupingBy () is a set of elements grouped by the three overloaded methods composition

  • Overload 1: groupingBy (Function)
  • Overload 2: groupingBy (Function, Collector)
  • 重载3: groupingBy(Function, Supplier, Collector)

Overload overloaded call 1 wherein 2, 3 overloaded call the overloaded 2, thus eventually implemented to be overloaded 3.

First, a look overloaded groupingBy(Function)usage, this method of default packets to the new List, the following example of this type of product are grouped into the same type of goods in a List.

@Data
@AllArgsConstructor
static class Goods {
    private String goodsName;
    // 类型,1:手机,2:电脑
    private int type;
    @Override
    public String toString() {
        return goodsName;
    }
}

public static void main(String[] args) {
    List<Goods> list = Arrays.asList(
            new Goods("iphoneX", 1)
            , new Goods("mate30 pro", 1)
            , new Goods("thinkpad T400", 2)
            , new Goods("macbook pro", 2)
            );
    
    Map<Integer, List<Goods>> goodsListMap = list.stream()
        .collect(Collectors.groupingBy(Goods::getType));
    goodsListMap.forEach((key, value) -> {
        System.out.println("类型" + key + ":" + value);
    });
}复制代码

print:

类型1:[iphoneX, mate30 pro]
类型2:[thinkpad T400, macbook pro]复制代码

Speaking of the above groupingBy(Function)is actually called groupingBy(Function, Collector), where the second parameter Collectordetermines the conversion to where, by default toList(), see groupingBy(Function)the source code:

public static <T, K> Collector<T, ?, Map<K, List<T>>>
    groupingBy(Function<? super T, ? extends K> classifier) {
        return groupingBy(classifier, toList());
    }复制代码

So we can call groupingBy(Function, Collector)manually specify the Collector, assuming that the elements we need to convert them into Set, you can write:

Map<Integer, Set<Goods>> goodsListMap = list.stream()
        .collect(Collectors.groupingBy(Goods::getType, Collectors.toSet()));复制代码

View overloaded method Source 2, found its calling overloaded 3:

public static <T, K, A, D>
    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream) {
        return groupingBy(classifier, HashMap::new, downstream);
    }复制代码

Wherein Goods::getTypethe corresponding classifier, Collectors.toSet()a corresponding downstream. The middle of that parameter HashMap::newmeaning is clear, and that is the return of Map implementation class which, if we wanted to change LinkedHashMap, write:

LinkedHashMap<Integer, Set<Goods>> goodsListMap = list.stream()
        .collect(Collectors.groupingBy(Goods::getType, LinkedHashMap::new, Collectors.toSet()));
        复制代码

This is heavy-duty use 3.

GroupingByConcurrent Collectors method is based on the heavy-duty 3 from the middle of the code changed ConcurrentHashMap::newit.

public static <T, K>
    Collector<T, ?, ConcurrentMap<K, List<T>>>
    groupingByConcurrent(Function<? super T, ? extends K> classifier) {
        return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
    }复制代码

Collector parameters groupingBy method not only can toList (), toSet (), it also has a more flexible usage, before we are converted form, value is stored in a collection of objects, if you do not want so much property, only want the object to which the trade name ,, which means that we want , which is a key commodity type, value is the name of the collection of goods.Map > Map >

This time Collectors.mapping()comes in handy, we use the groupingBy(Function, Collector)method, the second parameter passedCollectors.mapping()

Map<Integer, List<String>> goodsListMap = 
list.stream()
    .collect(
         Collectors.groupingBy(
            Goods::getType, 
            Collectors.mapping(Goods::getGoodsName, Collectors.toList())
         )
    );复制代码

Mapping () method takes two parameters, a first parameter specifies the property returns, the second parameter which specifies the return collection.

joining

The method of joining the elements can be spliced ​​together Stream.

List<String> list = Arrays.asList("hello", "world");
String str = list.stream().collect(Collectors.joining());
System.out.println(str); // 打印:helloworld复制代码

You can also specify the delimiter:

List<String> list = Arrays.asList("hello", "world");
String str = list.stream().collect(Collectors.joining(","));
System.out.println(str); // 打印:hello,world复制代码

In addition, the Stringclass provides a join method, function is the same

String str2 = String.join(",", list);
System.out.println(str2);复制代码

maxBy&minBy

  • maxBy: find the largest element in the Stream
@Data
@AllArgsConstructor
static class Goods {
    private String goodsName;
    private int price;
}

public static void main(String[] args) {
    List<Goods> list = Arrays.asList(
            new Goods("iphoneX", 4000)
            , new Goods("mate30 pro", 5999)
            , new Goods("redmek20", 2999)
            );
    
    Goods maxPriceGoods = list.stream()
        .collect(
            Collectors.maxBy(
                Comparator.comparing(Goods::getPrice)
            )
        )
        .orElse(null);
    System.out.println("最贵的商品:" + maxPriceGoods);
}复制代码

The above example demonstrates find the most expensive commodity, Collectors.maxBy () method requires passing a comparison, we need to compare based on price goods.

Similarly, to find the cheapest goods simply maxByreplace minBycan.

partitioningBy

The method represents partitioningBy partition, it will be according to the conditions in the Stream element divided into two parts, and which were placed into a Map, the Map key is a Boolean type, the key storage element satisfies the condition part is true, false key is stored is not satisfied element conditions.

{
    true -> 符合条件的元素
    false -> 不符合条件的元素
}复制代码

The method consists of two overloaded methods partitioningBy composition

  • Overload 1: partitioningBy (Predicate)
  • 重载2:partitioningBy(Predicate, Collector)

Which will call the overloaded heavy-duty 1 2, and therefore eventually called method overloading 2, we look at the heavy load 1 method.

The following example of the type of product, the product is divided into categories of goods and non-mobile phones commodities.

@Data
@AllArgsConstructor
static class Goods {
    private String goodsName;
    // 类型,1:手机,2:电脑
    private int type;
    @Override
    public String toString() {
        return goodsName;
    }
}

public static void main(String[] args) {
    List<Goods> list = Arrays.asList(
            new Goods("iphoneX", 1)
            , new Goods("mate30 pro", 1)
            , new Goods("thinkpad T400", 2)
            , new Goods("macbook pro", 2)
            );
    
    // 手机归为一类,非手机商品归为一类
    // true -> 手机类商品
    // false -> 非手机类商品
    Map<Boolean, List<Goods>> goodsMap = list.stream()
        .collect(
            Collectors.partitioningBy(goods -> goods.getType() == 1)
        );
    // 获取手机类商品
    List<Goods> mobileGoods = goodsMap.get(true);
    System.out.println(mobileGoods);
}复制代码

The second parameter partitioningBy (Predicate, Collector) method can be used to specify a set of elements used by default List store, if you want to use Set to store, write:

Map<Boolean, Set<Goods>> goodsMap = list.stream()
    .collect(
        Collectors.partitioningBy(
            goods -> goods.getType() == 1
            // 指定收集类型
            , Collectors.toSet())
    );复制代码

toList & toSet & toCollection

toList toSet and may convert the elements into Stream List, Set collection, which is more and more used two methods.

Stream<Goods> stream = Stream.of(
        new Goods("iphoneX", 4000)
        , new Goods("mate30 pro", 5999)
        , new Goods("redmek20", 2999)
        );

List<Goods> list = stream.collect(Collectors.toList());
Set<Goods> set = stream.collect(Collectors.toSet());复制代码

By default, toList returns ArrayList, toSet returns HashSet, if you want to return a collection of other types such as LinkedList, you can use toCollection, it allows developers to specify their own set of needs what.

LinkedList<Goods> linkedList = stream.collect(Collectors.toCollection(LinkedList::new));复制代码

toConcurrentMap

Stream toConcurrentMap approach is to convert into ConcurrentMap, it is composed of three overloads

  • Overload 1:toConcurrentMap(Function keyMapper, Function valueMapper)
  • Overload 2:toConcurrentMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction)
  • Heavy-duty 3:toConcurrentMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction, Supplier mapSupplier)

Overload 1 wherein calling overloaded 2, 3 overloaded call the overloaded 2, eventually implemented method overloads up to 3.

Look at the heavy-duty 1, two parameters

  • keyMapper: key values ​​specified in ConcurrentMap
  • valueMapper: corresponding to the specified key value

The following example is the name of the product as a key, as a value price

List<Goods> list = Arrays.asList(
        new Goods("iphoneX", 4000)
        , new Goods("mate30 pro", 5999)
        , new Goods("redmek20", 2999)
);
ConcurrentMap<String, Integer> goodsMap = list.stream()
        .collect(
                Collectors.toConcurrentMap(Goods::getGoodsName, Goods::getPrice)
        );
System.out.println(goodsMap);复制代码

print:

{mate30 pro=5999, iphoneX=4000, redmek20=2999}复制代码

Note: This method requires the key can not be repeated, if there are duplicate key, it will throw IllegalStateException exception if there are duplicate key, use that overloads 2toConcurrentMap(Function, Function, BinaryOperator)

Then look at the heavy-duty 2: toConcurrentMap(Function, Function, BinaryOperator)before this method two parameters with heavy-duty 1 as the third argument to deal with conflict situations key, allowing developers to select a value return value.

List<Goods> list = Arrays.asList(
        new Goods("iphoneX", 4000)
        , new Goods("mate30 pro", 5999)
        , new Goods("mate30 pro", 6000) // 这里有两个冲突了
        , new Goods("redmek20", 2999)
);
ConcurrentMap<String, Integer> goodsMap = list.stream()
        .collect(
                Collectors.toConcurrentMap(Goods::getGoodsName, Goods::getPrice, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer price1, Integer price2) {
                        // 选择价格贵的返回
                        return Math.max(price1, price2);
                    }
                })
        );
System.out.println(goodsMap);复制代码

print:{mate30 pro=6000, iphoneX=4000, redmek20=2999}

This example mate30 pro repeat as key in BinaryOperator, we chose a piece of data that the high price of return.

Finally, look overloaded 3, compared to the heavy-duty 2, the addition of a parameter Supplier, which allows developers to specify a return one kindConcurrentMap

Call the overloaded overloaded 2 3, is used by default ConcurrentMap::new.

Note: The fourth parameter must be a subclass of ConcurrentMap or ConcurrentMap

Section

Data in this chapter explain the Stream.collectusage, as well as Collectorsthe use of static methods of the class, the next article, we will explain in detail about reducethe relevant usage.

Dry goods on a regular basis to share technology, learn together and progress together! Micro-channel public number: Under ape knocked on code

Guess you like

Origin juejin.im/post/5dba7971518825698010f23c