Learning: JDK1.8 new features: Collectors principle and usage

Learn to: https://blog.csdn.net/vbirdbest/article/details/80216713   Author: vbirdbest 

Learn to: https://blog.csdn.net/qq_39629277/article/details/83108585 


table of Contents

One: Introduction

 二、Collectors

1, the data collected into a list

1.1 Collectors toList()

1.2 Collectors  toSet()

2, the data collected into a collection

2.1 Collectors  toMap()

3, with a custom implementation of a data structure collection Collection

3.1 Collectors  toCollection()

4, a set of splice element

4.1Collectors  Joining()

4.2 collectingAndThen () to continue to do some processing after collection. 

5, the polymerization elements

5.1 maxBy,minBy,summingInt,averagingDouble

5.2 mapping

 

 6, group

7, the cumulative operation

to sum up:


One: Introduction


Stream There are two methods one collect and collectingAndThen for processing the data in the stream data may be performed in a convection polymerization operation, such as:

The data stream is converted into a set of type: toList, toset, toMap, toCollection
the data (character string) stream delimiters stitched together: joining
the data in the stream selecting the maximum value maxBy , minimum minBy , summing summingInt , averaging averagingDouble
data in the stream mapping processing mapping
data packets in the stream: groupingBy, partitioningBy
data in the stream cumulative: Reducing
 



 二、Collectors

1, the data collected into a list

 public final class Collectors {

	// 转换成集合
	public static <T> Collector<T, ?, List<T>> toList();
	public static <T> Collector<T, ?, Set<T>> toSet();
	public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper);
    public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory);
                                     
   // 拼接字符串,有多个重载方法                                  
   public static Collector<CharSequence, ?, String> joining(CharSequence delimiter);   
   public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                             CharSequence prefix,
                                                             CharSequence suffix);      
    // 最大值、最小值、求和、平均值                                                         
    public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator);
    public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator);
    public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper);      
    public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper);                   
    
    // 分组:可以分成true和false两组,也可以根据字段分成多组                                 
	public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier);
	// 只能分成true和false两组
	public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate);
	
	 // 映射
	 public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
                               Collector<? super U, A, R> downstream);
                               
	 public static <T, U> Collector<T, ?, U> reducing(U identity,
                                Function<? super T, ? extends U> mapper,
                                BinaryOperator<U> op);
}
 

1.1 Collectors toList()

Tip: Java 8, we can pass the constructor :: `` key to access the class object methods, static methods.

Reference article: https://blog.csdn.net/kegaofei/article/details/80582356

-> lambda expression is an anonymous function.

The simplest example is Collections.sort (list, (x, y) -> y - x); wherein

(X, y) -> y - x is a lambda expression, two input parameters x, y, returns the value x - y. "->" separated from the role. , Java automatically translated

Reference article: https://blog.csdn.net/kegaofei/article/details/80582356

Source:

 

/**
     * Returns a {@code Collector} that accumulates the input elements into a
     * new {@code List}. There are no guarantees on the type, mutability,
     * serializability, or thread-safety of the {@code List} returned; if more
     * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
     *
     * @param <T> the type of the input elements
     * @return a {@code Collector} which collects all the input elements into a
     * {@code List}, in encounter order
     */
    public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }

Example:

 @Test
    public void testCollectToList(){
        List<Integer> list = Arrays.asList(1, 2, 3);
        // 要求:将list中每个数值扩大10倍 结果为: [10, 20, 30]
        
        //先将list转化为stream类型,map内 等于遍历map方法使所有数据乘以10
        Stream stream=list.stream().map(i -> i * 10);//
        List<Integer> collectOne=(List<Integer>)stream.collect(Collectors.toList());
        
        //简写可如下,一般使用简写方便快捷
        List<Integer> collectTwo = list.stream().map(i -> i * 10).collect(Collectors.toList());

        System.out.println(collectOne.toString());
        System.out.println(collectTwo.toString());
    }
 

The benefit of this writing, eliminating redundant complex traversal operation. A simple line to complete the operation on the list data.

1.2 Collectors  toSet()

Source:

/**
     * Returns a {@code Collector} that accumulates the input elements into a
     * new {@code Set}. There are no guarantees on the type, mutability,
     * serializability, or thread-safety of the {@code Set} returned; if more
     * control over the returned {@code Set} is required, use
     * {@link #toCollection(Supplier)}.
     *
     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
     * Collector.
     *
     * @param <T> the type of the input elements
     * @return a {@code Collector} which collects all the input elements into a
     * {@code Set}
     */
    public static <T>
    Collector<T, ?, Set<T>> toSet() {
        return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_UNORDERED_ID);
    }

