在 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]
}
}