深入Comparator&Collector

从源码深入Comparator

Comparator从Java1.2就出来了,但是在1.8的时候,又添加了大量的默认方法.

  1. compare()
  2. equals()
  3. reversed() //倒序
  4. thenComparing(Comparator<? super T> other) //然后,再去比较.
  5. thenComparing( Function<? super T, ? extends U> keyExtractor,
  6. Comparator<? super U> keyComparator) //先通过第一个比较器,再执行第二个比较器...串联
  7. thenComparing()
  8. thenComparingInt()
  9. thenComparingLong()
  10. thenComparingDouble()
  11. reverseOrder()
  12. naturalOrder()
  13. nullsFirst()
  14. nullsLast()
  15. comparing () //静态方法
  16. comparing()
  17. comparingInt()
  18. comparingLong()
  19. comparingDouble()

从Demo代码看Comparator

  1. package com.dawa.jdk8.stream2;
  2. import java.util.Arrays;
  3. import java.util.Collections;
  4. import java.util.Comparator;
  5. import java.util.List;
  6. //关于比较器comparator,案例详解.
  7. public class MyComparator {
  8. public static void main(String[] args) {
  9. List<String> list = Arrays.asList("hello", "world", "welcome", "nihao");
  10. //按照字母排序
  11. Collections.sort(list);
  12. System.out.println(list);
  13. //按照字符串的长度.
  14. Collections.sort(list, (item1, item2) -> item1.length() - item2.length());
  15. System.out.println(list);
  16. //按照字符串的长度降序排序.
  17. Collections.sort(list, (item1, item2) -> item2.length() - item1.length());
  18. //使用方法引用
  19. //长度排序
  20. Collections.sort(list, Comparator.comparingInt(String::length));
  21. System.out.println(list);
  22. //长度倒叙排序
  23. Collections.sort(list, Comparator.comparingInt(String::length).reversed());
  24. System.out.println(list);
  25. //使用lambda表达式实现上述两个方法
  26. // Collections.sort(list,Comparator.comparingInt(item->item.length()).reversed());
  27. //这里,reversed()方法,参数要的是Object类型.
  28. //参数的类型推断.
  29. Collections.sort(list,Comparator.comparingInt((String item)->item.length()).reversed());
  30. //这样写就行了.
  31. //问题:之前为什么会成功? 因为是从Stream<T> 类型开始推断的,可以获取到原属性的元素.
  32. //问题:为什么上述的类型推断失败了/? 看sort方法的 Comparator类的泛型<T>,T是传入参数的泛型- <? super T>.
  33. // String上的类型.你没指定,编译器也没办法帮你指定.
  34. // public static <T> void sort(List<T> list, Comparator<? super T> c) {
  35. // list.sort(c);
  36. // }
  37. //如: Collections.sort(list,Comparator.comparingInt((Boolean item)->1).reversed());
  38. //这样不会被兼容.因为Boolean 不是 String的上类型.
  39. //如: Collections.sort(list,Comparator.comparingInt((Object item)->1).reversed());
  40. //这样就是可以的.
  41. //如: Collections.sort(list,Comparator.comparingInt(item->item.length());
  42. //这样也是可以的.
  43. }
  44. }
  1. @SuppressWarnings({"unchecked", "rawtypes"})
  2. public static <T> void sort(List<T> list, Comparator<? super T> c) {
  3. list.sort(c);
  4. }

关于: <? super T> 泛型的使用.需要注意.

语义更宽泛,但是从实际结果类型,实际就是T类型本身.这个需要仔细思考一下.

Comparator比较器的串联使用

  1. //通过两层比较,1:排序(升序) ,2:字母顺序排序. 使用thenComparing()
  2. Collections.sort(list,Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER));

thenComparing()方法源码如下

  1. /**
  2. * Returns a lexicographic-order comparator with another comparator.
  3. * If this {@code Comparator} considers two elements equal, i.e.
  4. * {@code compare(a, b) == 0}, {@code other} is used to determine the order.
  5. *
  6. * <p>The returned comparator is serializable if the specified comparator
  7. * is also serializable.
  8. *
  9. * @apiNote
  10. * For example, to sort a collection of {@code String} based on the length
  11. * and then case-insensitive natural ordering, the comparator can be
  12. * composed using following code,
  13. *
  14. 不区分大小写,的实现. 技术上述案例.
  15. * <pre>{@code
  16. * Comparator<String> cmp = Comparator.comparingInt(String::length)
  17. * .thenComparing(String.CASE_INSENSITIVE_ORDER);
  18. * }</pre>
  19. *
  20. * @param other the other comparator to be used when this comparator
  21. * compares two objects that are equal.
  22. * @return a lexicographic-order comparator composed of this and then the
  23. * other comparator
  24. * @throws NullPointerException if the argument is null.
  25. * @since 1.8
  26. */
  27. default Comparator<T> thenComparing(Comparator<? super T> other) {
  28. Objects.requireNonNull(other);
  29. return (Comparator<T> & Serializable) (c1, c2) -> {
  30. int res = compare(c1, c2);
  31. return (res != 0) ? res : other.compare(c1, c2);
  32. };
  33. }

前面比较器的结果等于0,这个thenComparing()才会被调用. 就如三个长度相同的那三个数,才会被二次排序.

也就是说如果第一个比较器,能够排序,就用第一个,第一个排序不成再用第二个.

另一种实现

  1. Collections.
  2. sort(list,Comparator.comparingInt(String::length).
  3. thenComparing((item1,item2)->item1.toLowerCase().compareTo(item2)));

另一种实现

  1. Collections.sort(list,Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toUpperCase)));

另一种实现

  1. Collections.sort(list,Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase,Comparator.reverseOrder())));

上述几个案例,主要就是对于 thenComparing()方法的不同使用实现.

那么,下面这个方法的输出结果是什么?

  1. Collections.sort(list,Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase,Comparator.reverseOrder())));

再次重复一下:前面比较器的结果等于0,这个thenComparing()才会被调用. 就如三个长度相同的那三个数,才会被二次排序.也就是说如果第一个比较器,能够排序,就用第一个,第一个排序不成再用第二个.