Example:

@Test
    public void testCollectToSet(){
        List<Integer> list = Arrays.asList(1, 2, 3);
        // 要求:将list中每个数值扩大10倍  

        //先将list转化为stream类型,map内 等于遍历map方法使所有数据乘以10
        Stream stream=list.stream().map(i -> i * 10);//
        Set<Integer> collect1=(Set<Integer>)stream.collect(Collectors.toSet());

        //简写可如下,一般使用简写方便快捷
        Set<Integer> collect2 = list.stream().map(i -> i * 10).collect(Collectors.toSet());

        System.out.println(collect1.toString());
        System.out.println(collect2.toString());
    }

Because the set is so disorderly as the result of [20,10,30]


2, the data collected into a collection

2.1 Collectors  toMap()

Source:

/**
     * students to their grade point average:
     * <pre>{@code
     *     Map<Student, Double> studentToGPA
     *         students.stream().collect(toMap(Functions.identity(),
     *                                         student -> computeGPA(student)));
     * }</pre>
     * And the following produces a {@code Map} mapping a unique identifier to
     * students:
     * <pre>{@code
     *     Map<String, Student> studentIdToStudent
     *         students.stream().collect(toMap(Student::getId,
     *                                         Functions.identity());
     * }</pre>
*/
public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper) {
        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
    }

Example:

 

   @Test
    public void testCollectToMap(){
        List<Integer> list = Arrays.asList(1, 2, 3);
        // {key1=value:10, key2=value:20, key3=value:30}  {key1=value:1 , key2=value:2 , key3=value:3 }
        // toMap 可用于将List转为Map,便于通过key快速查找到某个value
        Map<String, String> collect1 = list.stream().map(i -> i * 10).collect(Collectors.toMap(key -> "key" + key/10, value -> "value:" + value));
        Map<String, String> collect2 = list.stream().map(i -> i).collect(Collectors.toMap(key -> "key" + key, value -> "value:" + value));

        //实体list转化map id作为主键,对象作为value
        List<DatabusTask> databusTaskArrayList=new ArrayList<DatabusTask>();
        DatabusTask databusTask=new DatabusTask();
        databusTask.setId(1);
        databusTask.setFile_name("测试");
        databusTaskArrayList.add(databusTask);

        Map<Integer,DatabusTask> taskMap = databusTaskArrayList.stream().collect(Collectors.toMap(DatabusTask::getId, entity -> entity));
        System.out.println(collect1.toString());
        System.out.println(collect2.toString());
        System.out.println(taskMap.toString());
    }

The benefit of this may be quickly written content into custom entity map set, entity list can be converted to id as key to the object as a set value map is convenient in some cases taken directly to give the corresponding object information id


3, with a custom implementation of a data structure collection Collection

3.1 Collectors  toCollection()

Source:

/**
     * Returns a {@code Collector} that accumulates the input elements into a
     * new {@code Collection}, in encounter order.  The {@code Collection} is
     * created by the provided factory.
     *
     * @param <T> the type of the input elements
     * @param <C> the type of the resulting {@code Collection}
     * @param collectionFactory a {@code Supplier} which returns a new, empty
     * {@code Collection} of the appropriate type
     * @return a {@code Collector} which collects all the input elements into a
     * {@code Collection}, in encounter order
     */
    public static <T, C extends Collection<T>>
    Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
        return new CollectorImpl<>(collectionFactory, Collection<T>::add,
                                   (r1, r2) -> { r1.addAll(r2); return r1; },
                                   CH_ID);
    }

Examples
 

 @Test
    public void testCollectToCollection(){
        //直接创建treeSet数据 [1, 3, 4]
        TreeSet<Integer> collect3= Stream.of(1, 3, 4).collect(Collectors.toCollection(TreeSet::new));
        System.out.println(collect3.toString());
        List<String> list = Arrays.asList("java", "python", "C++","php","java");
        //用LinkedList收集
        List<String> linkedListResult = list.stream().collect(Collectors.toCollection(LinkedList::new));
        linkedListResult.forEach(System.out::println);
        System.out.println("--------------");

        //用CopyOnWriteArrayList收集
        List<String> copyOnWriteArrayListResult = list.stream().collect(Collectors.toCollection(CopyOnWriteArrayList::new));
        copyOnWriteArrayListResult.forEach(System.out::println);
        System.out.println("--------------");

        //用TreeSet收集
        TreeSet<String> treeSetResult = list.stream().collect(Collectors.toCollection(TreeSet::new));
        treeSetResult.forEach(System.out::println);

    }


