Java-8-Collectors类

Java-8-Collectors类

final class Collectors

思维导图:

在这里插入图片描述

Stream 的核心在于Collectors,即对处理后的数据进行收集。Collectors 提供了非常多且强大的API,可以将最终的数据收集成List、Set、Map,甚至是更复杂的结构(这三者的嵌套组合)。

toList

源码:


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);
    }

将数据收集进一个列表(Stream 转换为 List,允许重复值,有顺序)

使用

public class M1 {


    public static void main(String[] args) {

        List<String> list = Stream.of("AA","BB","CC").collect(Collectors.toList());
        list.forEach(s->System.out.println(s));

        System.out.println("----------");

        List<Integer> l1 = Create_Data.supply_Integers();


        // 收集偶数到集合里面
        List<Integer> even = l1.stream()
                .filter(integer -> integer % 2 == 0)
                .collect(Collectors.toList());

        System.out.println(even);

    }
}

toSet

源码:


 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);
    }

将数据收集进一个集合(Stream 转换为 Set,不允许重复值,没有顺序)

使用

public class M1 {


    public static void main(String[] args) {

        Set<String> set = Stream.of("AA","AA","BB").collect(Collectors.toSet());
        set.forEach(s->System.out.println(s));

    }
}


toCollection

源码:


 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);
    }

Collectors.toCollection() 将数据转成Collection,只要是Collection 的实现都可以,例如ArrayList、HashSet ,该方法接受一个Collection 的实现对象或者说Collection 工厂的入参

使用

public class M1 {


    public static void main(String[] args) {

        List<String> l1 = Stream.of(
                "kdkkd","kdkdkkd","lokfkf"
        ).collect(Collectors.toCollection(ArrayList::new));

        System.out.println(l1);

        System.out.println("-------------");


        Set<String> set1 = Stream.of("a","a","bb")
                .collect(Collectors.toCollection(HashSet::new));

        System.out.println(set1);

    }
}


toMap

源码:


    //  * <p>If the mapped keys contains duplicates (according to
    //  * {@link Object#equals(Object)}), an {@code IllegalStateException} is
    //  * thrown when the collection operation is performed.  If the mapped keys
    //  * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
    //  * instead.

    //  * @param <T> the type of the input elements
    //  * @param <K> the output type of the key mapping function
    //  * @param <U> the output type of the value mapping function
    //  * @param keyMapper a mapping function to produce keys
    //  * @param valueMapper a mapping function to produce values
    //  * @return a {@code Collector} which collects elements into a {@code Map}
    //  * whose keys and values are the result of applying mapping functions to
    //  * the input elements
  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);
    }


    
    //  * <p>If the mapped
    //  * keys contains duplicates (according to {@link Object#equals(Object)}),
    //  * the value mapping function is applied to each equal element, and the
    //  * results are merged using the provided merging function.


    //  * @param <T> the type of the input elements
    //  * @param <K> the output type of the key mapping function
    //  * @param <U> the output type of the value mapping function
    //  * @param keyMapper a mapping function to produce keys
    //  * @param valueMapper a mapping function to produce values
    //  * @param mergeFunction a merge function, used to resolve collisions between
    //  *                      values associated with the same key, as supplied
    //  *                      to {@link Map#merge(Object, Object, BiFunction)}
    public static <T, K, U>
    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
                                    Function<? super T, ? extends U> valueMapper,
                                    BinaryOperator<U> mergeFunction) {
        return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
    }



    // * @param <T> the type of the input elements
    //  * @param <K> the output type of the key mapping function
    //  * @param <U> the output type of the value mapping function
    //  * @param <M> the type of the resulting {@code Map}
    //  * @param keyMapper a mapping function to produce keys
    //  * @param valueMapper a mapping function to produce values
    //  * @param mergeFunction a merge function, used to resolve collisions between
    //  *                      values associated with the same key, as supplied
    //  *                      to {@link Map#merge(Object, Object, BiFunction)}
    //  * @param mapSupplier a function which returns a new, empty {@code Map} into
    //  *                    which the results will be inserted
    public static <T, K, U, M extends Map<K, U>>
    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                                Function<? super T, ? extends U> valueMapper,
                                BinaryOperator<U> mergeFunction,
                                Supplier<M> mapSupplier) {
        BiConsumer<M, T> accumulator
                = (map, element) -> map.merge(keyMapper.apply(element),
                                              valueMapper.apply(element), mergeFunction);
        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
    }

第一个

如果遇到键重复的情况会抛出IllegalStateException异常

使用
public class Student {


    static private Random random = new Random();

    static private DecimalFormat df = new DecimalFormat("0.00");

    private int id;

    private String name;

    private int age;

    private int G_math;

    private int G_english;

    private int G_chinese;


    public Student(int id, String name, int age, int g_math, int g_english, int g_chinese) {
        this.id = id;
        this.name = name;
        this.age = age;
        G_math = g_math;
        G_english = g_english;
        G_chinese = g_chinese;
    }

    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", G_math=" + G_math +
                ", G_english=" + G_english +
                ", G_chinese=" + G_chinese +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getG_math() {
        return G_math;
    }

    public void setG_math(int g_math) {
        G_math = g_math;
    }

    public int getG_english() {
        return G_english;
    }

    public void setG_english(int g_english) {
        G_english = g_english;
    }

    public int getG_chinese() {
        return G_chinese;
    }

