Stream的深入(三)

心得:之前学习流,深入了流的底层。但是学的这些东西在平时日常开发的过程中,是根本不会用到的。只是为了更好帮助自己去理解流的底层设施。用起来也更自信,能够确定用的东西非常正确。

专注技术:这种纯技术的这种环境。

而不是说:专注业务开发了5年,技术没有长进。

这位张龙老师给讲课的方式,就是学习一门新技术的过程。如果觉得这种方式学习起来很有效的话。可以使用这种方式去学习一门新的技术。

lambda表达式和匿名内部类完全不同

之前虽然学了流了,但是还不太够。我们还缺少了一个能够把一个流从头到尾的执行过程给用起来的过程。

接下来会完成这个目的

用程序入门。

  1. public class LambdaTest {
  2. //内部类和lambda表达式到底有什么关系
  3. Runnable r1 = () -> System.out.println(this);
  4. //匿名内部类 - 标识我生成了一个Runnable的实例 . 是一个类
  5. Runnable r2 = new Runnable() {
  6. @Override
  7. public void run() {
  8. System.out.println(this);
  9. }
  10. };
  11. public static void main(String[] args) {
  12. LambdaTest lambdaTest = new LambdaTest();
  13. Thread t1 = new Thread(lambdaTest.r1);
  14. t1.start();
  15. System.out.println("-------------");
  16. Thread t2 = new Thread(lambdaTest.r2);
  17. t2.start();
  18. //请问,输出结果一样吗?
  19. }
  20. }

运行结果:

  1. -------------
  2. com.dawa.jdk8.LambdaTest@59a30351 (lambda表达式的结果)
  3. com.dawa.jdk8.LambdaTest$1@2831008d (匿名内部类的结果)
  4. Process finished with exit code 0

LambdaTest$1, 这个1就是匿名内部类的类名。 (匿名内部类的名字)

经过对比,虽然说 lambda是匿名内部类的不同实现,但是 他们两个是完全一样的。原理不同。

结论:

  1. 匿名内部类会开辟一个新的作用域
  2. lambda是不会开辟新的作用域的

这里普及这个知识点,是为了以后在Debug的时候会发现 匿名内部类和lambda表达式的类名不同、


系统的去走一遍stream的执行流程

  1. public class StreamTest3 {
  2. public static void main(String[] args) {
  3. List<String> list = Arrays.asList("hello", "world", "welcome");
  4. list.stream().map(item->item+"_abc").forEach(System.out::println);
  5. }
  6. }

map()实现

返回值为StatelessOp

  1. @Override
  2. @SuppressWarnings("unchecked")
  3. public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
  4. Objects.requireNonNull(mapper);
  5. return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
  6. StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
  7. @Override
  8. Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
  9. return new Sink.ChainedReference<P_OUT, R>(sink) {
  10. @Override
  11. public void accept(P_OUT u) {
  12. downstream.accept(mapper.apply(u));
  13. }
  14. };
  15. }
  16. };
  17. }
  1. //StatelessOp类的定义和构造方法
  2. /**
  3. * Base class for a stateless intermediate stage of a Stream.
  4. *
  5. * @param <E_IN> type of elements in the upstream source
  6. * @param <E_OUT> type of elements in produced by this stage
  7. * @since 1.8
  8. */
  9. abstract static class StatelessOp<E_IN, E_OUT>
  10. extends ReferencePipeline<E_IN, E_OUT> {
  11. /**
  12. * Construct a new Stream by appending a stateless intermediate
  13. * operation to an existing stream.
  14. *
  15. * @param upstream The upstream pipeline stage
  16. * @param inputShape The stream shape for the upstream pipeline stage
  17. * @param opFlags Operation flags for the new stage
  18. */
  19. StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
  20. StreamShape inputShape,
  21. int opFlags) {
  22. super(upstream, opFlags);
  23. assert upstream.getOutputShape() == inputShape;
  24. }
  25. @Override
  26. final boolean opIsStateful() {
  27. return false;
  28. }
  29. }