4, a set of splice element

4.1Collectors  Joining()

Source joining three kinds of argument types

 /**
     * Returns a {@code Collector} that concatenates the input elements into a
     * {@code String}, in encounter order.
     *
     * @return a {@code Collector} that concatenates the input elements into a
     * {@code String}, in encounter order
     */
    public static Collector<CharSequence, ?, String> joining() {
        return new CollectorImpl<CharSequence, StringBuilder, String>(
                StringBuilder::new, StringBuilder::append,
                (r1, r2) -> { r1.append(r2); return r1; },
                StringBuilder::toString, CH_NOID);
    }

    /**
     * Returns a {@code Collector} that concatenates the input elements,
     * separated by the specified delimiter, in encounter order.
     *
     * @param delimiter the delimiter to be used between each element
     * @return A {@code Collector} which concatenates CharSequence elements,
     * separated by the specified delimiter, in encounter order
     */
    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
        return joining(delimiter, "", "");
    }

    /**
     * Returns a {@code Collector} that concatenates the input elements,
     * separated by the specified delimiter, with the specified prefix and
     * suffix, in encounter order.
     *
     * @param delimiter the delimiter to be used between each element
     * @param  prefix the sequence of characters to be used at the beginning
     *                of the joined result
     * @param  suffix the sequence of characters to be used at the end
     *                of the joined result
     * @return A {@code Collector} which concatenates CharSequence elements,
     * separated by the specified delimiter, in encounter order
     */
    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                             CharSequence prefix,
                                                             CharSequence suffix) {
        return new CollectorImpl<>(
                () -> new StringJoiner(delimiter, prefix, suffix),
                StringJoiner::add, StringJoiner::merge,
                StringJoiner::toString, CH_NOID);
    }

Example:

    @Test
    public void testCollectJoining(){

        List<String> list = Arrays.asList("java", "python", "C++","php","java");
        //直接将输出结果拼接
        System.out.println(list.stream().collect(Collectors.joining()));
        //每个输出结果之间加拼接符号“|”
        System.out.println(list.stream().collect(Collectors.joining(" | ")));
        //输出结果开始头为Start--,结尾为--End,中间用拼接符号“||”
        System.out.println(list.stream().collect(Collectors.joining(" || ", "Start--", "--End")));
        
        // a,b,c
        List<String> list2 = Arrays.asList("a", "b", "c");
        //此方法等同于直接 String result = Joiner.on(",").join(list2); 将数组转化逗号分隔字符串
        String result = list2.stream().collect(Collectors.joining(","));
        System.out.println(result);
      
    }

4.2 collectingAndThen () to continue to do some processing after collection. 

Source:

 /**
     * Adapts a {@code Collector} to perform an additional finishing
     * transformation.  For example, one could adapt the {@link #toList()}
     * collector to always produce an immutable list with:
     * <pre>{@code
     *     List<String> people
     *         = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
     * }</pre>
     *
     * @param <T> the type of the input elements
     * @param <A> intermediate accumulation type of the downstream collector
     * @param <R> result type of the downstream collector
     * @param <RR> result type of the resulting collector
     * @param downstream a collector
     * @param finisher a function to be applied to the final result of the downstream collector
     * @return a collector which performs the action of the downstream collector,
     * followed by an additional finishing step
     */
    public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
                                                                Function<R,RR> finisher) {
        Set<Collector.Characteristics> characteristics = downstream.characteristics();
        if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
            if (characteristics.size() == 1)
                characteristics = Collectors.CH_NOID;
            else {
                characteristics = EnumSet.copyOf(characteristics);
                characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
                characteristics = Collections.unmodifiableSet(characteristics);
            }
        }
        return new CollectorImpl<>(downstream.supplier(),
                                   downstream.accumulator(),
                                   downstream.combiner(),
                                   downstream.finisher().andThen(finisher),
                                   characteristics);
    }

Example:

  @Test
    public void testCollectingAndThan(){
        List<String> list2 = Arrays.asList("a", "b", "c");
        // Collectors.joining(",")的结果是:a,b,c  然后再将结果 x + "d"操作, 最终返回a,b,cd
        String str= Stream.of("a", "b", "c").collect(Collectors.collectingAndThen(Collectors.joining(","), x -> x + "d"));
        System.out.println(str);


    }


5, the polymerization elements

5.1 maxBy,minBy,summingInt,averagingDouble