    public void setG_chinese(int g_chinese) {
        G_chinese = g_chinese;
    }

    public static int computeGPA(Student student){
        return (student.getG_chinese() + student.getG_english() + student.getG_math()) / 3;
    }

    public static List<Student> supple_S(){
        List<Student> d = new ArrayList<>();

        for (int i = 0; i < 20; i++) {
            d.add(new Student(i,i+"号学生",random.nextInt(25),random.nextInt(100),random.nextInt(100),random.nextInt(100)));
        }

        return d;

    }




    public static void main(String[] args) {

        supple_S().stream()
                .forEach(System.out::println);

    }
}

public class M1 {


//      * <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 void main(String[] args) {

        List<Student> students = Student.supple_S();

        Map<Student,Integer> studentToGPA = students.stream()
                .collect(Collectors.toMap(Function.identity(),student -> Student.computeGPA(student)));

//        System.out.println(studentToGPA);

        studentToGPA.forEach(
                (k,v) ->
                        System.out.println(k + "---" + v)
        );

        System.out.println("----------------");

        Map<Integer, Student> studentIdToStudent = students.stream()
                .collect(Collectors.toMap(Student::getId,Function.identity()));

        studentIdToStudent.forEach(
                (k,v) ->
                        System.out.println(k + "---" + v)
        );

        System.out.println("----------------");


        Map<String,String> map = Stream.of("AA","BB","CC").collect(Collectors.toMap(k->k, v->v+v));
        map.forEach((k,v)->System.out.println("key:"+k +"  value:"+v));




    }
}


第二个

mergeFunction是解决当key相同时,取哪个value的问题,由返回值指定,当返回null时,从map中移除当前entry

当遇到重复的键时,API文档给出的做法是相同key的情况下,把value变成list,形成Map(Object,List)的形式


//  * <pre>{@code
//      *     Map<String, String> phoneBook
//      *         people.stream().collect(toMap(Person::getName,
//      *                                       Person::getAddress,
//      *                                       (s, a) -> s + ", " + a));
//      * }</pre>

使用

public class Person {

    private static String[] addresss =
            {
                    "北京",
                    "上海",
                    "广州",
                    "深圳",
                    "南京"

            };

    private static Random random = new Random();

    private String name;

    private String address;

    public Person(String name, String address) {
        this.name = name;
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public static List<Person> supply_P(){
        List<Person> people = new ArrayList<>();

        for (int i = 0; i < 3; i++) {

            people.add(new Person("A",addresss[random.nextInt(addresss.length)]));
        }

        for (int i = 0; i < 3; i++) {

            people.add(new Person("C",addresss[random.nextInt(addresss.length)]));
        }

        return people;

    }
}


public class M2 {

//       * @apiNote
//     * There are multiple ways to deal with collisions between multiple elements
//     * mapping to the same key.  The other forms of {@code toMap} simply use
//     * a merge function that throws unconditionally, but you can easily write
//     * more flexible merge policies.  For example, if you have a stream
//     * of {@code Person}, and you want to produce a "phone book" mapping name to
//     * address, but it is possible that two persons have the same name, you can
//     * do as follows to gracefully deals with these collisions, and produce a
//     * {@code Map} mapping names to a concatenated list of addresses:
//            * <pre>{@code
//     *     Map<String, String> phoneBook
//     *         people.stream().collect(toMap(Person::getName,
//                *                                       Person::getAddress,
//                *                                       (s, a) -> s + ", " + a));
//     * }</pre>
    public static void main(String[] args) {

        List<Person> people = Person.supply_P();
//  对于重复的key的处理
        Map<String,String> phoneBook = people.stream()
                .collect(Collectors.toMap(Person::getName,
                        Person::getAddress,
                        (s,a) -> s + ",   " + a));

        phoneBook.forEach(
                (k,v) ->
                        System.out.println(k + "     "  + v)
        );


        System.out.println("---------------");

        // 也可以这样处理

        //
        //   这里我们假设有两个id相同Student,如果他们id相同,在转成Map的时候,取name大一个,小的将会被丢弃。

        System.out.println("----------------");


        Student s1 = new Student(1,"Mike",15);

        Student s2 = new Student(1,"Joshon",15);

        Student s3 = new Student(2,"Ted",15);

        Map<Integer,Student> map1 = Stream.of(s1,s2,s3)
                .collect(Collectors.toMap(
                        Student::getId,
                        Function.identity(),
                        BinaryOperator
                                .maxBy(Comparator.comparing(Student::getName))
                ));

        map1.forEach(
                (k,v)->
                        System.out.println(k+"---"+v)
        );
        /* 输出 */

//        1---Student{id=1, name='Mike', age=15, G_math=0, G_english=0, G_chinese=0}
//        2---Student{id=2, name='Ted', age=15, G_math=0, G_english=0, G_chinese=0}


    }
}

第三个

如果不想使用默认的HashMap 或者 ConcurrentHashMap , 第三个重载方法还可以使用自定义的Map对象(Map工厂)

使用

public class M3 {


    public static void main(String[] args) {

        List<Person> people = Person.supply_P();

        Map<String,String> phoneBook = people.stream()
                .collect(Collectors.toMap(Person::getName,
                        Person::getAddress,
                        (s,a) -> s + ",   " + a,
                        LinkedHashMap::new));

        phoneBook.forEach(
                (k,v) ->
                        System.out.println(k + "     "  + v)
        );
    }
}

toConcurrentMap

toConcurrentMap()是可以支持并行收集的

源码:

