在 Java8 中,limit 和 concat 是 Stream API 中两个非常有用的方法,它们分别用于限制流中元素的数量和合并两个流。
提取子流即从一个流中截取返回流中的部分元素。如果要实现提取流前 n 个元素,需要使用 limit 方法;如果要实现分页功能,则需要使用 limit 和 skip 方法。
Stream.limit(n) 方法用于限制流中元素的数量,即只取前 n 个元素,并返回一个新的流。这个方法特别适用于裁剪指定长度的流。
注意:
当 n<0 时,抛IllegalArgumentException异常。
当 n=0 时,不取元素,返回空流。
当 0<n<length 时,取前n个元素,返回新的流。
当 n>=length 时,取所有元素,相当于原封不动地返回原流。
方法定义:
Stream<T> limit(long maxSize)
例如:
package com.hxstrive.jdk8.stream_api; import java.util.ArrayList; import java.util.List; /** * limit 方法 * @author hxstrive.com */ public class StreamLimitDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); // 返回流前 2 个元素,并输出这些元素 list.stream().limit(2).forEach(System.out::println); //输出: //one //two } }
在 Java8 的 Stream API 中,而 Sream.skip(n) 与 Stream.limit(n) 正好相反。skip 方法是一个中间操作,用于跳过流中的前 N 个元素,并返回一个新的流,其中不包含这些被跳过的元素。
方法定义:
Stream<T> skip(long n)
示例:
package com.hxstrive.jdk8.stream_api; import java.util.ArrayList; import java.util.List; /** * skip 方法 * @author hxstrive.com */ public class StreamSkipDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); // 跳过流前 2 个元素,并输出这些元素 list.stream().skip(2).forEach(System.out::println); //输出: //three } }
注意:
如果 n 是一个负数,则 skip 方法会抛出 IllegalArgumentException。
如果原始流的长度小于 n,则 skip 方法将返回一个空的流(不包含任何元素)。
skip 方法返回的流与原始流具有相同的元素类型。
skip 是一个中间操作,它不会立即执行任何计算。要触发流的执行,你需要调用一个终端操作,如 collect、forEach、count 等。
与 Stream API 的其他方法一样,skip 方法本身不是线程安全的。如果你在多线程环境中共享 Stream,并尝试对其进行 skip 操作,可能会遇到并发问题。
组合流是将多个流连接到一起,组合成一个流。
在 Java8 的 Stream API 中,可以通过 Stream 的静态方法 concat 实现将两个流连接在一起。concat 方法用于将两个流合并成一个流。合并后的流包含原始流中所有元素,且保持原始流的顺序。
方法定义:
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
注意:在重复连接构建流时要小心,访问深度级联的流的元素可能导致 StackOverflowException 。
例如:
package com.hxstrive.jdk8.stream_api; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * concat 方法 * @author hxstrive.com */ public class StreamConcatDemo { public static void main(String[] args) { List<String> list1 = Arrays.asList("a", "b", "c"); List<String> list2 = Arrays.asList("e", "f", "g"); Stream<String> stream = Stream.concat(list1.stream(), list2.stream()); System.out.println(stream.collect(Collectors.toList())); //输出: //[a, b, c, e, f, g] } }
注意:
concat 方法只能用于两个流的合并,不能用于多个流的合并。如果需要合并多个流,请使用 flatMap 方法。
合并后的流的元素顺序和原始流的元素顺序相同。
如果原始流是无限流,合并后的流也将是无限流。
如果你有一个流的流(即 Stream<Stream<T>>),你可以使用 flatMap 来将它们合并成一个流。flatMap 接受一个 Function 函数式接口作为参数,该函数将每个元素映射为一个流,然后将这些流中的所有元素合并成一个流。
方法定义:
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
例如:
下面示例将 List<List<String>> 转换成一个字符串流,如下:
package com.hxstrive.jdk8.stream_api; import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; /** * flatMap 方法 * @author hxstrive.com */ public class StreamFlatMapDemo2 { public static void main(String[] args) { List<List<String>> list = Arrays.asList( Arrays.asList("apple", "banana", "cherry"), Arrays.asList("dog", "elephant", "fox")); Stream<List<String>> stream = list.stream(); // 传统匿名函数方式 Stream<String> newStream = stream.flatMap(new Function<List<String>, Stream<String>>() { @Override public Stream<String> apply(List<String> strings) { return strings.stream(); } }); System.out.println(newStream.collect(Collectors.toList())); // lambda 表达式方式 newStream = list.stream().flatMap(e -> { return e.stream(); }); System.out.println(newStream.collect(Collectors.toList())); //输出: //[apple, banana, cherry, dog, elephant, fox] //[apple, banana, cherry, dog, elephant, fox] } }