多级排序

  1. Collections.sort(list,Comparator.comparingInt(String::length).reversed()
  2. .thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder()))
  3. .thenComparing(Comparator.reverseOrder()));

JDK1.8之前,Collections里面提供的方法是很少的,从JDK1.8之后,新增了大量的实现方法和具体的特化的实现.

避免了装箱和拆箱操作.这也可能会影响性能.


自定义Collector实现类

实现Collector接口

  1. public interface Collector<T, A, R> {
  2. Supplier<A> supplier();
  3. BiConsumer<A, T> accumulator();
  4. BinaryOperator<A> combiner();
  5. Function<A, R> finisher();
  6. Set<Characteristics> characteristics();
  7. public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
  8. BiConsumer<R, T> accumulator,
  9. BinaryOperator<R> combiner,
  10. Characteristics... characteristics) {
  11. Objects.requireNonNull(supplier);
  12. Objects.requireNonNull(accumulator);
  13. Objects.requireNonNull(combiner);
  14. Objects.requireNonNull(characteristics);
  15. Set<Characteristics> cs = (characteristics.length == 0)
  16. ? Collectors.CH_ID
  17. : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
  18. characteristics));
  19. return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
  20. }
  21. public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
  22. BiConsumer<A, T> accumulator,
  23. BinaryOperator<A> combiner,
  24. Function<A, R> finisher,
  25. Characteristics... characteristics) {
  26. Objects.requireNonNull(supplier);
  27. Objects.requireNonNull(accumulator);
  28. Objects.requireNonNull(combiner);
  29. Objects.requireNonNull(finisher);
  30. Objects.requireNonNull(characteristics);
  31. Set<Characteristics> cs = Collectors.CH_NOID;
  32. if (characteristics.length > 0) {
  33. cs = EnumSet.noneOf(Characteristics.class);
  34. Collections.addAll(cs, characteristics);
  35. cs = Collections.unmodifiableSet(cs);
  36. }
  37. return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
  38. }
  39. Characteristics {
  40. CONCURRENT,
  41. UNORDERED,
  42. IDENTITY_FINISH
  43. }
  44. }

自定义的收集器

  1. package com.dawa.jdk8.stream2;
  2. import java.util.*;
  3. import java.util.function.BiConsumer;
  4. import java.util.function.BinaryOperator;
  5. import java.util.function.Function;
  6. import java.util.function.Supplier;
  7. import java.util.stream.Collector;
  8. import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH;
  9. public class MySetCollector<T> implements Collector<T,Set<T>,Set<T>> {
  10. @Override
  11. public Supplier<Set<T>> supplier() {
  12. System.out.println("supplier invoked");
  13. return HashSet<T>::new;// 返回一个HasHSet容器.
  14. }
  15. @Override
  16. public BiConsumer<Set<T>, T> accumulator() {
  17. System.out.println("accumalator invoked");//累加器
  18. return Set<T>::add;
  19. // return HashSet<T>::add; //不行,没有静态方法支持. 应该是 Supplier返回值的父类接口. 不能使用具体类型的set.
  20. }
  21. @Override
  22. public BinaryOperator<Set<T>> combiner() {
  23. System.out.println("combiner invoked");//并行流的时候,合并中间结果
  24. return (set1,set2)->{
  25. set1.addAll(set2);return set1;
  26. };
  27. }
  28. @Override
  29. public Function<Set<T>, Set<T>> finisher() {//合并结果类型.结果容器
  30. System.out.println("finisher invoked");
  31. // return ts -> ts;
  32. return Function.identity(); //底层是一样的. 同一性.
  33. }
  34. @Override
  35. public Set<Characteristics> characteristics() {
  36. System.out.println("charcteristics invoked ");
  37. return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH));
  38. }
  39. public static void main(String[] args) {
  40. List<String> list = Arrays.asList("hello", "world", "welcome");
  41. Set<String> collect = list.stream().collect(new MySetCollector<>());
  42. System.out.println(collect);
  43. }
  44. }

从源码深入Collector

第一步:代码中调用collect()

  1. public static void main(String[] args) {
  2. List<String> list = Arrays.asList("hello", "world", "welcome");
  3. Set<String> collect = list.stream().collect(new MySetCollector<>());
  4. System.out.println(collect);
  5. }

第二步:collect()方法的实现类

  1. @Override
  2. @SuppressWarnings("unchecked")
  3. public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
  4. A container;
  5. if (isParallel()
  6. && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
  7. && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
  8. container = collector.supplier().get();
  9. BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
  10. forEach(u -> accumulator.accept(container, u));
  11. }
  12. else {
  13. container = evaluate(ReduceOps.makeRef(collector));
  14. }
  15. return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
  16. ? (R) container
  17. : collector.finisher().apply(container);
  18. }

IDENTITY_FINISH的字段特别重要,在这里使用

第三步: makeRef(), 逐步调用者三个函数式接口对象

  1. public static <T, I> TerminalOp<T, I>
  2. makeRef(Collector<? super T, I, ?> collector) {
  3. Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
  4. BiConsumer<I, ? super T> accumulator = collector.accumulator();
  5. BinaryOperator<I> combiner = collector.combiner();
  6. class ReducingSink extends Box<I>
  7. implements AccumulatingSink<T, I, ReducingSink> {
  8. @Override
  9. public void begin(long size) {
  10. state = supplier.get();
  11. }
  12. @Override
  13. public void accept(T t) {
  14. accumulator.accept(state, t);
  15. }
  16. @Override
  17. public void combine(ReducingSink other) {
  18. state = combiner.apply(state, other.state);
  19. }
  20. }
  21. return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
  22. @Override
  23. public ReducingSink makeSink() {
  24. return new ReducingSink();
  25. }
  26. @Override
  27. public int getOpFlags() {
  28. return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
  29. ? StreamOpFlag.NOT_ORDERED
  30. : 0;
  31. }
  32. };
  33. }

Collector的一些"坑"