    public static <T, K, U>
    Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
                                                        Function<? super T, ? extends U> valueMapper) {
        return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new);
    }




    public static <T, K, U>
    Collector<T, ?, ConcurrentMap<K,U>>
    toConcurrentMap(Function<? super T, ? extends K> keyMapper,
                    Function<? super T, ? extends U> valueMapper,
                    BinaryOperator<U> mergeFunction) {
        return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new);
    }




    public static <T, K, U, M extends ConcurrentMap<K, U>>
    Collector<T, ?, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
                                       Function<? super T, ? extends U> valueMapper,
                                       BinaryOperator<U> mergeFunction,
                                       Supplier<M> mapSupplier) {
        BiConsumer<M, T> accumulator
                = (map, element) -> map.merge(keyMapper.apply(element),
                                              valueMapper.apply(element), mergeFunction);
        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID);
    }

具体使用可以参考toMap()

summarizingInt

收集流中Integer属性的统计值

源码:


// * Returns a {@code Collector} which applies an {@code int}-producing
// * mapping function to each input element, and returns summary statistics
// * for the resulting values.
 public static <T>
    Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
        return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
                IntSummaryStatistics::new,
                (r, t) -> r.accept(mapper.applyAsInt(t)),
                (l, r) -> { l.combine(r); return l; }, CH_ID);
    }

IntSummaryStatistics:


* A state object for collecting statistics such as count, min, max, sum, and
 * average.

主要用于统计整形数组中元素的最大值,最小值,平均值,个数,元素总和等等

使用

public class M1 {


    public static void main(String[] args) {

        List<Student> students = Student.supple_S();

        // 统计 每个同学的语文成绩
        IntSummaryStatistics intSummaryStatistics = students.stream()
                .collect(Collectors.summarizingInt(Student::getG_chinese));

        System.out.println("最高分  " + intSummaryStatistics.getMax());

        System.out.println("");
        System.out.println("最低分  " + intSummaryStatistics.getMin());

        System.out.println("");
        System.out.println("平均分  " + intSummaryStatistics.getAverage());

        System.out.println("");
        System.out.println("参加考试人数    " + intSummaryStatistics.getCount());

        System.out.println("");
        System.out.println("所有信息汇总  :");
        System.out.println(intSummaryStatistics.toString());



    }
}


summarizingLong

源码:


  public static <T>
    Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {
        return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>(
                LongSummaryStatistics::new,
                (r, t) -> r.accept(mapper.applyAsLong(t)),
                (l, r) -> { l.combine(r); return l; }, CH_ID);
    }

使用参考summarizingInt

summarizingDouble

源码:


 public static <T>
    Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {
        return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>(
                DoubleSummaryStatistics::new,
                (r, t) -> r.accept(mapper.applyAsDouble(t)),
                (l, r) -> { l.combine(r); return l; }, CH_ID);
    }

使用参考summarizingInt

summingInt

源码:


  public static <T> Collector<T, ?, Integer>
    summingInt(ToIntFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new int[1],
                (a, t) -> { a[0] += mapper.applyAsInt(t); },
                (a, b) -> { a[0] += b[0]; return a; },
                a -> a[0], CH_NOID);
    }

Collectors 类专门为汇总提供了一个工厂方法: Collectors.summingInt 。它可接受一个把对象映射为求和所需 int 的函数,并返回一个收集器;该收集器在传递给普通的 collect 方法后即执行我们需要的汇总操作

使用


public class M1 {


    public static void main(String[] args) {


        List<Student> students = Student.supple_S();


        // 统计学生年龄总和
        System.out.println(
                students.stream()
                .collect(Collectors.summingInt(Student::getAge))
        );

        System.out.println("--------------------------------------");


        // 统计英语成绩总分
        System.out.println(
                students.stream()
                .collect(Collectors.summingInt(Student::getG_english))
        );


    }
}


summingLong

源码:


  
  public static <T> Collector<T, ?, Long>
    summingLong(ToLongFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new long[1],
                (a, t) -> { a[0] += mapper.applyAsLong(t); },
                (a, b) -> { a[0] += b[0]; return a; },
                a -> a[0], CH_NOID);
    }

summingDouble

源码:


  //  * <p>The sum returned can vary depending upon the order in which
    //  * values are recorded, due to accumulated rounding error in
    //  * addition of values of differing magnitudes. Values sorted by increasing
    //  * absolute magnitude tend to yield more accurate results.  If any recorded
    //  * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
    //  * sum will be {@code NaN}.

 public static <T> Collector<T, ?, Double>
    summingDouble(ToDoubleFunction<? super T> mapper) {
        /*
         * In the arrays allocated for the collect operation, index 0
         * holds the high-order bits of the running sum, index 1 holds
         * the low-order bits of the sum computed via compensated
         * summation, and index 2 holds the simple sum used to compute
         * the proper result if the stream contains infinite values of
         * the same sign.
         */
        return new CollectorImpl<>(
                () -> new double[3],
                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
                            a[2] += mapper.applyAsDouble(t);},
                (a, b) -> { sumWithCompensation(a, b[0]);
                            a[2] += b[2];
                            return sumWithCompensation(a, b[1]); },
                a -> computeFinalSum(a),
                CH_NOID);
    }

