查看“核心技术Ⅱ:流”的源代码
←
核心技术Ⅱ:流
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
[[category:JavaCore]] == 关于 Java SE 8 的流库 == <pre> Stream它并不是一个容器,它只是对容器的功能进行了增强,添加了很多便利的操作,例如查找、过滤、分组、排序等一系列的操作。 并且有串行、并行两种执行模式,并行模式充分的利用了多核处理器的优势,使用fork/join框架进行了任务拆分,同时提高了执行速度。 简而言之,Stream就是提供了一种高效且易于使用的处理数据的方式。 </pre> 流提供了一种在比集合更高的概念级别上指定计算的数据视图,以“做什么而非怎么做”的方式处理集合。 === 从迭代到流的操作 === 处理集合时,通常会迭代遍历它的元素,并在每个元素上执行某项操作: <syntaxhighlight lang="java"> String contents = new String(Files.readAllBytes(Paths.get("alice.txt")), Standard(harsets,UTF_8); // Read file into string List<String> words= Arrays.aslist(contents.split("\\PL+")); // Split into words; nonletters are delimiters long count = O; for (String w : words) { if (w. length() > 12) count++; } </syntaxhighlight> 使用流时,相同的操作看起来像下面这样: <syntaxhighlight lang="java"> 1ong count = words.stream().filter(w -> w.length() > 12).count(); </syntaxhighlight> * 仅将stream 修改为parallelStream 就可以让流库以并行方式来执行过滤和计数: *: <syntaxhighlight lang="java"> 1ong count = words.parallelStream().filter(w -> w.length() > 12).count(); </syntaxhighlight> 以上: # stream 和parallel Stream 方法会产生一个用于words 列表的stream。 # filter 方法会返回另一个流,其中只包含长度大于12 的单词。 # count 方法会将这个流化简为一个结果。 === 流与集合 === 流表面上活起来和集合很类似,都可以让我们转换和获取数据。但是,它们之间存在着显著的差异: # 流并不存储其元素。 #: 这些元素可能存储在底层的栠合中,或者是按需生成的。 # 流的操作不会修改其数据源。 #: 例如,filter 方法不会从新的流中移除元素,而是会生成一个新的流,其中不包含被过滤掉的元素。 # 流的操作是尽可能惰性执行的。这意味若直至需要其结果时,操作才会执行。 #: 例如,如果我们只想查找前5 个长单词而不是所有长单词,那么filter 方法就会在匹配到第5 个单词后停止过滤。因此,我们甚至可以操作无限流。 === 相关方法 === java.util.stream.Stream<T> 8 * Stream<T> filter(Predicate<? super T> p) *: 产生一个流,其中包含当前流中满足P 的所有元索。 * 1ong count() *: 产生当前流中元素的数批。这是一个终止操作。 java.util.Collection<E> 1.2 * default Stream<E> stream() * default Stream<E> parallel Stream() *: 产生当前集合中所有元素的顺序流或并行流。 == 流的创建 == # 集合转换为流: #: 用“Collection.stream()”方法将任何集合转换为一个流。 # 数组转换为流: ## 使用“Array.stream(array, from, to)”可以从数组中位于from (包括)和to (不包括)的元索中创建一个流。 ## 使用Stream静态的“of”方法,将数组转换为流: ##: <syntaxhighlight lang="java"> Stream<String> words= Stream.of(contents.split("\\PL+")); // split returns a String[] array </syntaxhighlight> ##* of 方法具有可变长参数,因此我们可以构建具有任意数趾引元的流: ##*: <syntaxhighlight lang="java"> Stream<String> song = Stream.of("gently", "down", "the", "stream"); </syntaxhighlight> # 空流: #: 使用静态的Stream.empty 方法,创建不包含任何元素的流; #: <syntaxhighlight lang="java"> Stream<String> silence = Stream.empty(); // Generic type <String> is inferred; same as St ream. <St ri ng>empty() </syntaxhighlight> # 无限流: ## generate 方法:接受一个不包含任何引元的函数(或者从技术上讲,是一个Supplier<T> 接口的对象)。 ##: <syntaxhighlight lang="java"> Stream<String> echos = Stream.generate(() -> "Echo"); // 获得一个常批值的流: Stream<Double> randoms = Stream.generate(Math:: random); // 获得一个随机数的流: </syntaxhighlight> ## iterate 方法:接受一个“种子”值,以及一个函数(从技术上讲,是一个UnaryOperation<T>), 并且会反复地将该函数应用到之前的结果上。 ##: <syntaxhighlight lang="java"> Strea价<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE)); // 第一个元素是种子Biglnteger.ZERO, 第二个元素是f(seed), 即l (作为大整数),下一个元素是f(f(seed)), 即2, 后续以此类推。 </syntaxhighlight> Java API中的其他流方法: # Pattern 类有一个“splitAsStream”方法,它会按照某个正则表达式来分割一个“CharSequence”对象: #: <syntaxhighlight lang="java"> Stream<String> words = Pattern,compile("\\PL+").splitAsStream(contents); </syntaxhighlight> # 静态的“Files.lines”方法会返回一个包含了文件中所有行的Stream: #: <syntaxhighlight lang="java"> try (Stream<String> lines = Files.lines (path)) { ...Process lines... } </syntaxhighlight> === 相关方法 === java.util.stream.Stream 8 * static <T> Stream<T> of(T .. . values) *: 产生一个元素为给定值的流。 * static <T> Stream<T> empty() *: 产生一个不包含任何元素的流。 * static <T> Stream<T> generate(Supplier<T> s) *: 产生一个无限流,它的值是通过反复调用函数s 而构建的。 * static <T> Stream<T> iterate(T seed , UnaryOperator<T> f ) *: 产生一个无限流,它的元素包含种子、在种子上调用f 产生的值、在前一个元素上调用f 产生的值,等等。 java.util.Arrays 1.2 * static <T> Stream<T> stream(T[] array, int startinclusive , int endExclusive) 8 *: 产生一个流,它的元素是由数组中指定范围内的元素构成的。 java.util.regex.Pattem 1.4 * Stream<Stri ng> spl i tAsStream(CharSequence input) 8 *: 产生一个流,它的元素是输入中由该模式界定的部分。 java.nio.file.Files 7 * static Stream<String> lines(Path path) 8 * static Stream<Stri ng> lines(Path path, Charset cs) 8 *: 产生一个流, 它的元素是指定文件中的行,该文件的字符集为UTF-8 , 或者为指定的字符集。 java.util.function.Supplier<T> 8 * T get() *: 提供一个值。 == 流的转换 == '''流的转换会产生一个新的流,它的元素派生自另一个流中的元素。''' === filter 、map 和 flatMap 方法 === # '''filter''' 转换会产生一个流,它的元素与某种条件相匹配。 #: filter 的引元是Predicate<T>, 即从T 到boolean 的函数。 #: <syntaxhighlight lang="java"> List<String> wordlist = . . . ; Stream<String> longwords = wordlist.stream().filter(w -> w. length() > 12); </syntaxhighlight> # '''map''' 方法用于按照某种方式来转换流中的值。 #: <syntaxhighlight lang="java"> // 1、使用函数式接口: Stream<String> lowercaseWords = words.stream().map(String::tolowerCase); // 2、或者使用lambda替换: Stream<String> firstletters = words.stream().map(s -> s.substring(O, 1)); </syntaxhighlight> # '''flatMap''' 方法用于“摊平由流构成的流”。 #: (即,将包含流的流,变为流) #: <syntaxhighlight lang="java"> // 1、 Stream<Stream<String>> result = words.stream() .map(w -> letters(w)); // 2、 Stream<String> flatResult = words.stream().flatMap(w -> letters(w)); letters: public static Stream<String> letters(String s) { List<Stri ng> result = new Array List<>(); for (int i = O; i < s.length(); i++) result.add(s.substring(i, i + 1)); return result.stream(); } // 若 w 为“[[your][boat]]”; // 1、结果为“[...["y","o", "u" ,"r"),["b" ,"o" ,"a" ,"t"],...]”; // 2、结果为“[..."y","o","u" ,"r", "b","o" ,"a" ,"t",...],”; </syntaxhighlight> ==== 相关方法 ==== java.util.stream.Stream 8 * Stream<T> filter(Predicate<? super T> predicate) *: 产生一个流,它包含当前流中所有满足断言条件的元索。 * <R> Stream<R> map(Function<? super T,? extends R> mapper) *: 产生一个流,它包含将mapper 应用于当前流中所有元素所产生的结果。 * <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R»mapper) *: 产生一个流,它是通过将mapper 应用于当前流中所有元素所产生的结果连接到一起而获得的。(注意,这里的每个结果都是一个流。) === 抽取子流和连接流 === # '''stream.limit(n)''':会返回一个新的流,它在n个元素之后结束(如果原来的流更短,那么就会在流结束时结束)。 #:(对于裁剪无限流的尺寸特别有用。) #: <syntaxhighlight lang="java"> Stream<Doub1e> randoms = Stream.generate(Math::random).1imit(lOO); // 会产生一个包含100 个随机数的流 </syntaxhighlight> # '''stream.skip(n)''':会丢弃前n个元素。 #:(在将文本分隔为单词时会显得很方便。) #: <syntaxhighlight lang="java"> Stream<String> words = Stream.of(contents.split("\\PL+")).skip(l); // 会跳过split方法产生字符串的第一个字符(空字符串) </syntaxhighlight> # '''Stream.concat(Stream<? extends T> a, Stream<? extends T> b)''':静态方法,用于拼接两个流。 #* 第一个流不应该是无限的,否则第二个流没有处理机会。 #: <syntaxhighlight lang="java"> Stream<String> combined= Stream.concat(1etters("Hello"), 1etters("Wor1d")); // Yields the stream ["H", "e", "l", "1", "o", "W", "o", "r", "l", "d") </syntaxhighlight> ==== 相关方法 ==== java:util.stream.Stream 8 * Stream<T> limit(long maxSize) *: 产生一个流,其中包含了当前流中最初的maxSize 个元素。 * Stream<T> skip(long n) *: 产生一个流,它的元素是当前流中除了前n 个元素之外的所有元素。 * static<T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) *: 产生一个流,它的元素是a 的元素后面跟着b 的元素。 === 其他的流转换 === # '''distinct''':方法会返回一个流,它的元素是从原有流中,按照同样的顺序剔除重复元素后产生的。 #: <syntaxhighlight lang="java"> Stream<String> uniqueWords = Stream.of("merrily", "merrily", "merrily", "gently").distinct(); // Only one "merrily" is retained </syntaxhighlight> # '''sorted''':方法会返回一个流,它的元素是原有流中按照顺序排列的元素。 #:(有多种sorted方法的变体可用:一种用于操作“Comparable”元素的流,另一种可以接受一个“Comparator”) #: <syntaxhighlight lang="java"> Stream<String> longestFirst = words.stream().sorted(Comparator.comparing(String::1ength).reversed()); </syntaxhighlight> # '''peek''':元素与原来流中的元索相同,但是在每次获取一个元素时,都会调用一个函数。 #:(对于调试可以让peek调用一个设置断点的方法。) #: <syntaxhighlight lang="java"> Object[] powers= Stream.iterate(l.O, p -> p * 2).peek(e -> System.out.println("Fetching" + e)).1imit(20).toArray(); // 当实际访问一个元素时,就会打印出来一条消息。 </syntaxhighlight> ==== 相关方法 ==== java.util.stream.Stream 8 * Stream<T> distinct() *: 产生一个流,包含当前流中所有不同的元素。 * Stream<T> sorted() * Stream<T> sorted(Comparator<? super T> comparator) *: 产生一个流,它的元素是当前流中的所有元素按照顺序排列的。第一个方法要求元素是实现了 Comparable 的类的实例。 * Stream<T> peek(Consumer<? super T> action) *: 产生一个流,它与当前流中的元素相同,在获取其中每个元素时,会将其传递给action。 == 流的终止操作 == 流的终止操作:即从流数据中获得答案。 === 简单约简 === 约简是一种终结操作(tennjnal operation), 它们会将流约简为可以在程序中使用的非流值。<br/> * 这些方法返回的是一个类型“Optional<T>”的值,它要么在其中包装了答案,要么表示没有任何值(因为流碰巧为空)。 常用的简单约简: # “'''count'''”方法,会返回流中元素的数量; # “'''max'''”、“'''min'''”方法,会返回流中元素的最大值和最小值; #: <syntaxhighlight lang="java"> Optional<String> largest = words.max(String::compareToignoreCase); System.out.println("largest: " + largest.orElse("")); </syntaxhighlight> # “'''findFirst'''”方法,返回的是非空集合中的第一个值; #:(通常会在与filter 组合使用时显得很有用) #: <syntaxhighlight lang="java"> Optional<String> startsWithQ = words.filter(s -> s.startsWith("Q")).findFirst(); // 找到第一个以字母Q 开头的单词 </syntaxhighlight> # “'''findAny'''”方法,返回的是非空集合中的任意匹配值; #: <syntaxhighlight lang="java"> Optional<String> startsWithQ = words.parallel().filter(s -> s.startsWith("Q")).findAny(); </syntaxhighlight> # “'''anyMatch'''”方法,只返回是否存在匹配; #:(这个方法会接受一个断言引元Predicate,因此不需要使用filter) #: <syntaxhighlight lang="java"> boolean aWordStartsWithQ = words.parallel().anyMatch(s -> s.startsWith("Q")); </syntaxhighlight> # “'''allMatch'''”方法,在所有元素匹配断言的情况下返回true; # “'''noneMatch'''”方法,在没有任何元素匹配断言的情况下返回true; === Optional 类型 === Optional<T> 对象是一种包装器对象,要么包装了类型T 的对象,要么没有包装任何对象。 * Optional<T> 类型被当作一种更安全的方式,用来替代类型T 的引用,这种引用要么引用某个对象,要么为null。 ==== 如何使用Optional值 ==== 使用Optional 的关键: # 在值不存在的情况下会产生一个可替代物; #: <syntaxhighlight lang="java"> // 在没有任何匹配时:使用某种默认值,可能是空字符串: String result= optionalString.orElse('"'); // The wrapped string, or "" if none // 调用代码来计算默认值: String result= optionalString.orElseGet(() -> Locale.getDefault().getDisplayName()); // The function is only called when needed // 在没有任何值时抛出异常: String resu 1t = opti ona 1 String. orEl se Throw(Illega1StateException::new); // Supply a method that yi e 1 ds an exception object </syntaxhighlight> # 在值存在的情况下才会使用这个值。 #* “'''ifPresent'''”方法:接受一个函数。如果该可选值存在,那么它会被传递给该函数。否则不会发生任何事情。 #*:(当调用ifPresent 时,从该函数不会返回任何值。如果想要处理函数的结果,应该使用map) #: <syntaxhighlight lang="java"> // 1、使用ifPresent来调用函数处理optionalValue optionalValue.ifPresent(v -> Process v); // 调用Process处理v // 2、将其添加到某个集中 optionalValue.ifPresent(v -> results.add(v)); optionalValue.ifPresent(results::add); // 或使用函数式接口 // 当调用ifPresent时,从该函数不会返回任何值。如果想要处理函数的结果,应该使用map: Optional<Boo1ean> added = optianalVa1ue.map(results::add); // 现在added 具有三种值之一: // 在optionalValue存在的情况下包装在Optional中的true或false, 以及在optionalValue不存在的情况下的空Optional。 </syntaxhighlight> ===== 相关方法 ===== java.util.Optional 8 * T orElse(T other) *: 产生这个Optional 的值,或者在该Optional 为空时,产生other 。 * T orElseGet(Supplier<? extends T> other) *: 产生这个Optional 的值,或者在该Optional 为空时,产生调用other 的结果。 * <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) *: 产生这个Optional 的值,或者在该Optional 为空时,抛出调用exceptionSupplier的结果。 * void ifPresent(Consumer<? super T> c onsumer) *: 如果该Optional 不为空,那么就将它的值传递给consumer 。 * <nowiki><U> Optiona1<U> map(Function<? super T , ? extends U> mapper)</nowiki> *: 产生将该Optional 的值传递给mapper 后的结果,只要这个Optional 不为空且结果不为null , 否则产生一个空Optional 。 ==== 不适合使用Optional值的方式 ==== 【???】 <pre> 如果没有正确地使用Optional 值,那么相比较以往的得到“某物或null”的方式,你并没有得到任何好处。 get 方法会在Optional 值存在的情况下获得其中包装的元素,或者在不存在的情况下抛出一个NoSuchElementException 对象。因此, Optional <T> optionalValue = ...; optionalValue.get().someMethod(); 并不比下面的方式更安全: T value = ...; va1ue.someMethod(); isPresent 方法会报告某个Optional<T> 对象是否具有一个值。但是 if (optionalVa1ue.isPresent()) optionalValue.get().someMethod(); 并不比下面的方式更容易处理: if (value != null) value.someMethod(); </pre> ===== 相关方法 ===== * T get() *: 产生这个Optional 的值,或者在该Optional 为空时, 抛出一个NoSuchElementException对象。 * boolean isPresent() *: 如果该Optional 不为空,则返回true 。 ==== 创建Optional 值 ==== 有多个方法可以创建Optional 对象: # “Optional.of(result)” # “Optional.empty()” # “Optional.ofNullable(obj)”:在obj 不为null 的情况下返回“Optional.of(obj)”, 否则会返回“Optional.empty()”。 #: <syntaxhighlight lang="java"> public static Optional<Double> inverse(Double x) { return x = 0 ? Optional.empty() : Optional.of(l / x); } </syntaxhighlight> ===== 相关方法 ===== java.util.Optional 8 * static <T> Optional<T> of(T value) * static <T> Optional<T> ofNullable(T value) *: 产生一个具有给定值的Optional 。如果value 为nul1, 那么第一个方法会抛出一个NullPointerException 对象, 而第二个方法会产生一个空Optional 。 * static <T> Optional<T> empty() *: 产生一个空Optional 。 ==== 用flatMap 来构建Optional值的函数 ==== *(类比于“stream.flatMap()”) “ptional.flatMap()”用来将流计算过程中的方法连接起来: <pre> 假设你有一个可以产生Optional<T> 对象的方法f, 并且目标类型T 具有一个可以产生Optional<U> 对象的方法g。如果它们都是普通的方法,那么你可以通过调用“s.f().g()”来将它们组合起来。 但是这种组合没法工作,因为“s.f()”的类型为Optional<T>, 而不是T。因此,需要调用: Optional<U> result= s.f().flatMap(T::g); 如果s.f() 的值存在,那么g 就可以应用到它上面。否则,就会返回一个空Optional<U> 。 很明显,如果有更多的可以产生Optional 值的方法或Lambda 表达式,那么就可以重复此过程。 </pre> 可以直接将对flatMap 的调用链接起来,从而构建由这些步骤构成的管道,只有所有步骤都成功时,该管道才会成功。 <syntaxhighlight lang="java"> public static Optional<Double> squareRoot(Double x) { return x<0 ? Optional.empty() : Optional.of(Math.sqrt(x)); } // 计算倒数的平方根: Optional<Double> result = inverse(x).flatMap(MyMath::squareRoot); // 或者,你可以选择下面的方式: Optional<Double> result = Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot); </syntaxhighlight> ===== 相关方法 ===== java.util.Optional 8 * <nowiki><U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)</nowiki> *: 产生将mapper 应用千当前的Optional 值所产生的结果,或者在当前Optional 为空时,返回一个空Optional 。 === 收集结果 === 当处理完流之后,通常会想要查看、收集其元素。 查看元素: # 调用“'''iterator'''”方法,它会产生可以用来访问元素的旧式风格的迭代器。 # 调用“'''forEach'''”方法,将某个函数应用于每个元素: #* 在并行流上,forEach会以任意顺序遍历各个元索; #* 如果想要按照流中的顺序来处理它们,可以调用“'''forEachOrdered'''”方法(会丧失并行处理的部分甚至全部优势); #: <syntaxhighlight lang="java"> stream.forEach(System.out::println); </syntaxhighlight> 收集元素: # “'''stream.toArray()'''”:收集到数组中: #*(如果想要让数组具有正确的类型,可以将其传递到数组构造器中) #: <syntaxhighlight lang="java"> // 1、“stream.toArray()”:会返回一个Object[]数组; String[] result = stream.toArray(); // 2、使用构造器,使数组有正确的类型 String[] result = stream.toArray(String[]::new); // stream.toArray() has type Object[] </syntaxhighlight> # “'''stream.collect()'''”:收集到其他目标中; #* 该方法接受—个“Collector”接口的实例(Collectors类提供了大扯用于生成公共收集器的工厂方法); ## 收集到列表或集: ##: <syntaxhighlight lang="java"> List<String> resu1t = stream.co11ect(Co11ectors, toList()); 或 Set<String> result = stream.collect(Collectors.toSet()); </syntaxhighlight> ## 控制获得的集的种类: ##: <syntaxhighlight lang="java"> TreeSet<String> result = stream.collect(Co11ectors.toCo11ection(TreeSet::new)) ; </syntaxhighlight> ## 通过连接操作来收集流中的所有字符串: ##: <syntaxhighlight lang="java"> String result= stream.collect(Collectors.joining()); </syntaxhighlight> ## 在元素之间增加分隔符,可以将分隔符传递给joining 方法: ##: <syntaxhighlight lang="java"> String result= stream.collect(Collectors.joining(", ")); </syntaxhighlight> ## 如果流中包含除字符串以外的其他对象,那么我们需要现将其转换为字符串: ##: <syntaxhighlight lang="java"> String result = stream.map(Object::toString).collect(Collectors.joining(", ")); </syntaxhighlight> ## 如果想要将流的结果约简为总和、平均值、最大值或最小值,可以使用“summarizing(IntlLonglDouble)”方法中的某一个。 ##*(这些方法会接受一个将流对象映射为数据的函数,同时,这些方法会产生类型为“(Int|Long|Double)SummaryStatistics”的结果,同时计算总和、数最、平均值、最小值和最大值。) ##: <syntaxhighlight lang="java"> IntSummaryStatistics summary = stream.co11ect(Co11ectors.summarizingInt(String::length)); double averageWordLength = summary.getAverage(); double maxWordLength = summary.getMax(); </syntaxhighlight> ==== 相关方法 ==== java.util.stream.BaseStream 8 * Iterator<T> iterator( ) *: 产生一个用于获取当前流中各个元素的迭代器。这是一种终结操作。 java.util.slream.Stream 8 * void forEach(Consumer<? super T> action) *: 在流的每个元素上砌用action 。这是一种终结操作。 * Object[ J toArray() * <A> A[] toArray(IntFunction<A[]> generator) *: 产生一个对象数组,或者在将引用A[]::new 传递给构造器时,返回一个A 类型的数组。这些操作都是终结操作。 * <R ,A> R collect(Collector<? super T,A,R> collector) *: 使用给定的收集器来收集当前流中的元素。Collectors 类有用于多种收集器的T厂方法。 java.util.stream.Collectors 8 * static <T> Coll ector<T,?, Li st<T»tol i st() * static <T> Collector<T,? , Set<T»toSet() *: 产生一个将元素收集到列表或集中的收集器。 * static <T,C extends Collection<T>> Collector<T,?,C> toCollection(Supplier<C> collectionFactory) *: 产生一个将元素收集到任意集合中的收集器。可以传递一个诸如TreeSet::new 的构造器引用。 * static Collector<CharSequence,?,String> joining() * static Coll ector<CharSequence,?, String> joining(CharSequence delimiter) * static Coll ector<CharSequence,?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) *: 产生一个连接字符串的收集器。分隔符会翌于字符串之间,而第一个字符串之前可以有前缀,最后一个字符串之后可以有后缀。如果没有指定,那么它们都为空。 * static <T> Coll ector<T,?, IntSumnaryStati sties> sumnari zi ngInt(TolntFunction<? super T> mapper) * stat i c<T> Coll ector<T,?, LongSummaryStat i st i cs> summarizingLong(TolongFunction<? superT> mapper) * static <T> Collector<T,?,DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) *: 产生能够生成(IntlLonglDouble)SummaryStatistics 对象的收集器,通过它可以获得将mapper 应用千每个元素后所产生的结果的个数、总和、平均值、最大值和最小值。 lntSummaryStatistics 8 LongSummaryStatistics 8 DoubleSummaryStatistics 8 * long getCount () *: 产生汇总后的元素的个数。 * (intllongldouble) getSum() * double getAverage() *: 产生汇总后的元素的总和或平均值,或者在没有任何元素时返回0 。 * (int 11 ong I double) getMax () * (intllongldouble) getMin() *: 产生汇总后的元素的最大值和最小值,或者在没有任何元素时,产生(Integer|Long|Double).(MAXI MIN)_VALUE。 === 收集到映射表中 === === 群组和分区 === == 其他 == === 下游收集器 === === 约简操作 === === 基本类型流 === === 并行流 ===
返回至“
核心技术Ⅱ:流
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
大陆简体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
笔记
服务器
数据库
后端
前端
工具
《To do list》
日常
阅读
电影
摄影
其他
Software
Windows
WIKIOE
所有分类
所有页面
侧边栏
站点日志
工具
链入页面
相关更改
特殊页面
页面信息