StatelessOp继承ReferencePipeline,而ReferencePipeline实现了Stream.

所以map方法返回new StatelessOp<P_OUT, R>就等于返回了一个Stream

返回的是继承了StatelessOp的子类的对象。完成了上游和下游流的互通.

Reference Pipeline 无非就是一个双向链表

操作包装:map()方法中的 opWrapSink()的ChainedReference,实现了流的包装操作。把剩下的流给warp到一起

然后就一个元素,同时经过了剩下的方法操作。

  1. @Override
  2. Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
  3. return new Sink.ChainedReference<P_OUT, R>(sink) {
  4. @Override
  5. public void accept(P_OUT u) {
  6. downstream.accept(mapper.apply(u));
  7. }
  8. };
  9. }
  1. Sink
  2. * <p>A sink may be in one of two states: an initial state and an active state.
  3. * It starts out in the initial state; the {@code begin()} method transitions
  4. * it to the active state, and the {@code end()} method transitions it back into
  5. * the initial state, where it can be re-used. Data-accepting methods (such as
  6. * {@code accept()} are only valid in the active state.
  7. *

ChainedReference()链接引用

  1. /**
  2. * Abstract {@code Sink} implementation for creating chains of
  3. * sinks. The {@code begin}, {@code end}, and
  4. * {@code cancellationRequested} methods are wired to chain to the
  5. * downstream {@code Sink}. This implementation takes a downstream
  6. * {@code Sink} of unknown input shape and produces a {@code Sink<T>}. The
  7. * implementation of the {@code accept()} method must call the correct
  8. * {@code accept()} method on the downstream {@code Sink}.
  9. */
  10. static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
  11. protected final Sink<? super E_OUT> downstream;
  12. public ChainedReference(Sink<? super E_OUT> downstream) {
  13. this.downstream = Objects.requireNonNull(downstream);
  14. }
  15. @Override
  16. public void begin(long size) {
  17. downstream.begin(size);
  18. }
  19. @Override
  20. public void end() {
  21. downstream.end();
  22. }
  23. @Override
  24. public boolean cancellationRequested() {
  25. return downstream.cancellationRequested();
  26. }
  27. }

Sink类中的end(),和 begin()方法,切换两种状态:1.初始状态 2.激活状态

每一次accept()方法执行之前,需要调用Sink中的begin()方法,进入激活状态,执行完毕之后调用end()方法,进入初始状态。

涉及设计模式:模板方法模式。

opWrapSink() 的上级实现:

接受了一个Sink对象,这个对象接受了操作的结果,并且返回了一个Sink,还会执行这个操作,并将这个结果传递给所提供的sink。 *(输入参数才是带结果的sinK)

正是因为这种操作,才能将sink给包装起来。

  1. /**
  2. * Accepts a {@code Sink} which will receive the results of this operation,
  3. * and return a {@code Sink} which accepts elements of the input type of
  4. * this operation and which performs the operation, passing the results to
  5. * the provided {@code Sink}.
  6. 接受了一个Sink对象,这个对象接受了操作的结果,并且返回了一个Sink,还会执行这个操作,并将这个结果传递给所提供的sink。 *(输入参数才是带结果的sinK)
  7. 正式因为这种操作,才能将sink给包装起来。
  8. *
  9. * @apiNote
  10. * The implementation may use the {@code flags} parameter to optimize the
  11. * sink wrapping. For example, if the input is already {@code DISTINCT},
  12. * the implementation for the {@code Stream#distinct()} method could just
  13. * return the sink it was passed.
  14. *
  15. * @param flags The combined stream and operation flags up to, but not
  16. * including, this operation
  17. * @param sink sink to which elements should be sent after processing
  18. * @return a sink which accepts elements, perform the operation upon
  19. * each element, and passes the results (if any) to the provided
  20. * {@code Sink}.
  21. 参数本身是用来接收结果的,而不是用返回值来返回结果的。
  22. */
  23. abstract Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink);
  1. @Override
  2. final Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink) {
  3. throw new UnsupportedOperationException();
  4. }

