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 elementspublic 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 insertedpublic 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;}@Overridepublic 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;}@Overridepublic 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 elementpublic 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 resultpublic 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 valuespublic 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 elementspublic 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 valuespublic 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 keyspublic 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));}@Overridepublic 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}]*/}
}
Java-8-Collectors类相关推荐
- Java集合Stream类
Java集合Stream类 ----按条件对集合进行过滤filter public class Test {public static void main(String[] args) {List&l ...
- 【Java 8 新特性】Java 8 Collectors示例
Java 8 Collectors示例 Collectors.averagingDouble Collectors.averagingInt Collectors.averagingLong Coll ...
- java string改变的影响_为什么Java的string类要设成immutable(不可变的)
最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类 ...
- java中properties作用,java中Properties类的使用
java中Properties类的使用 在java.util 包下面有一个类 Properties,该类主要用于读取以项目的配置文件(以.properties结尾的文件和xml文件). Propert ...
- Java程序员从笨鸟到菜鸟之(五)java开发常用类(包装,数字处理集合等)(下)...
本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 写在前面:由于前天项目老师建设局的项目快到验收阶段,所以,前天晚上通宵,昨天睡了大半天, ...
- 【转】深入研究java.lang.Class类
深入研究java.lang.Class类 Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识.这项信息纪录了每个对象所属的类.虚拟机通常使用运行时类 ...
- java生成缩略图类源码
把做工程过程比较好的一些内容备份一下,如下内容段是关于 java生成缩略图类的内容. package com.whatycms.common.util; import java.awt.image.B ...
- Java基础-Date类常用方法介绍
Java基础-Date类常用方法介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.毫秒值概念 我们在查阅Date类的API文档时,会发现这样的一句话:"The cl ...
- spark需要maven管理吗_Spark-Maven全新安装:如何同时编译Java和Scala类
我有一个Spark项目,其中同时包含.scala和.java文件.我正在尝试通过Maven构建来编译这两种类型的类.但是,当我运行" mvn clean install"时,它只会 ...
- java内省操作类的属性
java内省操作类的属性 1.取得指定类的属性的方法 2.操作指定类的属性的方法 3.得到指定类的属性数据类型的方法 package com.ma.introspector;import java.b ...
最新文章
- IE调试网页之一:F12 开发人员工具简介
- parents()和parent()
- eos和以太坊有什么关系_以太坊 2.0是什么?
- linux安装pgsql源码包解压,在Linux(centos)中使用源码安装pgRouting
- SpringBoot(十四)_springboot使用内置定时任务Scheduled的使用(一)
- rest-framework解析器,url控制,分页,响应器,渲染器,版本控制
- 【算法学习】高斯模糊算法
- 【ATSC】美国地面数字电视广播从ATSC 1.0向ATSC 3.0标准的过渡
- EPLAN电气设计入门学习笔记
- Guava base -- Joiner
- 泰坦尼克号生命值预测
- Premiere Pro CC 2018 经典教程
- 分布式服务协调---幂等(Idempotent)机制
- 将打开网页以网页 仅HTML,网页保存的不同方法
- 珞石(ROKAE)机械手简单的编程
- compose安装单个扩展_将自动化测试扩展到单个项目之外
- Android进程间通信 - 几种方式的对比总结
- java编程——案例1:模拟购物车
- Robust Visual Tracking with a Freely-moving Event Camera
- 赋能数字经济发展的数字政府建设:内在逻辑与创新路径