使用这个案例去理解运作过程.

把一个set集合进行收集,我们对结果做一个增强.(原来是直接放在set当中了.)我们现在放在Map当中.

声明一个Collector类,要求.

  1. 输入:Set
  2. 输出:Map<String,String>

示例输入:["hello","world","hello world"]

示例输出:[{hello,hello},{world,world},{hello world,hello world}

泛型:<T,T,T>

彻底理解Characteristics.IDENTITY_FINISH属性

  1. package com.dawa.jdk8.stream2;
  2. import java.util.*;
  3. import java.util.function.BiConsumer;
  4. import java.util.function.BinaryOperator;
  5. import java.util.function.Function;
  6. import java.util.function.Supplier;
  7. import java.util.stream.Collector;
  8. public class MySetCollector2<T> implements Collector<T, Set<T>, Map<T,T>> {
  9. @Override
  10. public Supplier<Set<T>> supplier() {
  11. System.out.println("supplier invoked");
  12. return HashSet<T>::new;
  13. }
  14. @Override
  15. public BiConsumer<Set<T>, T> accumulator() {
  16. System.out.println("accumulator invoked");
  17. return Set::add;
  18. }
  19. @Override
  20. public BinaryOperator<Set<T>> combiner() {
  21. System.out.println("combiner invoked");
  22. return (set1, set2) -> {
  23. set1.addAll(set2);
  24. return set1;
  25. };
  26. }
  27. @Override
  28. public Function<Set<T>, Map<T, T>> finisher() { //这里一定会被调用.因为结果类型和最终类型不同
  29. //示例输入:["hello","world","hello world"]
  30. //示例输出:[{hello,hello},{world,world},{hello world,hello world}
  31. System.out.println("finisher invoked");
  32. return set ->{
  33. Map<T, T> map = new HashMap<>();
  34. set.stream().forEach(item -> map.put(item, item));
  35. return map;
  36. };
  37. }
  38. @Override
  39. public Set<Characteristics> characteristics() {
  40. System.out.println("characteristics invoked");
  41. return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));
  42. }
  43. public static void main(String[] args) {
  44. List<String> list = Arrays.asList("hello", "world", "hello", "welocome", "a", "b", "c", "d", "e");
  45. HashSet<String> set = new HashSet<>(list);
  46. System.out.println("set:"+list);
  47. Map<String, String> collect = set.stream().collect(new MySetCollector2<>());
  48. System.out.println(collect);
  49. }
  50. }

如果多一个参数:

  1. return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.IDENTITY_FINISH));

则会出现类型转换异常.

  1. /**
  2. * Indicates that the finisher function is the identity function and
  3. * can be elided. If set, it must be the case that an unchecked cast
  4. * from A to R will succeed.
  5. */
  6. IDENTITY_FINISH

如果定义这个属性,则代表 indentity和 finish 是同一个类型的,要执行强制类型转换.所以会出现上述异常.

收集器是什么特性的,都是由这个Characteristics类来由你定义的.

所以你必须要理解你写的程序的类型.才能正确的使用这个枚举定义类.

彻底理解Characteristics.CONCURRENT属性

分支合并框架ForkJoinPoll(并行流)

对程序进行一定的改造,打印出相应的线程名称

  1. @Override
  2. public BiConsumer<Set<T>, T> accumulator() {
  3. System.out.println("accumulator invoked");
  4. return (set,item)->{
  5. System.out.println("accumulator:"+ Thread.currentThread().getName());
  6. set.add(item);
  7. };
  8. }
  • 串行情况下:
  1. Map<String, String> collect = set.Stream().collect(new MySetCollector2<>());

运行结果如下:

  • 并行情况下
  1. Map<String, String> collect = set.parallelStream().collect(new MySetCollector2<>());

运行结果如下.

如果加上 Characteristics.CONCURRENT.

  1. @Override
  2. public Set<Characteristics> characteristics() {
  3. System.out.println("characteristics invoked");
  4. return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.CONCURRENT));
  5. }

则可能会出来一个异常

  1. Caused by: java.util.ConcurrentModificationException

如果不加 ,则不会出现异常

多执行几次,会有一定的发现.

查看属性的源码.

  1. /**
  2. * Indicates that this collector is <em>concurrent</em>, meaning that
  3. * the result container can support the accumulator function being
  4. * called concurrently with the same result container from multiple
  5. * threads.
  6. *
  7. * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
  8. * then it should only be evaluated concurrently if applied to an
  9. * unordered data source.
  10. */
  11. CONCURRENT,

出现问题的原因:是在打印了set集合.


  1. /**
  2. * This exception may be thrown by methods that have detected concurrent
  3. * modification of an object when such modification is not permissible.
  4. * <p>
  5. * For example, it is not generally permissible for one thread to modify a Collection
  6. * while another thread is iterating over it. In general, the results of the
  7. * iteration are undefined under these circumstances. Some Iterator
  8. * implementations (including those of all the general purpose collection implementations
  9. * provided by the JRE) may choose to throw this exception if this behavior is
  10. * detected. Iterators that do this are known as <i>fail-fast</i> iterators,
  11. * as they fail quickly and cleanly, rather that risking arbitrary,
  12. * non-deterministic behavior at an undetermined time in the future.
  13. * <p>
  14. * Note that this exception does not always indicate that an object has
  15. * been concurrently modified by a <i>different</i> thread. If a single
  16. * thread issues a sequence of method invocations that violates the
  17. * contract of an object, the object may throw this exception. For
  18. * example, if a thread modifies a collection directly while it is
  19. * iterating over the collection with a fail-fast iterator, the iterator
  20. * will throw this exception.
  21. *
  22. * <p>Note that fail-fast behavior cannot be guaranteed as it is, generally
  23. * speaking, impossible to make any hard guarantees in the presence of
  24. * unsynchronized concurrent modification. Fail-fast operations
  25. * throw {@code ConcurrentModificationException} on a best-effort basis.
  26. * Therefore, it would be wrong to write a program that depended on this
  27. * exception for its correctness: <i>{@code ConcurrentModificationException}
  28. * should be used only to detect bugs.</i>
  29. *
  30. * @author Josh Bloch
  31. * @see Collection
  32. * @see Iterator
  33. * @see Spliterator
  34. * @see ListIterator
  35. * @see Vector
  36. * @see LinkedList
  37. * @see HashSet
  38. * @see Hashtable
  39. * @see TreeMap
  40. * @see AbstractList
  41. * @since 1.2
  42. */
  43. public class ConcurrentModificationException extends RuntimeException {
  44. }