流的特性:惰性求值和延迟求值。

map()方法,包括其他的peek(),filter()等等中间操作的这些方法。只是完成了返回了一个StatelessOp对象。

所以中间操作返回一个终止对象可能执行的StatelessOp,没有终止操作,所以流不会被处理。

那么终止操作。我们要去追一下了。


拿代码中写的 forEach()方法开始去追

  1. // Terminal operations from Stream
  2. @Override
  3. public void forEach(Consumer<? super P_OUT> action) {
  4. evaluate(ForEachOps.makeRef(action, false));
  5. }

这是调用了makeRef()方法.方法在ForEachOps类中.

先看ForEachOps类的javadoc

  1. /**
  2. * Factory for creating instances of {@code TerminalOp} that perform an
  3. * action for every element of a stream. Supported variants include unordered
  4. * traversal (elements are provided to the {@code Consumer} as soon as they are
  5. * available), and ordered traversal (elements are provided to the
  6. * {@code Consumer} in encounter order.)
  7. 这是一个工厂,用来创建 TerminalOp 对象,(终止操作。)这个对象会对每一个元素执行一个动作。
  8. 所支持的变化包括:无序的遍历,有序的遍历(按照所提供的的顺序来遍历)。
  9. *
  10. * <p>Elements are provided to the {@code Consumer} on whatever thread and
  11. * whatever order they become available. For ordered traversals, it is
  12. * guaranteed that processing an element <em>happens-before</em> processing
  13. * subsequent elements in the encounter order.
  14. 元素被提供被一个任何可用的Consumer队形。
  15. 处理一个元素,一定是发生在 另外一件事之前 (happens-before)。
  16. 也就事 先遇到的元素先处理,后遇到的元素后处理。
  17. *
  18. * <p>Exceptions occurring as a result of sending an element to the
  19. * {@code Consumer} will be relayed to the caller and traversal will be
  20. * prematurely terminated.
  21. 提供了大量的 静态方法。
  22. *
  23. * @since 1.8
  24. */
  25. final class ForEachOps {
  26. }

如makeRef()

  1. /**
  2. * Constructs a {@code TerminalOp} that perform an action for every element
  3. * of a stream.
  4. *
  5. * @param action the {@code Consumer} that receives all elements of a
  6. * stream
  7. * @param ordered whether an ordered traversal is requested
  8. * @param <T> the type of the stream elements
  9. * @return the {@code TerminalOp} instance
  10. */
  11. public static <T> TerminalOp<T, Void> makeRef(Consumer<? super T> action,
  12. boolean ordered) {
  13. Objects.requireNonNull(action);
  14. return new ForEachOp.OfRef<>(action, ordered);
  15. }

TerminalOp说明