averagingInt

取平均值

源码:

  public static <T> Collector<T, ?, Double>
    averagingInt(ToIntFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new long[2],
                (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
    }
使用
public class M1 {

    public static void main(String[] args) {

        List<Student> students = Student.supple_S();


        // 计算 学生 年龄 平均值
        System.out.println(
                students.stream()
                .collect(Collectors.averagingInt(Student::getAge))
        );


        System.out.println("---------------------------------");

        // 计算 语文成绩 平均分
        System.out.println(
                students.stream()
                .collect(Collectors.averagingInt(Student::getG_chinese))
        );


    }
}


averagingLong

源码:

 public static <T> Collector<T, ?, Double>
    averagingLong(ToLongFunction<? super T> mapper) {
        return new CollectorImpl<>(
                () -> new long[2],
                (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
    }

averagingDouble

源码:

   public static <T> Collector<T, ?, Double>
    averagingDouble(ToDoubleFunction<? super T> mapper) {
        /*
         * In the arrays allocated for the collect operation, index 0
         * holds the high-order bits of the running sum, index 1 holds
         * the low-order bits of the sum computed via compensated
         * summation, and index 2 holds the number of values seen.
         */
        return new CollectorImpl<>(
                () -> new double[4],
                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
                (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
                a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
                CH_NOID);
    }

minBy

源码:


//    * @implSpec
//      * This produces a result equivalent to:
//      * <pre>{@code
//      *     reducing(BinaryOperator.minBy(comparator))
//      * }</pre>
 public static <T> Collector<T, ?, Optional<T>>
    minBy(Comparator<? super T> comparator) {
        return reducing(BinaryOperator.minBy(comparator));
    }

minBy方法返回一个Collector收集器,它根据给定的Comparator比较器生成最小元素,描述为Optional

使用
public class M1 {

    public static void main(String[] args) {

        List<Student> students = Student.supple_S();

        System.out.println(
                students.stream()
                .collect(Collectors.minBy(Comparator.comparing(Student::getAge)))
        );

    }
}


maxBy

源码:


    // * @implSpec
    //  * This produces a result equivalent to:
    //  * <pre>{@code
    //  *     reducing(BinaryOperator.maxBy(comparator))
    //  * }</pre>
  public static <T> Collector<T, ?, Optional<T>>
    maxBy(Comparator<? super T> comparator) {
        return reducing(BinaryOperator.maxBy(comparator));
    }


使用


public class M1 {


    public static void main(String[] args) {

        List<Student> students = Student.supple_S();

        // 找出数学最高分的同学
        System.out.println(
                students.stream()
                .collect(Collectors.maxBy(Comparator.comparing(Student::getG_math)))
        );

        
    }
}


counting

源码:

//    * @implSpec
//      * This produces a result equivalent to:
//      * <pre>{@code
//      *     reducing(0L, e -> 1L, Long::sum)
//      * }</pre>
  public static <T> Collector<T, ?, Long>
    counting() {
        return reducing(0L, e -> 1L, Long::sum);
    }


counting方法返回一个Collector收集器接受T类型的元素,用于计算输入元素的数量。如果没有元素,则结果为0。

使用
public class M1 {


    public static void main(String[] args) {

        List<Student> students = Student.supple_S();

        // 统计有多少个学生

        System.out.println(
                students.stream()
                .collect(Collectors.counting())
        );

        System.out.println("-----------");

        // 统计 数学 80分以上的有多少人

        System.out.println(
                students.stream()
                .filter(student -> student.getG_math() > 80)
                .collect(Collectors.counting())
        );

    }
}


joining

源码:


   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);
    }


    // * @param delimiter the delimiter to be used between each element
    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
        return joining(delimiter, "", "");
    }




    //  * @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
    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);
    }





第一个

joining()方法返回一个Collector收集器,它按遇见顺序将输入元素连接成String。

使用

public class M1 {

    public static void main(String[] args) {

        List<String> strings = Create_Data.supply_Strings(5,6);

        System.out.println(strings);

        System.out.println("--------------------------------");

        String s1 = strings.stream()
                .collect(Collectors.joining());
        // 把字符串连接起来
        System.out.println(s1);

        /*
         * [uzkCKX, uzkCKXaBrgim, uzkCKXaBrgimheFUll, uzkCKXaBrgimheFUllSJvAml, uzkCKXaBrgimheFUllSJvAmlurqtBC]
         * --------------------------------
         * uzkCKXuzkCKXaBrgimuzkCKXaBrgimheFUlluzkCKXaBrgimheFUllSJvAmluzkCKXaBrgimheFUllSJvAmlurqtBC
         */
        
    }
}



第二个

joining(delimiter)方法返回一个Collector收集器,它以遇见顺序连接由指定分隔符分隔的输入元素

使用

public class M2 {

    public static void main(String[] args) {


        List<Person> people = Person.supply_P();

        // 把地址连接起来
        String s1 = people.stream()
                .map(Person::getAddress)
                .collect(Collectors.joining(","));

        System.out.println(s1);
        /*
        北京,北京,深圳,广州,上海,广州

         */

    }
}


第三个

joining(delimiter, prefix, suffix)方法返回一个Collector收集器,它以遇见顺序将由指定分隔符分隔的输入元素与指定的前缀和后缀连接起来

使用

public class M3 {