并发修改异常.

因为如果加上这个属性,那么这个就有一个结果集

并行的时候,会对set进行操作,但是你同时又在遍历打印, 两个赶到一起了.然后就会抛出这个异常.

这就是抛出这个异常的根本原因.

注意:如果是并行的话,千万要避免 打印遍历 你要操作的对象.

如果不加这个属性,那么combiner()方法的中间结果集就会被调用,所以就不会出现抢占资源的现象.

扩展: sequential() && parallerl()方法的调用.

  1. Set<String> collect = list.stream().parallel().sequential().sequential().parallel().collect(new MySetCollector<>());

只有最后一个会生效.

sequential()

  1. /**
  2. * Returns an equivalent stream that is sequential. May return
  3. * itself, either because the stream was already sequential, or because
  4. * the underlying stream state was modified to be sequential.
  5. *
  6. * <p>This is an <a href="package-summary.html#StreamOps">intermediate
  7. * operation</a>.
  8. *
  9. * @return a sequential stream
  10. */
  11. S sequential();

parallerl()

  1. /**
  2. * Returns an equivalent stream that is parallel. May return
  3. * itself, either because the stream was already parallel, or because
  4. * the underlying stream state was modified to be parallel.
  5. *
  6. * <p>This is an <a href="package-summary.html#StreamOps">intermediate
  7. * operation</a>.
  8. *
  9. * @return a parallel stream
  10. */
  11. S parallel();

关于Supplier()容器的定义.

修改代码.查看 串行 和并行的 区别.

  1. @Override
  2. public Supplier<Set<T>> supplier() {
  3. System.out.println("supplier invoked");
  4. // return HashSet<T>::new;// 返回一个HasHSet容器.
  5. System.out.println("-----");
  6. return HashSet::new;
  7. }

结论:串行的时候,会生成单个初始容器 / 并行的时候,会生成多个初始容器.

关于串行和并行的效率问题

并不是说串行的效率就一定比并行的效率低.这都是要看实际情况的.

最多会生成系统最大CPU核心

超线程技术

Collectors类方法详解

题外话:当你具备一些底层基础知识之后,你看一些东西会觉得是理所当然的.

如果你不具备这些知识的话,是看不懂的.云里雾里的.

关注一下JDK提供的方法是怎么实现的.对于Collectors静态工厂类来说,其实现一共分为两种方式.

  1. 通过CollectorImpl来实现
  2. 通过reducing来实现 (reducing本身又是通过CollectorImpl来实现)