默认执行的是串行的。

  1. /**
  2. * An operation in a stream pipeline that takes a stream as input and produces
  3. * a result or side-effect. A {@code TerminalOp} has an input type and stream
  4. * shape, and a result type. A {@code TerminalOp} also has a set of
  5. * <em>operation flags</em> that describes how the operation processes elements
  6. * of the stream (such as short-circuiting or respecting encounter order; see
  7. * {@link StreamOpFlag}).
  8. 流管道中的一个操作。会接受一个流作为输入, 产生的结果,是有副作用的(副作用:你传递了一个引用,你修改了这个引用)。
  9. 一个 TerminalOp 会有一个输入类型,和流的shape 和一个结果类型。
  10. TerminalOp 还会有一个 如何处理流中的元素 的标识。
  11. TerminalOp 必须要提供一种 串行的和并行的 实现。
  12. *
  13. * <p>A {@code TerminalOp} must provide a sequential and parallel implementation
  14. * of the operation relative to a given stream source and set of intermediate
  15. * operations.
  16. *
  17. * @param <E_IN> the type of input elements
  18. * @param <R> the type of the result
  19. * @since 1.8
  20. */
  21. interface TerminalOp<E_IN, R> {
  22. /**
  23. * Gets the shape of the input type of this operation.
  24. *
  25. * @implSpec The default returns {@code StreamShape.REFERENCE}.
  26. *
  27. * @return StreamShape of the input type of this operation
  28. */
  29. default StreamShape inputShape() { return StreamShape.REFERENCE; }
  30. /**
  31. * Gets the stream flags of the operation. Terminal operations may set a
  32. * limited subset of the stream flags defined in {@link StreamOpFlag}, and
  33. * these flags are combined with the previously combined stream and
  34. * intermediate operation flags for the pipeline.
  35. *
  36. * @implSpec The default implementation returns zero.
  37. *
  38. * @return the stream flags for this operation
  39. * @see StreamOpFlag
  40. */
  41. default int getOpFlags() { return 0; }
  42. /**
  43. * Performs a parallel evaluation of the operation using the specified
  44. * {@code PipelineHelper}, which describes the upstream intermediate
  45. * operations.
  46. *
  47. * @implSpec The default performs a sequential evaluation of the operation
  48. * using the specified {@code PipelineHelper}.
  49. *
  50. * @param helper the pipeline helper
  51. * @param spliterator the source spliterator
  52. * @return the result of the evaluation
  53. */
  54. default <P_IN> R evaluateParallel(PipelineHelper<E_IN> helper,
  55. Spliterator<P_IN> spliterator) {
  56. if (Tripwire.ENABLED)
  57. Tripwire.trip(getClass(), "{0} triggering TerminalOp.evaluateParallel serial default");
  58. return evaluateSequential(helper, spliterator);
  59. }
  60. /**
  61. * Performs a sequential evaluation of the operation using the specified
  62. * {@code PipelineHelper}, which describes the upstream intermediate
  63. * operations.
  64. *
  65. * @param helper the pipeline helper
  66. * @param spliterator the source spliterator
  67. * @return the result of the evaluation
  68. */
  69. <P_IN> R evaluateSequential(PipelineHelper<E_IN> helper,
  70. Spliterator<P_IN> spliterator);
  71. }

终止操作的实现就4类:

1.find

2.match

3.forEach 遍历

4.reduce

返回去: forEach()操作就是返回了一个终止操作对象。

然后:evaluate()方法, 执行那个终止操作对象。


  1. // Terminal evaluation methods
  2. /**
  3. * Evaluate the pipeline with a terminal operation to produce a result.
  4. *
  5. * @param <R> the type of result
  6. * @param terminalOp the terminal operation to be applied to the pipeline.
  7. * @return the result
  8. */
  9. final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
  10. assert getOutputShape() == terminalOp.inputShape();
  11. if (linkedOrConsumed)
  12. throw new IllegalStateException(MSG_STREAM_LINKED);
  13. linkedOrConsumed = true;
  14. return isParallel()
  15. ? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))
  16. : terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags()));
  17. }

PipelineHelper类

用来描述流的各种信息。

  1. /**
  2. * Helper class for executing <a href="package-summary.html#StreamOps">
  3. * stream pipelines</a>, capturing all of the information about a stream
  4. * pipeline (output shape, intermediate operations, stream flags, parallelism,
  5. * etc) in one place.
  6. Helper是一个帮助类,用于执行流管道
  7. 包含流管道的所有信息:源数据。输出类型,操作,流标识,并行标记等。
  8. *
  9. * <p>
  10. * A {@code PipelineHelper} describes the initial segment of a stream pipeline,
  11. * including its source, intermediate operations, and may additionally
  12. * incorporate information about the terminal (or stateful) operation which
  13. * follows the last intermediate operation described by this
  14. * {@code PipelineHelper}. The {@code PipelineHelper} is passed to the
  15. * {@link TerminalOp#evaluateParallel(PipelineHelper, java.util.Spliterator)},
  16. * {@link TerminalOp#evaluateSequential(PipelineHelper, java.util.Spliterator)},
  17. * and {@link AbstractPipeline#opEvaluateParallel(PipelineHelper, java.util.Spliterator,
  18. * java.util.function.IntFunction)}, methods, which can use the
  19. * {@code PipelineHelper} to access information about the pipeline such as
  20. * head shape, stream flags, and size, and use the helper methods
  21. * such as {@link #wrapAndCopyInto(Sink, Spliterator)},
  22. * {@link #copyInto(Sink, Spliterator)}, and {@link #wrapSink(Sink)} to execute
  23. * pipeline operations..
  24. 一个流管道的最初的分块,包含源,中间操作和增加的操作。等
  25. PipelineHelper会被传递给。。。。 方法, 就可以通过PipelineHelper来访问管道的各种信息。
  26. *
  27. * @param <P_OUT> type of output elements from the pipeline
  28. * @since 1.8
  29. */
  30. abstract class PipelineHelper<P_OUT> {
  31. ...
  32. }