    public static void main(String[] args) {

        List<String> strings = Create_Data.supply_Strings(6,6);

        System.out.println(strings);

        String s1 = strings.stream()
                .collect(Collectors.joining("   ,   ","[","]"));

        System.out.println(s1);

        /*
        [NJevkE, NJevkEgPHHJo, NJevkEgPHHJoEsIdWH, NJevkEgPHHJoEsIdWHpREMIs, NJevkEgPHHJoEsIdWHpREMIskTavvX, NJevkEgPHHJoEsIdWHpREMIskTavvXltdiUr]
[NJevkE   ,   NJevkEgPHHJo   ,   NJevkEgPHHJoEsIdWH   ,   NJevkEgPHHJoEsIdWHpREMIs   ,   NJevkEgPHHJoEsIdWHpREMIskTavvX   ,   NJevkEgPHHJoEsIdWHpREMIskTavvXltdiUr]
         */
    }
}


mapping

源码:


    //  * Adapts a {@code Collector} accepting elements of type {@code U} to one
    //  * accepting elements of type {@code T} by applying a mapping function to
    //  * each input element before accumulation.
    //  *
    //  * @apiNote
    //  * The {@code mapping()} collectors are most useful when used in a
    //  * multi-level reduction, such as downstream of a {@code groupingBy} or
    //  * {@code partitioningBy}.  For example, given a stream of
    //  * {@code Person}, to accumulate the set of last names in each city:
    //  * <pre>{@code
    //  *     Map<City, Set<String>> lastNamesByCity
    //  *         = people.stream().collect(groupingBy(Person::getCity,
    //  *                                              mapping(Person::getLastName, toSet())));
    //  * }</pre>

    //    * @param <T> the type of the input elements
    //  * @param <U> type of elements accepted by downstream collector
    //  * @param <A> intermediate accumulation type of the downstream collector
    //  * @param <R> result type of collector
    //  * @param mapper a function to be applied to the input elements
    //  * @param downstream a collector which will accept mapped values
 public static <T, U, A, R>
    Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
                               Collector<? super U, A, R> downstream) {
        BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
        return new CollectorImpl<>(downstream.supplier(),
                                   (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
                                   downstream.combiner(), downstream.finisher(),
                                   downstream.characteristics());
    }


mapping方法通过在累积之前将映射函数应用于每个输入元素,将Collector收集器接受U类型的元素调整为一个接受T类型的元素

使用

public class M1 {


    public static void main(String[] args) {

        List<Employee> employees = Employee.supply_Ems();
        
        // 统计 每个部门下员工名字
        Map<String,List<String>> map1 = employees.stream()
                .collect(Collectors.groupingBy(
                        Employee::getPartment,
                        Collectors.mapping(Employee::getName,Collectors.toList())
                ));

        map1.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        财务部    [0号员工, 1号员工, 8号员工, 10号员工, 14号员工, 15号员工, 16号员工, 18号员工, 19号员工, 20号员工, 21号员工]
        技术部    [3号员工, 4号员工, 29号员工]
        设计部    [7号员工, 25号员工, 27号员工]
        市场部    [5号员工, 11号员工]
        公关部    [12号员工, 13号员工, 22号员工, 23号员工, 24号员工, 26号员工, 28号员工]
        管理部    [2号员工, 6号员工, 9号员工, 17号员工]
         */
    }
}

reducing

源码:


    // * <p>For example, given a stream of {@code Person}, to calculate tallest
    //  * person in each city:
    //  * <pre>{@code
    //  *     Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
    //  *     Map<City, Person> tallestByCity
    //  *         = people.stream().collect(groupingBy(Person::getCity, reducing(BinaryOperator.maxBy(byHeight))));
    //  * }</pre>
    //  *
    //  * @param <T> element type for the input and output of the reduction
    //  * @param op a {@code BinaryOperator<T>} used to reduce the input elements

 public static <T> Collector<T, ?, Optional<T>>
    reducing(BinaryOperator<T> op) {
       // .......
    }


//    * <p>For example, given a stream of {@code Person}, to calculate the longest
//      * last name of residents in each city:
//      * <pre>{@code
//      *     Comparator<String> byLength = Comparator.comparing(String::length);
//      *     Map<City, String> longestLastNameByCity
//      *         = people.stream().collect(groupingBy(Person::getCity,
//      *                                              reducing(Person::getLastName, BinaryOperator.maxBy(byLength))));
//      * }</pre>
//      *
//      * @param <T> the type of the input elements
//      * @param <U> the type of the mapped values
//      * @param identity the identity value for the reduction (also, the value
//      *                 that is returned when there are no input elements)
//      * @param mapper a mapping function to apply to each input value
//      * @param op a {@code BinaryOperator<U>} used to reduce the mapped values
  public static <T, U>
    Collector<T, ?, U> reducing(U identity,
                                Function<? super T, ? extends U> mapper,
                                BinaryOperator<U> op) {
        return new CollectorImpl<>(
                boxSupplier(identity),
                (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
                a -> a[0], CH_NOID);
    }


使用

public class M1 {


    public static void main(String[] args) {

        List<Employee> employees = Employee.supply_Ems();

        Comparator<Employee> bySalary = Comparator.comparing(Employee::getSalary);

        // 找出 每个部门工资最高的员工
        Map<String, Optional<Employee>> map1 = employees.stream()
                .collect(Collectors.groupingBy(
                        Employee::getPartment,
                        Collectors.reducing(BinaryOperator.maxBy(bySalary))
                ));

        map1.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        财务部    Optional[Employee{name='22号员工', age=30, partment='财务部', salary=8226}]
        技术部    Optional[Employee{name='27号员工', age=41, partment='技术部', salary=7898}]
        设计部    Optional[Employee{name='12号员工', age=25, partment='设计部', salary=5544}]
        市场部    Optional[Employee{name='11号员工', age=39, partment='市场部', salary=8179}]
        公关部    Optional[Employee{name='25号员工', age=25, partment='公关部', salary=4269}]
        管理部    Optional[Employee{name='10号员工', age=23, partment='管理部', salary=7286}]
         */

    }
}


groupingBy

分组

源码:



// * Returns a {@code Collector} implementing a "group by" operation on
// * input elements of type {@code T}, grouping elements according to a
// * classification function, and returning the results in a {@code Map}.


// * @param <T> the type of the input elements
// * @param <K> the type of the keys
// * @param classifier the classifier function mapping input elements to keys

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


// * <p>The classification function maps elements to some key type {@code K}.
// * The downstream collector operates on elements of type {@code T} and
// * produces a result of type {@code D}. The resulting collector produces a
// * {@code Map<K, D>}.
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);
    }