所以,所有的方法都是通过CollectorImpl来实现的.

  1. 4个变量
  1. static final Set<Collector.Characteristics> CH_CONCURRENT_ID
  2. = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
  3. Collector.Characteristics.UNORDERED,
  4. Collector.Characteristics.IDENTITY_FINISH));
  5. static final Set<Collector.Characteristics> CH_CONCURRENT_NOID
  6. = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
  7. Collector.Characteristics.UNORDERED));
  8. static final Set<Collector.Characteristics> CH_ID
  9. = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
  10. static final Set<Collector.Characteristics> CH_UNORDERED_ID
  11. = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
  12. Collector.Characteristics.IDENTITY_FINISH));
  13. static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
  1. toCollection()方法
  1. public static <T, C extends Collection<T>>
  2. Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
  3. return new CollectorImpl<>(collectionFactory, Collection<T>::add,
  4. (r1, r2) -> { r1.addAll(r2); return r1; },
  5. CH_ID);
  6. }
  1. toList()方法.是toCollection的一种特例.
  1. public static <T>
  2. Collector<T, ?, List<T>> toList() {
  3. return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
  4. (left, right) -> { left.addAll(right); return left; },
  5. CH_ID);
  6. }
  1. toSet()方法.是toCollection的一种特例.
  1. public static <T>
  2. Collector<T, ?, Set<T>> toSet() {
  3. return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
  4. (left, right) -> { left.addAll(right); return left; },
  5. CH_UNORDERED_ID);
  6. }
  1. joining(): 融合成一个字符串. 此外,还有两个重载的.单参数的和多参数的.
  1. public static Collector<CharSequence, ?, String> joining() {
  2. return new CollectorImpl<CharSequence, StringBuilder, String>(
  3. StringBuilder::new, StringBuilder::append,
  4. (r1, r2) -> { r1.append(r2); return r1; },
  5. StringBuilder::toString, CH_NOID);
  6. }
  1. mapping() 映射函数
  1. public static <T, U, A, R>
  2. Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
  3. Collector<? super U, A, R> downstream) {
  4. BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
  5. return new CollectorImpl<>(downstream.supplier(),
  6. (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
  7. downstream.combiner(), downstream.finisher(),
  8. downstream.characteristics());
  9. }
  1. collectingAndThen() 收集,并且做处理

    原理:把IDENTITY_FINISH标识符给去掉.

    为什么要去掉:不去掉的话,表示不会执行 finisher()方法.

  1. public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
  2. Function<R,RR> finisher) {
  3. Set<Collector.Characteristics> characteristics = downstream.characteristics();
  4. if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
  5. if (characteristics.size() == 1)
  6. characteristics = Collectors.CH_NOID;
  7. else {
  8. characteristics = EnumSet.copyOf(characteristics);
  9. characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
  10. characteristics = Collections.unmodifiableSet(characteristics);
  11. }
  12. }
  13. return new CollectorImpl<>(downstream.supplier(),
  14. downstream.accumulator(),
  15. downstream.combiner(),
  16. downstream.finisher().andThen(finisher),
  17. characteristics);
  18. }
  1. counting() 计算.
  1. public static <T> Collector<T, ?, Long>
  2. counting() {
  3. return reducing(0L, e -> 1L, Long::sum);
  4. }
  1. minBy()
  1. public static <T> Collector<T, ?, Optional<T>>
  2. minBy(Comparator<? super T> comparator) {
  3. return reducing(BinaryOperator.minBy(comparator));
  4. }
  1. maxBy()
  1. public static <T> Collector<T, ?, Optional<T>>
  2. maxBy(Comparator<? super T> comparator) {
  3. return reducing(BinaryOperator.maxBy(comparator));
  4. }
  1. summingInt(),Long(),Double

    为什么要用一个 int[1]? 最后还要返回一个数组中的单个数组呢?直接用一个数组行不行.

    因为:不行,因为直接用数字,数字是不能被传递的. 数组本身是一个引用.是可以改变的.数组本身就是一个容器.

  1. public static <T> Collector<T, ?, Integer>
  2. summingInt(ToIntFunction<? super T> mapper) {
  3. return new CollectorImpl<>(
  4. () -> new int[1],
  5. (a, t) -> { a[0] += mapper.applyAsInt(t); },
  6. (a, b) -> { a[0] += b[0]; return a; },
  7. a -> a[0], CH_NOID);
  8. }
  1. averagingInt(),Long(),Double
  1. public static <T> Collector<T, ?, Double>
  2. averagingInt(ToIntFunction<? super T> mapper) {
  3. return new CollectorImpl<>(
  4. () -> new long[2],
  5. (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
  6. (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
  7. a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
  8. }
  1. reducing() 重点函数.
  1. public static <T> Collector<T, ?, T>
  2. reducing(T identity, BinaryOperator<T> op) {
  3. return new CollectorImpl<>(
  4. boxSupplier(identity),
  5. (a, t) -> { a[0] = op.apply(a[0], t); },
  6. (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
  7. a -> a[0],
  8. CH_NOID);
  9. }
  1. groupingBy()方法的实现.(不支持并发)
  1. public static <T, K> Collector<T, ?, Map<K, List<T>>>
  2. groupingBy(Function<? super T, ? extends K> classifier) {
  3. return groupingBy(classifier, toList());//调用下面2个参数的重载和toList()方法
  4. }
  1. public static <T, K, A, D>
  2. Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
  3. Collector<? super T, A, D> downstream) {
  4. return groupingBy(classifier, HashMap::new, downstream);//调用下面的三个参数的重载
  5. }

downstream下游. (接受一个,返回一个. 返回的就叫下游)

T:分类器函数,输入参数的类型.

K:分类器函数,返回的结果的类型.

D:返回的值的结果的类型.

HashMap::new :就是返回给客户的Map/

好处:为了给用户更好的使用.直接返回HashMap

坏处:局限了只能返回HashMap类型.

  1. //groupBy函数的最底层实现.
  2. /**
  3. * Returns a {@code Collector} implementing a cascaded "group by" operation
  4. * on input elements of type {@code T}, grouping elements according to a
  5. * classification function, and then performing a reduction operation on
  6. * the values associated with a given key using the specified downstream
  7. * {@code Collector}. The {@code Map} produced by the Collector is created
  8. * with the supplied factory function.
  9. *
  10. * <p>The classification function maps elements to some key type {@code K}.
  11. * The downstream collector operates on elements of type {@code T} and
  12. * produces a result of type {@code D}. The resulting collector produces a
  13. * {@code Map<K, D>}.
  14. *
  15. * <p>For example, to compute the set of last names of people in each city,
  16. * where the city names are sorted:
  17. * <pre>{@code
  18. * Map<City, Set<String>> namesByCity
  19. * = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
  20. * mapping(Person::getLastName, toSet())));
  21. * }</pre>
  22. *
  23. * @implNote
  24. * The returned {@code Collector} is not concurrent. For parallel stream
  25. * pipelines, the {@code combiner} function operates by merging the keys
  26. * from one map into another, which can be an expensive operation. If
  27. * preservation of the order in which elements are presented to the downstream
  28. * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}
  29. * may offer better parallel performance.
  30. *
  31. * @param <T> the type of the input elements
  32. * @param <K> the type of the keys
  33. * @param <A> the intermediate accumulation type of the downstream collector
  34. * @param <D> the result type of the downstream reduction
  35. * @param <M> the type of the resulting {@code Map}
  36. * @param classifier a classifier function mapping input elements to keys
  37. * @param downstream a {@code Collector} implementing the downstream reduction
  38. * @param mapFactory a function which, when called, produces a new empty
  39. * {@code Map} of the desired type
  40. * @return a {@code Collector} implementing the cascaded group-by operation
  41. *
  42. * @see #groupingBy(Function, Collector)
  43. * @see #groupingBy(Function)
  44. * @see #groupingByConcurrent(Function, Supplier, Collector)
  45. */
  46. public static <T, K, D, A, M extends Map<K, D>>
  47. Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
  48. Supplier<M> mapFactory,
  49. Collector<? super T, A, D> downstream) {
  50. Supplier<A> downstreamSupplier = downstream.supplier();
  51. BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
  52. BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
  53. K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
  54. A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
  55. downstreamAccumulator.accept(container, t);
  56. };
  57. BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
  58. @SuppressWarnings("unchecked")
  59. Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
  60. if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
  61. return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
  62. }
  63. else {
  64. @SuppressWarnings("unchecked")
  65. Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
  66. Function<Map<K, A>, M> finisher = intermediate -> {
  67. intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
  68. @SuppressWarnings("unchecked")
  69. M castResult = (M) intermediate;
  70. return castResult;
  71. };
  72. return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
  73. }
  74. }

参数分析:

1.分类器: 输入T类型,返回K类型 返回的Map的键,是K类型.

2.容器:HashMap

3.下游收集器: D为下游收集器的返回的类型.