PipelineHelper类里的方法:wrapAndCopyInto()

  1. /**
  2. * Applies the pipeline stages described by this {@code PipelineHelper} to
  3. * the provided {@code Spliterator} and send the results to the provided
  4. * {@code Sink}.
  5. 将调用了这个方法的pipeline所描述的管道的各个阶段,同时 应用到Spliterator和发送给Sink对象
  6. *
  7. * @implSpec
  8. * The implementation behaves as if:
  9. * <pre>{@code
  10. * intoWrapped(wrapSink(sink), spliterator);
  11. * }</pre>
  12. *
  13. * @param sink the {@code Sink} to receive the results
  14. * @param spliterator the spliterator describing the source input to process
  15. */
  16. abstract<P_IN, S extends Sink<P_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator);

wrapAndCopyInto具体实现:

  1. @Override
  2. final <P_IN, S extends Sink<E_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator) {
  3. copyInto(wrapSink(Objects.requireNonNull(sink)), spliterator);
  4. return sink;
  5. }

Sink中的wrapSink()方法

  1. /**
  2. * Takes a {@code Sink} that accepts elements of the output type of the
  3. * {@code PipelineHelper}, and wrap it with a {@code Sink} that accepts
  4. * elements of the input type and implements all the intermediate operations
  5. * described by this {@code PipelineHelper}, delivering the result into the
  6. * provided {@code Sink}.
  7. 接受了一个Sink, Sink接受了PipelineHelper的所有输出类型。
  8. *
  9. * @param sink the {@code Sink} to receive the results
  10. * @return a {@code Sink} that implements the pipeline stages and sends
  11. * results to the provided {@code Sink}
  12. */
  13. abstract<P_IN> Sink<P_IN> wrapSink(Sink<P_OUT> sink);

wrapSink()方法具体实现 (完成了对于多个流操作的串联。)

  1. @Override
  2. @SuppressWarnings("unchecked")
  3. final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
  4. Objects.requireNonNull(sink);
  5. //根据depth判断是否有中间操作。 从后往前的去走。
  6. for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
  7. sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
  8. }
  9. return (Sink<P_IN>) sink;
  10. }

wrapSink()


自我总结:Stream的执行流程。

源数据-中间操作-中间操作-终止操作

1.串联起来所有的操作。(中间操作 和 终止操作)

2.让流中的元素,一个一个的执行所含有的所有操作。

最核心的方法:copyInto()中的:spliterator.forEachRemaining(wrappedSink); //最最核心的一步

  1. @Override
  2. final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
  3. Objects.requireNonNull(wrappedSink);
  4. if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
  5. wrappedSink.begin(spliterator.getExactSizeIfKnown());
  6. spliterator.forEachRemaining(wrappedSink); //最最核心的一步
  7. wrappedSink.end();
  8. }
  9. else {
  10. copyIntoWithCancel(wrappedSink, spliterator);
  11. }
  12. }

wrappedSink : 所有的中间操作,封装到了这个 sink对象

spliterator:源数据- 执行forEachRemaining 遍历,执行每一次这过sink对象封装的操作。

上面是静态分析(通过源码分析)

自行通过动态分析(程序Debug分析)