// * <p>For example, to compute the set of last names of people in each city,
// * where the city names are sorted:
// * <pre>{@code
// *     Map<City, Set<String>> namesByCity
// *         = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
// *                                              mapping(Person::getLastName, toSet())));
// * }</pre>
public static <T, K, D, A, M extends Map<K, D>>
    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? super T, A, D> downstream) {
        

        //..........
    }




第一个

使用
public class M1 {


    public static void main(String[] args) {


        List<Student> students = Student.supple_S();

        Map<Integer,List<Student>> map =

                students.stream()
                        .collect(Collectors.groupingBy(Student::getG_chinese));


//        map.forEach(
//                (k,v)->
//                        System.out.println(k + "    " + v)
//        );

        Function<Student,Boolean> function = student ->
        {
            if (student.getG_math() > 50) {
                return true;
            } else return false;
        };

        // 根据 数学成绩是否大于50 分组
        Map<Boolean,List<Student>> map2 =

                students.stream()
                .collect(Collectors.groupingBy(function));

        map2.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        false    [Student{id=0, name='0号学生', age=11, G_math=19, G_english=90, G_chinese=18},
         Student{id=2, name='2号学生', age=18, G_math=24, G_english=34, G_chinese=90},
         Student{id=7, name='7号学生', age=4, G_math=35, G_english=92, G_chinese=31},
         Student{id=10, name='10号学生', age=6, G_math=6, G_english=43, G_chinese=91},
         Student{id=18, name='18号学生', age=1, G_math=4, G_english=3, G_chinese=22}]
        true    [Student{id=1, name='1号学生', age=8, G_math=80, G_english=78, G_chinese=9},
        Student{id=3, name='3号学生', age=5, G_math=71, G_english=76, G_chinese=48},
        Student{id=4, name='4号学生', age=15, G_math=96, G_english=91, G_chinese=15},
        Student{id=5, name='5号学生', age=22, G_math=87, G_english=27, G_chinese=47}, Student{id=6, name='6号学生', age=20, G_math=69, G_english=54, G_chinese=75},
        Student{id=8, name='8号学生', age=24, G_math=68, G_english=88, G_chinese=92}, Student{id=9, name='9号学生', age=23, G_math=85, G_english=46, G_chinese=36},
        Student{id=11, name='11号学生', age=14, G_math=51, G_english=31, G_chinese=68}, Student{id=12, name='12号学生', age=19, G_math=64, G_english=6, G_chinese=70},
        Student{id=13, name='13号学生', age=15, G_math=99, G_english=54, G_chinese=84}, Student{id=14, name='14号学生', age=3, G_math=61, G_english=28, G_chinese=51},
        Student{id=15, name='15号学生', age=17, G_math=88, G_english=79, G_chinese=71}, Student{id=16, name='16号学生', age=8, G_math=84, G_english=2, G_chinese=60},
         Student{id=17, name='17号学生', age=5, G_math=68, G_english=2, G_chinese=68}, Student{id=19, name='19号学生', age=5, G_math=54, G_english=40, G_chinese=41}]
         */


        /**********************************/

        System.out.println("-------------------");

        List<Person> people = Person.supply_P();

        Function<Person,String> function1 = person ->
        {
            if (person.getAddress().equals("北京")){
                return "北京人";
            } else return "外地人";
        };

        Map<String,List<Person>> map3 =

                people.stream()
                .collect(Collectors.groupingBy(function1));

        map3.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );
        
        /*
        北京人    [Person{name='A', address='北京'}]
        外地人    [Person{name='A', address='深圳'}, Person{name='A', address='上海'}, Person{name='C', address='南京'}, Person{name='C', address='广州'}, Person{name='C', address='南京'}]
         */
        

    }
}

第二个

groupingBy(Function, Collector)方法返回一个Collector收集器,对T类型的输入元素执行级联"group by"操作,根据分类函数对元素进行分组,然后使用指定的下游Collector收集器对与给定键关联的值执行缩减操作

使用

public class M2 {