方法逻辑分析.

  1. groupingByConcurrent() :(支持并发) (前提是你需要对顺序没有要求.)
  1. public static <T, K>
  2. Collector<T, ?, ConcurrentMap<K, List<T>>>
  3. groupingByConcurrent(Function<? super T, ? extends K> classifier) {
  4. return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
  5. }
  6. //ConcurrentHashMap 实现起来支持并发.
  1. public static <T, K, A, D, M extends ConcurrentMap<K, D>>
  2. Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
  3. Supplier<M> mapFactory,
  4. Collector<? super T, A, D> downstream) {
  5. Supplier<A> downstreamSupplier = downstream.supplier();
  6. BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
  7. BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner());
  8. @SuppressWarnings("unchecked")
  9. Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory;
  10. BiConsumer<ConcurrentMap<K, A>, T> accumulator;
  11. //支持并发的同步的源码:
  12. if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
  13. accumulator = (m, t) -> {
  14. K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
  15. A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
  16. downstreamAccumulator.accept(resultContainer, t);
  17. };
  18. }
  19. else {
  20. accumulator = (m, t) -> {
  21. K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
  22. A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
  23. synchronized (resultContainer) {//同步锁.
  24. downstreamAccumulator.accept(resultContainer, t);
  25. }
  26. };
  27. }
  28. if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
  29. return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID);
  30. }
  31. else {
  32. @SuppressWarnings("unchecked")
  33. Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
  34. Function<ConcurrentMap<K, A>, M> finisher = intermediate -> {
  35. intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
  36. @SuppressWarnings("unchecked")
  37. M castResult = (M) intermediate;
  38. return castResult;
  39. };
  40. return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID);
  41. }
  42. }
  1. partitioningBy() 分区方法.()
  1. public static <T>
  2. Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
  3. return partitioningBy(predicate, toList());//调用完全的重载方法.
  4. }
  1. public static <T, D, A>
  2. Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
  3. Collector<? super T, A, D> downstream) {
  4. BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
  5. BiConsumer<Partition<A>, T> accumulator = (result, t) ->
  6. downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
  7. BinaryOperator<A> op = downstream.combiner();
  8. BinaryOperator<Partition<A>> merger = (left, right) ->
  9. new Partition<>(op.apply(left.forTrue, right.forTrue),
  10. op.apply(left.forFalse, right.forFalse));
  11. Supplier<Partition<A>> supplier = () ->
  12. new Partition<>(downstream.supplier().get(),
  13. downstream.supplier().get());
  14. if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
  15. return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
  16. }
  17. else {
  18. Function<Partition<A>, Map<Boolean, D>> finisher = par ->
  19. new Partition<>(downstream.finisher().apply(par.forTrue),
  20. downstream.finisher().apply(par.forFalse));
  21. return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
  22. }
  23. }

自己提供的内部静态类:

  1. /**
  2. * Implementation class used by partitioningBy.
  3. */
  4. private static final class Partition<T>
  5. extends AbstractMap<Boolean, T>
  6. implements Map<Boolean, T> {
  7. final T forTrue;
  8. final T forFalse;
  9. Partition(T forTrue, T forFalse) {
  10. this.forTrue = forTrue;
  11. this.forFalse = forFalse;
  12. }
  13. @Override
  14. public Set<Map.Entry<Boolean, T>> entrySet() {
  15. return new AbstractSet<Map.Entry<Boolean, T>>() {
  16. @Override
  17. public Iterator<Map.Entry<Boolean, T>> iterator() {
  18. Map.Entry<Boolean, T> falseEntry = new SimpleImmutableEntry<>(false, forFalse);
  19. Map.Entry<Boolean, T> trueEntry = new SimpleImmutableEntry<>(true, forTrue);
  20. return Arrays.asList(falseEntry, trueEntry).iterator();
  21. }
  22. @Override
  23. public int size() {
  24. return 2;
  25. }
  26. };
  27. }
  28. }

...

Stream类

  1. public interface Stream<T> extends BaseStream<T, Stream<T>> {}

