java8新特性-引用流-sorted

Stream的执行流程参考https://www.cnblogs.com/shigongp/p/17181380.html。

例子:

    List<User> users = new ArrayList<>();
    users.add(new User("张三",30));
    users.add(new User("李四",34));
    users.add(new User("王五",20));

    System.out.println(users);
    List<User> collect = users.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList());
    System.out.println(collect);

上面的例子是按照age字段对List排序。用Stream提供的排序功能实现,排序的对象要实现Comparable或使用sorted(Comparator<? super T> comparator)方法。

源码分析

ReferencePipeline#sorted(Comparator<? super P_OUT> comparator)

  public final Stream<P_OUT> sorted(Comparator<? super P_OUT> comparator) {
    return SortedOps.makeRef(this, comparator);
}

SortedOps#makeRef

 static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
                            Comparator<? super T> comparator) {
    return new OfRef<>(upstream, comparator);
}

关注SortedOps#OfRef#opWrapSink方法

SortedOps#OfRef#opWrapSink

        @Override
    public Sink<T> opWrapSink(int flags, Sink<T> sink) {
        Objects.requireNonNull(sink);

        // If the input is already naturally sorted and this operation
        // also naturally sorted then this is a no-op
        if (StreamOpFlag.SORTED.isKnown(flags) && isNaturalSort)
            return sink;
        else if (StreamOpFlag.SIZED.isKnown(flags))
            return new SizedRefSortingSink<>(sink, comparator);
        else
            return new RefSortingSink<>(sink, comparator);
    }

如果Stream是SORTED,即Stream已经有序直接返回。如果Stream有SIZED标志,表示Stream中元素数量有限,返回SizedRefSortingSink,否则返回RefSortingSink。上面的例子返回SizedRefSortingSink。

SizedRefSortingSink#begin

    public void begin(long size) {
        if (size >= Nodes.MAX_ARRAY_SIZE)
            throw new IllegalArgumentException(Nodes.BAD_SIZE);
        array = (T[]) new Object[(int) size];
    }

创建了Object[]数组。此时并没有调用downstream.begin。

SizedRefSortingSink#accept

 public void accept(T t) {
        array[offset++] = t;
    }

将元素加到数组中。

SizedRefSortingSink#end

        public void end() {
        Arrays.sort(array, 0, offset, comparator);
        downstream.begin(offset);
        if (!cancellationWasRequested) {
            for (int i = 0; i < offset; i++)
                downstream.accept(array[i]);
        }
        else {
            for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
                downstream.accept(array[i]);
        }
        downstream.end();
        array = null;
    }

调用Arrays.sort对数组排序后,调用downstream.begin将Stream操作向下传播。for循环对每个排序后的元素调用downstream.accept,交由下一个操作处理。之后调用downstream.end()结束处理。

 
 
 
 
 
如果调用的是sorted()函数:

ReferencePipeline#sorted()

 public final Stream<P_OUT> sorted() {
    return SortedOps.makeRef(this);
}

进入SortedOps.makeRef并向下追踪可看到最终调用:

     OfRef(AbstractPipeline<?, T, ?> upstream) {
        super(upstream, StreamShape.REFERENCE,
              StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
        this.isNaturalSort = true;
        // Will throw CCE when we try to sort if T is not Comparable
        @SuppressWarnings("unchecked")
        Comparator<? super T> comp = (Comparator<? super T>) Comparator.naturalOrder();
        this.comparator = comp;
    }

可看到comparator是Comparator.naturalOrder()。

 
 
 
 
 
抛开这个例子不谈,看下RefSortingSink:

private static final class RefSortingSink<T> extends AbstractRefSortingSink<T> {
    private ArrayList<T> list;

    RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
        super(sink, comparator);
    }

    @Override
    public void begin(long size) {
        if (size >= Nodes.MAX_ARRAY_SIZE)
            throw new IllegalArgumentException(Nodes.BAD_SIZE);
        list = (size >= 0) ? new ArrayList<T>((int) size) : new ArrayList<T>();
    }

    @Override
    public void end() {
        list.sort(comparator);
        downstream.begin(list.size());
        if (!cancellationWasRequested) {
            list.forEach(downstream::accept);
        }
        else {
            for (T t : list) {
                if (downstream.cancellationRequested()) break;
                downstream.accept(t);
            }
        }
        downstream.end();
        list = null;
    }

    @Override
    public void accept(T t) {
        list.add(t);
    }
}

begin方法创建了ArrayList而不是数组。accept方法调用list.add添加元素。end方法调用ArrayList.sort排序。之后的处理和SizedRefSortingSink差不多。

posted @ 2023-03-12 19:06  shigp1  阅读(139)  评论(0编辑  收藏  举报