    public static void main(String[] args) {

        List<Person> people = Person.supply_P();


        // 按照 地址 进行分组
        Map<String,List<String>> map = people.stream()
                .collect(Collectors.groupingBy(
                        Person::getAddress,
                        Collectors.mapping(
                                Person::getName,
                                Collectors.toList()
                        )
                ));


        map.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        广州    [C]
        上海    [A, C]
        深圳    [C]
        南京    [A, A]
         */

        // 返回的集合类型可以根据需要而定

        System.out.println("------------------");

        Map<String, Set<String>> map2 = people.stream()
                .collect(Collectors.groupingBy(
                        Person::getAddress,
                        Collectors.mapping(
                                Person::getName,
                                Collectors.toSet()
                        )
                ));

        map2.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        广州    [A, C]
        南京    [C]
        北京    [A, C]
         */

        System.out.println("------------------");

        List<Student> students = Student.supple_S();

        Function<Student,String> function = student ->
        {
            if (student.getG_english() > 60){
                return "及格人数";
            } else {
                return "不及格人数";
            }
        };

        // 统计 及格 不及格人数
        Map<String,Long> map3 = students.stream()
                .collect(Collectors.groupingBy(
                        function,
                        Collectors.counting()
                ));



        map3.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        不及格人数    14
        及格人数    6
         */
        
    }
}

第三个

groupingBy(Function, Supplier, Collector)方法返回一个Collector收集器,对T类型的输入元素执行级联"group by"操作,根据分类函数对元素进行分组,然后使用指定的下游Collector收集器对与给定键关联的值执行缩减操作。收集器生成的Map是使用提供的工厂函数创建的

使用
public class Employee {

    private static Random random = new Random();

    private static String[] parts =
            {
                    "市场部",
                    "管理部",
                    "公关部",
                    "技术部",
                    "设计部",
                    "财务部"

            };


    private String name;

    private int age;

    private String partment;

    private int salary;

    public Employee(String name, int age, String partment, int salary) {
        this.name = name;
        this.age = age;
        this.partment = partment;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPartment() {
        return partment;
    }

    public void setPartment(String partment) {
        this.partment = partment;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    //获取[m,n]之间的随机数(0<=m<=n)
    public static int getRandomBetweenNumbers(int m,int n){
        return (int)(m + Math.random() * (n - m + 1));
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", partment='" + partment + '\'' +
                ", salary=" + salary +
                '}';
    }

    public static List<Employee> supply_Ems(){
        List<Employee> employees = new ArrayList<>();

        for (int i = 0; i < 30; i++) {

            employees.add(new Employee(i+"号员工",getRandomBetweenNumbers(23,50),parts[random.nextInt(parts.length)],getRandomBetweenNumbers(1500,9000)));
        }
        return employees;
    }

    public static void main(String[] args) {

        for (Employee e : supply_Ems()){
            System.out.println(e);
        }

    }


}



public class M3 {

    public static void main(String[] args) {

        List<Employee> employees = Employee.supply_Ems();

        // 计算每个部门各有多少人

        Map<String,Long> map1 = employees.stream()
                .collect(Collectors.groupingBy(
                        Employee::getPartment,
                        Collectors.counting()
                ));

        map1.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        财务部    3
        技术部    5
        设计部    6
        市场部    8
        管理部    1
        公关部    7
         */

        System.out.println("-----------------------------------");

        /*  多层分组   */

        // 按照工资进行划分评价
        Function<Employee,String> f1 = employee ->
        {
            if (employee.getSalary() > 5000) {
                return "工资不错";
            } else {
                return "工资一般";
            }
        };

        Map<String,Map<String,List<Employee>>> mapMap = employees.stream()
                .collect(
                        Collectors.groupingBy(
                                Employee::getPartment,
                                Collectors.groupingBy(
                                     f1
                                )
                        )
                );

        mapMap.forEach(
                (k,v)->
                        System.out.println(k+v)
        );
        /*
        财务部    {工资一般=[Employee{name='5号员工', age=31, partment='财务部', salary=2733}, Employee{name='6号员工', age=42, partment='财务部', salary=4051}, Employee{name='14号员工', age=33, partment='财务部', salary=2347}, Employee{name='23号员工', age=44, partment='财务部', salary=2823}], 工资不错=[Employee{name='0号员工', age=40, partment='财务部', salary=6892}, Employee{name='12号员工', age=45, partment='财务部', salary=8296}, Employee{name='16号员工', age=27, partment='财务部', salary=6659}]}
        技术部    {工资不错=[Employee{name='7号员工', age=45, partment='技术部', salary=7158}, Employee{name='20号员工', age=24, partment='技术部', salary=7582}, Employee{name='29号员工', age=41, partment='技术部', salary=8372}], 工资一般=[Employee{name='1号员工', age=24, partment='技术部', salary=3436}, Employee{name='17号员工', age=39, partment='技术部', salary=2145}, Employee{name='27号员工', age=29, partment='技术部', salary=1580}]}
        设计部    {工资不错=[Employee{name='25号员工', age=38, partment='设计部', salary=8699}, Employee{name='26号员工', age=32, partment='设计部', salary=8503}], 工资一般=[Employee{name='2号员工', age=32, partment='设计部', salary=2732}, Employee{name='3号员工', age=28, partment='设计部', salary=3955}, Employee{name='18号员工', age=35, partment='设计部', salary=1583}]}
        市场部    {工资不错=[Employee{name='15号员工', age=49, partment='市场部', salary=6133}], 工资一般=[Employee{name='11号员工', age=29, partment='市场部', salary=1973}, Employee{name='21号员工', age=26, partment='市场部', salary=4726}]}
        管理部    {工资一般=[Employee{name='24号员工', age=39, partment='管理部', salary=3012}], 工资不错=[Employee{name='10号员工', age=32, partment='管理部', salary=8683}, Employee{name='19号员工', age=50, partment='管理部', salary=5210}]}
        公关部    {工资一般=[Employee{name='9号员工', age=37, partment='公关部', salary=3248}], 工资不错=[Employee{name='4号员工', age=50, partment='公关部', salary=6770}, Employee{name='8号员工', age=42, partment='公关部', salary=8611}, Employee{name='13号员工', age=39, partment='公关部', salary=7496}, Employee{name='22号员工', age=48, partment='公关部', salary=8740}, Employee{name='28号员工', age=24, partment='公关部', salary=5860}]}
         */

        System.out.println("-----------------------------------");


        // 统计每个部门 工资 高于8000的人数各有多少
        Map<String,Long> map2 = employees.stream()
                .filter(employee -> employee.getSalary() > 8000)
                .collect(
                        Collectors.groupingBy(
                                Employee::getPartment,
                                Collectors.counting()
                        )
                );

        map2.forEach(
                (k,v)->
                        System.out.println(k+"  ---  "+v)
        );


    }
}


groupingByConcurrent

支持并发操作

源码:




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



public static <T, K, A, D>
    Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                                              Collector<? super T, A, D> downstream) {
        return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
    }


public static <T, K, A, D, M extends ConcurrentMap<K, D>>
    Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                            Supplier<M> mapFactory,
                                            Collector<? super T, A, D> downstream) {
      //....................
    }