@Test
public void test(){
    // 求最值 3
    List<Integer> list = Arrays.asList(1, 2, 3);
    Integer maxValue = list.stream().collect(Collectors.collectingAndThen(Collectors.maxBy((a, b) -> a - b), Optional::get));


    // 最小值 1
    Integer minValue = list.stream().collect(Collectors.collectingAndThen(Collectors.minBy((a, b) -> a - b), Optional::get));

    // 求和 6
    Integer sumValue = list.stream().collect(Collectors.summingInt(item -> item));

    // 平均值 2.0
    Double avg = list.stream().collect(Collectors.averagingDouble(x -> x));
}
 

5.2 mapping

 

@Test
public void test(){
    // 映射:先对集合中的元素进行映射,然后再对映射的结果使用Collectors操作
    // A,B,C
    Stream.of("a", "b", "c").collect(Collectors.mapping(x -> x.toUpperCase(), Collectors.joining(",")));
}


 6, group

public class User {
    private Long id;
    private String username;
    private Integer type;

    // Getter & Setter & toString
}

@Test
public void testGroupBy(){
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    // 奇偶数分组:奇数分一组,偶数分一组
    // groupingBy(Function<? super T, ? extends K> classifier) 参数是Function类型,Function返回值可以是要分组的条件,也可以是要分组的字段
    // 返回的结果是Map,其中key的数据类型为Function体中计算类型,value是List<T>类型,为分组的结果
    Map<Boolean, List<Integer>> result = list.stream().collect(Collectors.groupingBy(item -> item % 2 == 0));
    // {false=[1, 3, 5, 7, 9], true=[2, 4, 6, 8, 10]}
    System.out.println(result);


	 // partitioningBy 用于分成两组的情况
    Map<Boolean, List<Integer>> twoPartiton = list.stream().collect(Collectors.partitioningBy(item -> item % 2 == 0));
    System.out.println(twoPartiton);
    
    
    User user = new User(1L, "zhangsan", 1);
    User user2 = new User(2L, "lisi", 2);
    User user3 = new User(3L, "wangwu", 3);
    User user4 = new User(4L, "fengliu", 1);
    List<User> users = Arrays.asList(user, user2, user3, user4);
    // 根据某个字段进行分组
    Map<Integer, List<User>> userGroup = users.stream().collect(Collectors.groupingBy(item -> item.type));

    /**
     * key 为要分组的字段
     * value 分组的结果
     * {
     *  1=[User{id=1, username='zhangsan', type=1}, User{id=4, username='fengliu', type=1}],
     *  2=[User{id=2, username='lisi', type=2}],
     *  3=[User{id=3, username='wangwu', type=3}]
     * }
     */
    System.out.println(userGroup);
}    
 

 

7, the cumulative operation

 

@Test
public void testReducing(){
		
    // sum: 是每次累计计算的结果,b是Function的结果
    System.out.println(Stream.of(1, 3, 4).collect(Collectors.reducing(0, x -> x + 1, (sum, b) -> {
        System.out.println(sum + "-" + b);
        return sum + b;
    })));

	
	 // 下面代码是对reducing函数功能实现的描述,用于理解reducing的功能
    int sum = 0;
    List<Integer> list3 = Arrays.asList(1, 3, 4);
    for (Integer item : list3) {
        int b = item + 1;
        System.out.println(sum + "-" + b);
        sum = sum + b;
    }
    System.out.println(sum);

		
    // 注意reducing可以用于更复杂的累计计算,加减乘除或者更复杂的操作
    // result = 2 * 4 * 5 = 40
    System.out.println(Stream.of(1, 3, 4).collect(Collectors.reducing(1, x -> x + 1, (result, b) -> {
        System.out.println(result + "-" + b);
        return result * b;
    })));
}
 
 

Small Example: requires "a, bb # b # c | #d" # Alternatively comma and apostrophe

    @Test
    public void test(){
        String param="a,bb#b#c|#d";
        //第一种写法
        Optional<String> optional=  Stream.of(param.split("#")).reduce((s1, s2)->s1+"','"+s2);
        String value= "'"+optional.get()+"'";
        //第二种写法
        List<String> lis = Arrays.asList(param.split("#"));
        String value2=lis.stream().collect(Collectors.joining("','", "'", "'"));
        
        System.out.println(value);
        System.out.println(value2);
        //结果一致
    }

New features in favor jdk1.8 collectors will find a lot of things have multiple solutions. Can quickly resolve some of the commonly used traversal issues, data type conversion, providing performance, reduce redundant code, the only drawback may be the readability of the poor people who do not understand. Take advantage of many new features of 1.8, keywords, symbols, and so on.


to sum up:

Guess you like

Origin blog.csdn.net/Alice_qixin/article/details/87169586