t通过Debug去跟一遍代码。

  1. public class StreamTest3 {
  2. public static void main(String[] args) {
  3. List<String> list = Arrays.asList("hello", "world", "welcome");
  4. // list.stream().map(item->item+"_abc").forEach(System.out::println);
  5. Stream<String> stream = list.stream();
  6. System.out.println("1");//断点
  7. Stream<String> stream1 = stream.map(item -> item + "_abc");
  8. System.out.println("2");//断点
  9. stream1.forEach(System.out::println);
  10. }
  11. }

JAVA8学习——Stream底层的实现三(学习过程)的更多相关文章

  1. JAVA8学习——Stream底层的实现(学习过程)

    Stream底层的实现 Stream接口实现了 BaseStream 接口,我们先来看看BaseStream的定义 BaseStream BaseStream是所有流的父类接口. 对JavaDoc做一 ...

  2. JAVA8学习——Stream底层的实现一(学习过程)

    Stream底层的实现 Stream接口实现了 BaseStream 接口,我们先来看看BaseStream的定义 BaseStream BaseStream是所有流的父类接口. 对JavaDoc做一 ...

  3. JAVA8学习——Stream底层的实现二(学习过程)

    继续深入Stream的底层实现过程 2.spliterator() 接上 https://www.cnblogs.com/bigbaby/p/12159495.html 我们这次回到最开始源码分析的地 ...

  4. JAVA8学习——Stream底层的实现四(学习过程)

    Stream的深入(四) 从更高角度去看一下:类与类之间的设计关系 (借助IDEA的图形处理工具 Ctrl+Alt+U). ReferencePipeline的三个实现的子类: Head Statel ...

  5. JAVA8学习——深入浅出函数式接口FunctionInterface(学习过程)

    函数式接口 函数式接口详解:FunctionInterface接口 话不多说,先打开源码,查阅一番.寻得FunctionInterface接口 package java.util.function; ...

  6. Java8学习笔记(二)--三个预定义函数接口

    三个函数接口概述 JDK预定义了很多函数接口以避免用户重复定义.最典型的是Function: @FunctionalInterface public interface Function<T, ...

  7. Java8学习笔记目录

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

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

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

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

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

随机推荐

  1. 宝塔linux

    宝塔linux linux 定时任务管理

  2. SuperSocket获取所有连接上的 Session

    你也可以从 AppServer 实例获取所有连接上的 session 然后推送数据到所有客户端: foreach(var session in appServer.GetAllSessions()) ...

  3. 使用属性position:fixed的时候如何才能让div居中

    css: .aa{ position: fixed; top: 200px; left: 0px; right: 0px; width: 200px; height: 200px; margin-le ...

  4. X Samara Regional Intercollegiate Programming Contest

    A. Streets of Working Lanterns - 2 对于每个括号序列,存在一个\(mv\),表示要接上这个序列至少需要\(-mv\)个左括号,同时处理出接上这个序列后,左括号数量的增 ...

  5. 怎样判断一个jquery对象是否为空jquery对象

    if ( $('#myDiv').length ){} http://stackoverflow.com/questions/47... 也可以直接判断$('#myDiv')[0]===undefin ...

  6. Codeforces Round #189 (Div. 1 + Div. 2)

    A. Magic Numbers 不能出现连续的3个4,以及1.4以外的数字. B. Ping-Pong (Easy Version) 暴力. C. Malek Dance Club 考虑\(x\)二 ...

  7. 【codeforces 764B】Timofey and cubes

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  8. 地址中如果含有"+",发给服务器时"+"变成了空格问题解析

    如地址为sms:+7 915 444-414-444,含有空格. 服务器解码 URLDecoder.decode("sms:+7 915 444-414-444"),返回的是sms ...

  9. java 反射实现框架功能

    框架与框架要解决的核心问题 我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中.框架与工具类有区别,工具类被用户的类调用,而框架则是调用 ...

  10. P1018 灵灵排数字

    题目描述 今天灵灵收到了n张卡片,他需要给他们从小到大排序. 输入格式 输入的第一行包含一个整数 \(n(1 \le n \le 10^5)\) . 输入的第二行包含 \(n\) 个正整数,以空格间隔 ...