partitioningBy

源码:


// * Returns a {@code Collector} which partitions the input elements according
// * to a {@code Predicate}, and organizes them into a
// * {@code Map<Boolean, List<T>>}.
public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
        return partitioningBy(predicate, toList());

}


public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
                                Collector<? super T, A, D> downstream) {

                                    //..............
      
}

分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数,它称分区函数。分区函数返回一个布尔值,这意味着得到的分组 Map 的键类型是 Boolean ,于是它最多可以分为两组—— true 是一组, false 是一组

使用

public class M1 {

    public static void main(String[] args) {

        List<Person> people = Person.supply_P();

        // 是否为北京来的
        Map<Boolean,List<Person>> map1 = people.stream()
                .collect(Collectors.partitioningBy(person ->
                        person.getAddress().equals("北京")));

        map1.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );

        /*
        false    [Person{name='A', address='深圳'}, Person{name='A', address='深圳'}, Person{name='A', address='上海'}, Person{name='C', address='深圳'}]
        true    [Person{name='C', address='北京'}, Person{name='C', address='北京'}]
         */

        System.out.println("--------------------------");
        
        // 统计英语成绩高于80分的学生
        
        List<Student> students = Student.supple_S();

        Map<Boolean,List<Student>> map2 = students.stream()
                .collect(Collectors.partitioningBy(student ->
                        student.getG_english() > 80));

        map2.forEach(
                (k,v)->
                        System.out.println(k + "    " + v)
        );
        
        /*
        false    [Student{id=0, name='0号学生', age=1, G_math=5, G_english=25, G_chinese=45}, Student{id=1, name='1号学生', age=18, G_math=8, G_english=80, G_chinese=0}, Student{id=2, name='2号学生', age=0, G_math=82, G_english=53, G_chinese=46}, Student{id=3, name='3号学生', age=16, G_math=87, G_english=52, G_chinese=60}, Student{id=4, name='4号学生', age=16, G_math=23, G_english=21, G_chinese=88}, Student{id=5, name='5号学生', age=13, G_math=82, G_english=19, G_chinese=3}, Student{id=6, name='6号学生', age=3, G_math=55, G_english=18, G_chinese=12}, Student{id=7, name='7号学生', age=2, G_math=65, G_english=56, G_chinese=20}, Student{id=8, name='8号学生', age=0, G_math=25, G_english=36, G_chinese=98}, Student{id=10, name='10号学生', age=5, G_math=11, G_english=6, G_chinese=84}, Student{id=12, name='12号学生', age=13, G_math=32, G_english=3, G_chinese=11}, Student{id=13, name='13号学生', age=22, G_math=71, G_english=11, G_chinese=44}, Student{id=15, name='15号学生', age=3, G_math=77, G_english=39, G_chinese=51}, Student{id=18, name='18号学生', age=12, G_math=24, G_english=55, G_chinese=84}]
        true    [Student{id=9, name='9号学生', age=5, G_math=60, G_english=99, G_chinese=21}, Student{id=11, name='11号学生', age=12, G_math=69, G_english=94, G_chinese=14}, Student{id=14, name='14号学生', age=10, G_math=88, G_english=90, G_chinese=11}, Student{id=16, name='16号学生', age=23, G_math=85, G_english=83, G_chinese=32}, Student{id=17, name='17号学生', age=15, G_math=67, G_english=98, G_chinese=82}, Student{id=19, name='19号学生', age=11, G_math=21, G_english=92, G_chinese=68}]
         */


    }
}


发布了229 篇原创文章 · 获赞 62 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/Coder_py/article/details/104179461
今日推荐