BaseStream类

  1. package java.util.stream;
  2. import java.nio.charset.Charset;
  3. import java.nio.file.Files;
  4. import java.nio.file.Path;
  5. import java.util.Collection;
  6. import java.util.Iterator;
  7. import java.util.Spliterator;
  8. import java.util.concurrent.ConcurrentHashMap;
  9. import java.util.function.IntConsumer;
  10. import java.util.function.Predicate;
  11. /**
  12. * Base interface for streams, which are sequences of elements supporting
  13. * sequential and parallel aggregate operations. The following example
  14. * illustrates an aggregate operation using the stream types {@link Stream}
  15. * and {@link IntStream}, computing the sum of the weights of the red widgets:
  16. *
  17. * <pre>{@code
  18. * int sum = widgets.stream()
  19. * .filter(w -> w.getColor() == RED)
  20. * .mapToInt(w -> w.getWeight())
  21. * .sum();
  22. * }</pre>
  23. *
  24. * See the class documentation for {@link Stream} and the package documentation
  25. * for <a href="package-summary.html">java.util.stream</a> for additional
  26. * specification of streams, stream operations, stream pipelines, and
  27. * parallelism, which governs the behavior of all stream types.
  28. *
  29. * @param <T> the type of the stream elements
  30. * @param <S> the type of the stream implementing {@code BaseStream}
  31. * @since 1.8
  32. * @see Stream
  33. * @see IntStream
  34. * @see LongStream
  35. * @see DoubleStream
  36. * @see <a href="package-summary.html">java.util.stream</a>
  37. */
  38. public interface BaseStream<T, S extends BaseStream<T, S>>
  39. extends AutoCloseable {
  40. /**
  41. * Returns an iterator for the elements of this stream.
  42. *
  43. * <p>This is a <a href="package-summary.html#StreamOps">terminal
  44. * operation</a>.
  45. *
  46. * @return the element iterator for this stream
  47. */
  48. Iterator<T> iterator();
  49. /**
  50. * Returns a spliterator for the elements of this stream.
  51. *
  52. * <p>This is a <a href="package-summary.html#StreamOps">terminal
  53. * operation</a>.
  54. *
  55. * @return the element spliterator for this stream
  56. */
  57. Spliterator<T> spliterator();
  58. /**
  59. * Returns whether this stream, if a terminal operation were to be executed,
  60. * would execute in parallel. Calling this method after invoking an
  61. * terminal stream operation method may yield unpredictable results.
  62. *
  63. * @return {@code true} if this stream would execute in parallel if executed
  64. */
  65. boolean isParallel();
  66. /**
  67. * Returns an equivalent stream that is sequential. May return
  68. * itself, either because the stream was already sequential, or because
  69. * the underlying stream state was modified to be sequential.
  70. *
  71. * <p>This is an <a href="package-summary.html#StreamOps">intermediate
  72. * operation</a>.
  73. *
  74. * @return a sequential stream
  75. */
  76. S sequential();
  77. /**
  78. * Returns an equivalent stream that is parallel. May return
  79. * itself, either because the stream was already parallel, or because
  80. * the underlying stream state was modified to be parallel.
  81. *
  82. * <p>This is an <a href="package-summary.html#StreamOps">intermediate
  83. * operation</a>.
  84. *
  85. * @return a parallel stream
  86. */
  87. S parallel();
  88. /**
  89. * Returns an equivalent stream that is
  90. * <a href="package-summary.html#Ordering">unordered</a>. May return
  91. * itself, either because the stream was already unordered, or because
  92. * the underlying stream state was modified to be unordered.
  93. *
  94. * <p>This is an <a href="package-summary.html#StreamOps">intermediate
  95. * operation</a>.
  96. *
  97. * @return an unordered stream
  98. */
  99. S unordered();
  100. /**
  101. * Returns an equivalent stream with an additional close handler. Close
  102. * handlers are run when the {@link #close()} method
  103. * is called on the stream, and are executed in the order they were
  104. * added. All close handlers are run, even if earlier close handlers throw
  105. * exceptions. If any close handler throws an exception, the first
  106. * exception thrown will be relayed to the caller of {@code close()}, with
  107. * any remaining exceptions added to that exception as suppressed exceptions
  108. * (unless one of the remaining exceptions is the same exception as the
  109. * first exception, since an exception cannot suppress itself.) May
  110. * return itself.
  111. *
  112. * <p>This is an <a href="package-summary.html#StreamOps">intermediate
  113. * operation</a>.
  114. *
  115. * @param closeHandler A task to execute when the stream is closed
  116. * @return a stream with a handler that is run if the stream is closed
  117. */
  118. S onClose(Runnable closeHandler);
  119. /**
  120. * Closes this stream, causing all close handlers for this stream pipeline
  121. * to be called.
  122. *
  123. * @see AutoCloseable#close()
  124. */
  125. @Override
  126. void close();
  127. }

扩展:AutoCloseable接口

  1. package java.lang;
  2. /**
  3. * An object that may hold resources (such as file or socket handles)
  4. * until it is closed. The {@link #close()} method of an {@code AutoCloseable}
  5. * object is called automatically when exiting a {@code
  6. * try}-with-resources block for which the object has been declared in
  7. * the resource specification header. This construction ensures prompt
  8. * release, avoiding resource exhaustion exceptions and errors that
  9. * may otherwise occur.
  10. 一个对象在关闭之前,会持有一些资源. 句柄之类的.
  11. 在退出块的时候,会自动调用close()
  12. 避免资源被耗尽等异常.
  13. *
  14. * @apiNote
  15. * <p>It is possible, and in fact common, for a base class to
  16. * implement AutoCloseable even though not all of its subclasses or
  17. * instances will hold releasable resources. For code that must operate
  18. * in complete generality, or when it is known that the {@code AutoCloseable}
  19. * instance requires resource release, it is recommended to use {@code
  20. * try}-with-resources constructions. However, when using facilities such as
  21. * {@link java.util.stream.Stream} that support both I/O-based and
  22. * non-I/O-based forms, {@code try}-with-resources blocks are in
  23. * general unnecessary when using non-I/O-based forms.
  24. *
  25. * @author Josh Bloch
  26. * @since 1.7
  27. */
  28. public interface AutoCloseable {
  29. /**
  30. * Closes this resource, relinquishing any underlying resources.
  31. * This method is invoked automatically on objects managed by the
  32. * {@code try}-with-resources statement.
  33. *
  34. * <p>While this interface method is declared to throw {@code
  35. * Exception}, implementers are <em>strongly</em> encouraged to
  36. * declare concrete implementations of the {@code close} method to
  37. * throw more specific exceptions, or to throw no exception at all
  38. * if the close operation cannot fail.
  39. *
  40. * <p> Cases where the close operation may fail require careful
  41. * attention by implementers. It is strongly advised to relinquish
  42. * the underlying resources and to internally <em>mark</em> the
  43. * resource as closed, prior to throwing the exception. The {@code
  44. * close} method is unlikely to be invoked more than once and so
  45. * this ensures that the resources are released in a timely manner.
  46. * Furthermore it reduces problems that could arise when the resource
  47. * wraps, or is wrapped, by another resource.
  48. *
  49. * <p><em>Implementers of this interface are also strongly advised
  50. * to not have the {@code close} method throw {@link
  51. * InterruptedException}.</em>
  52. *
  53. * This exception interacts with a thread's interrupted status,
  54. * and runtime misbehavior is likely to occur if an {@code
  55. * InterruptedException} is {@linkplain Throwable#addSuppressed
  56. * suppressed}.
  57. *
  58. * More generally, if it would cause problems for an
  59. * exception to be suppressed, the {@code AutoCloseable.close}
  60. * method should not throw it.
  61. *
  62. * <p>Note that unlike the {@link java.io.Closeable#close close}
  63. * method of {@link java.io.Closeable}, this {@code close} method
  64. * is <em>not</em> required to be idempotent. In other words,
  65. * calling this {@code close} method more than once may have some
  66. * visible side effect, unlike {@code Closeable.close} which is
  67. * required to have no effect if called more than once.
  68. *
  69. * However, implementers of this interface are strongly encouraged
  70. * to make their {@code close} methods idempotent.
  71. *
  72. * @throws Exception if this resource cannot be closed
  73. */
  74. void close() throws Exception;
  75. }

使用Example去理解这个接口

  1. public class AutoCloseableTest implements AutoCloseable {
  2. public static void main(String[] args) {
  3. try(AutoCloseableTest autoCloseableTest = new AutoCloseableTest()) {
  4. autoCloseableTest.doSomething();
  5. } catch (Exception e) {
  6. e.printStackTrace();
  7. } //这种写法.try with source.
  8. }
  9. @Override
  10. public void close() throws Exception {
  11. System.out.println("close invoked");
  12. }
  13. public void doSomething(){
  14. System.out.println("doSomething invoked");
  15. }
  16. }

运行结果: (实现了这个接口的类,会自动执行 close()方法.)

总结:

  1. JDK内置的函数式接口在这里得以体现.

看底层的原因:

不是因为要让你开发过程中去

看了源码之后,你使用的时候的信心就非常足.

在遇到问题的时候,你能快速的将问题fix掉.

学习方法

1.看优秀的代码

2.去学习别人的东西

3.用的多了就会变成自己的东西.

附加一个小插曲

JAVA8学习——深入Comparator&Collector(学习过程)的更多相关文章

  1. JAVA8学习——深入浅出方法引用(学习过程)

    方法引用:method reference 先简单的看一下哪里用到了方法引用: public class MethodReferenceTest { public static void main(S ...

  2. JAVA8学习——深入浅出Lambda表达式(学习过程)

    JAVA8学习--深入浅出Lambda表达式(学习过程) lambda表达式: 我们为什么要用lambda表达式 在JAVA中,我们无法将函数作为参数传递给一个方法,也无法声明返回一个函数的方法. 在 ...

  3. Java8学习笔记----Lambda表达式 (转)

    Java8学习笔记----Lambda表达式 天锦 2014-03-24 16:43:30 发表于:ATA之家       本文主要记录自己学习Java8的历程,方便大家一起探讨和自己的备忘.因为本人 ...

  4. Java8学习(3)- Lambda 表达式

    猪脚:以下内容参考<Java 8 in Action> 本次学习内容: Lambda 基本模式 环绕执行模式 函数式接口,类型推断 方法引用 Lambda 复合 上一篇Java8学习(2) ...

  5. 关于Java8中的Comparator那些事

    在前面一篇博文中,对于java中的排序方法进行比较和具体剖析,主要是针对 Comparator接口和 Comparable接口,无论是哪种方式,都需要实现这个接口,并且重写里面的 方法.Java8中对 ...

  6. JAVA8学习——新的时间日期API&Java8总结

    JAVA8-时间日期API java8之前用过的时间日期类. Date Calendar SimpleDateFormat 有很多致命的问题. 1.没有时区概念 2.计算麻烦,实现困难 3.类是可变的 ...

  7. Java8学习笔记目录

    Java8学习笔记(一)--Lambda表达式 Java8学习笔记(二)--三个预定义函数接口 Java8学习笔记(三)--方法引入 Java8学习笔记(四)--接口增强 Java8学习笔记(五)-- ...

  8. Java8学习笔记(八)--方法引入的补充

    在Java8学习笔记(三)--方法引入中,简要总结了方法引入时的使用规则,但不够完善.这里补充下几种情况: 从形参到实例方法的实参 示例 public class Example { static L ...

  9. JAVA8学习——从使用角度深入Stream流(学习过程)

    Stream 流 初识Stream流 简单认识一下Stream:Stream类中的官方介绍: /** * A sequence of elements supporting sequential an ...

随机推荐

  1. oracle访问Table的方式

    ORACLE 采用两种访问表中记录的方式: a.       全表扫描 全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描. b ...

  2. IP应用加速技术详解:如何提升动静混合站点的访问速率?

    全站加速(DCDN)-IPA是阿里云自主研发四层加速产品,它基于TCP/UDP的私有协议提供加速服务,包括解决跨运营商网络不稳定.单线源站.突发流量.网络拥塞等诸多因素导致的延迟高.服务不稳定的问题, ...

  3. OpenStack组件系列☞glance简介

    Glance项目提供虚拟机镜像的发现,注册,取得服务. Glance提供restful API可以查询虚拟机镜像的metadata,并且可以获得镜像. 通过Glance,虚拟机镜像可以被存储到多种存储 ...

  4. java+内存分配及变量存储位置的区别

    Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java在内存分配方面的知识.一般 ...

  5. 第三期 行为规划——11.在C ++中实现第二个成本函数

    在大多数情况下,单一成本函数不足以产生复杂的车辆行为.在这个测验中,我们希望您在C ++中实现更多的成本函数.我们稍后会在本课中使用这两个C ++成本函数.这个测验的目标是创建一个成本函数,使车辆在最 ...

  6. setTimeout 传参

    一般setTimeout中的参数为 setTimeout(f,time)但是如果我想要给f函数传入一个参数怎么办 setTimeout(f(arguments),time) 如果我这样写的话,那么ti ...

  7. fakeroot与sudo的区别

    fakeroot 可以用来模拟 root 权限,以便建立特定权限与档案拥有者的压缩文件案(tar, ar, .deb 等).透过 LD_PRELOAD 的 dynamic loader 功能,用户不必 ...

  8. Linux查看用户及其权限管理

    https://www.cnblogs.com/fxlttkl/p/7601224.html 查看用户 请打开终端,输入命令: $ who am i 或者 $ who mom likes 输出的第一列 ...

  9. C#的选择语句

    一.选择语句 if,else if是如果的意思,else是另外的意思,if'后面跟()括号内为判断条件,如果符合条件则进入if语句执行命令.如果不符合则不进入if语句.else后不用加条件,但是必须与 ...

  10. 5 分钟入门 Google 最强NLP模型:BERT

    BERT (Bidirectional Encoder Representations from Transformers) 10月11日,Google AI Language 发布了论文 BERT: ...