Stream流常用操作
1. forEach
forEach 用来遍历流中的数据。
void forEach(Consumer<? super T> action);
// Consumer接口中的抽象方法
void accept(T t);
该方法接收一个 Consumer 接口函数,会将每一个流元素交给该函数进行处理。基本使用:
@Test
public void testForEach() {
List<String> one = new ArrayList<>();
Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
// Lambda可以转成方法引用
one.stream().forEach(System.out::println);
}
2. count
Stream流提供 count 方法来统计其中的元素个数。
long count();
该方法返回一个long值代表元素个数。基本使用:
@Test
public void testCount() {
List<String> one = new ArrayList<>();
Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
long count = one.stream().count();
System.out.println(count);
}
3. filter
filter用于过滤数据,返回符合过滤条件的数据。
Stream<T> filter(Predicate<? super T> predicate);
// Predicate接口中的抽象方法
boolean test(T t);
该接口接收一个 Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件。基本使用:
@Test
public void testFilter() {
List<String> one = new ArrayList<>();
Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
// 得到名字长度为3个字的人(过滤)
one.stream().filter(s -> s.length() == 3).forEach(System.out::println);
}
4. limit
limit 方法可以对流进行截取,只取用前n个。
Stream<T> limit(long maxSize);
参数是一个long型,如果集合当前长度大于参数则进行截取。否则不进行操作。基本使用:
@Test
public void testLimit() {
List<String> one = new ArrayList<>();
Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
// 获取前3个数据
one.stream()
.limit(3)
.forEach(System.out::println);
}
5. skip
如果希望跳过前几个元素,可以使用 skip 方法获取一个截取之后的新流。
Stream<T> skip(long n);
如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。基本使用:
@Test
public void testSkip() {
List<String> one = new ArrayList<>();
Collections.addAll(one, "迪丽热巴", "宋远桥", "苏星河", "老子", "庄子", "孙子");
// 跳过前两个数据
one.stream()
.skip(2)
.forEach(System.out::println);
}
6. map
如果需要将流中的元素映射到另一个流中,可以使用 map 方法。方法签名:
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
// Function 接口中抽象方法
R apply(T t);
该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。基本使用:
@Test
public void testMap() {
Stream<String> original = Stream.of("11", "22", "33");
// Map可以将一种类型的流转换成另一种类型的流
// 将Stream流中的字符串转成Integer
// original.map(s -> Integer.parseInt(s)).forEach(System.out::println);
original.map(Integer::parseInt).forEach(System.out::println);
}
7. sorted
如果需要将数据排序,可以使用 sorted 方法。方法签名:
Stream<T> sorted(); // 根据元素的自然顺序排序
Stream<T> sorted(Comparator<? super T> comparator); // 根据比较器指定的规则排序
// 其中Comparator接口中有一个抽象方法
int compare(T o1, T o2);
基本使用:
@Test
public void testSorted() {
// sorted(): 根据元素的自然顺序排序
// sorted(Comparator<? super T> comparator): 根据比较器指定的规则排序
Stream<Integer> stream = Stream.of(33, 22, 11, 55);
// stream.sorted().forEach(System.out::println);
/*stream.sorted((Integer i1, Integer i2) -> {
return i2 - i1;
}).forEach(System.out::println);*/
stream.sorted((i1, i2) -> i2 - i1).forEach(System.out::println); // 55 33 22 11
}
8. distinct
如果需要去除重复数据,可以使用 distinct 方法。方法签名:
Stream<T> distinct();
基本使用1(基本类型去重):
@Test
public void testDistinct() {
Stream<Integer> stream = Stream.of(22, 33, 22, 11, 33);
stream.distinct().forEach(System.out::println);
Stream<String> stream1 = Stream.of("aa", "bb", "aa", "bb", "cc");
stream1.distinct().forEach(System.out::println);
}
基本使用2(自定义类型去重):
@Test
public void testDistinct2() {
Stream<Person> stream = Stream.of(
new Person("貂蝉", 18),
new Person("杨玉环", 20),
new Person("杨玉环", 20),
new Person("西施", 16),
new Person("西施", 16),
new Person("王昭君", 25)
);
stream.distinct().forEach(System.out::println);
}
注: 对于自定义的数据类型,需要重写hashCode和equals方法,否则无法进行去重。
9. match
如果需要判断数据是否匹配指定的条件,可以使用 Match 相关方法。方法签名:
boolean allMatch(Predicate<? super T> predicate); // 匹配所有元素,所有元素都需要满足条件
boolean anyMatch(Predicate<? super T> predicate); // 匹配某个元素,只要有其中一个元素满足条件即可
boolean noneMatch(Predicate<? super T> predicate); // 匹配所有元素,所有元素都不满足条件
// Predicate接口中的抽象方法
boolean test(T t);
基本使用:
@Test
public void testMatch() {
Stream<Integer> stream = Stream.of(5, 3, 6, 1);
// boolean b = stream.allMatch(i -> i > 0); // allMatch: 匹配所有元素,所有元素都需要满足条件
// boolean b = stream.anyMatch(i -> i > 5); // anyMatch: 匹配某个元素,只要有其中一个元素满足条件即可
boolean b = stream.noneMatch(i -> i < 0); // noneMatch: 匹配所有元素,所有元素都不满足条件
System.out.println(b);
}
10. find
如果需要找到某些数据,可以使用 find 相关方法。方法签名:
Optional<T> findFirst();
Optional<T> findAny();
基本使用:
@Test
public void testFind() {
Stream<Integer> stream = Stream.of(33, 11, 22, 5);
// Optional<Integer> first = stream.findFirst();
Optional<Integer> first = stream.findAny();
System.out.println(first.get());
}
11. max、min
如果需要获取最大和最小值,可以使用 max 和 min 方法。方法签名:
Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);
// Comparator接口中的抽象方法
int compare(T o1, T o2);
基本使用:
@Test
public void testMax_Min() {
// 获取最大值
// 1, 3, 5, 6
Optional<Integer> max = Stream.of(5, 3, 6, 1).max((o1, o2) -> o1 - o2);
System.out.println("最大值: " + max.get()); // 最大值: 6
// 获取最小值
// 1, 3, 5, 6
Optional<Integer> min = Stream.of(5, 3, 6, 1).min((o1, o2) -> o1 - o2);
System.out.println("最小值: " + min.get()); // 最小值: 1
}
12. reduce
如果需要将所有数据归纳得到一个数据,可以使用 reduce 方法。方法签名:
T reduce(T identity, BinaryOperator<T> accumulator);
// 其中,BinaryOperator extends BiFunction
// BiFunction接口中有一个抽象方法
R apply(T t, U u);
基本使用:
@Test
public void testReduce() {
// T reduce(T identity, BinaryOperator<T> accumulator);
// T identity: 默认值
// BinaryOperator<T> accumulator: 对数据进行处理的方式
// reduce如何执行?
// 第一次, 将默认值赋值给x, 取出集合第一元素赋值给y
// 第二次, 将上一次返回的结果赋值x, 取出集合第二元素赋值给y
// 第三次, 将上一次返回的结果赋值x, 取出集合第三元素赋值给y
// 第四次, 将上一次返回的结果赋值x, 取出集合第四元素赋值给y
int reduce = Stream.of(4, 5, 3, 9).reduce(0, (x, y) -> {
System.out.println("x = " + x + ", y = " + y);
return x + y;
});
System.out.println("reduce = " + reduce); // 21
// 获取最大值
Integer max = Stream.of(4, 5, 3, 9).reduce(0, (x, y) -> x > y ? x : y);
System.out.println("max = " + max);
}
// 输出结果:
x = 0, y = 4
x = 4, y = 5
x = 9, y = 3
x = 12, y = 9
reduce = 21
max = 9
13. map与reduce组合
基本使用
@Test
public void testMapReduce() {
// 求出所有年龄的总和
// 1.得到所有的年龄
// 2.让年龄相加
Integer totalAge = Stream.of(
new Person("刘德华", 58),
new Person("张学友", 56),
new Person("郭富城", 54),
new Person("黎明", 52))
.map(Person::getAge).reduce(0, Integer::sum);
System.out.println("totalAge = " + totalAge);
// 找出最大年龄
// 1.得到所有的年龄
// 2.获取最大的年龄
Integer maxAge = Stream.of(
new Person("刘德华", 58),
new Person("张学友", 56),
new Person("郭富城", 54),
new Person("黎明", 52))
.map(Person::getAge)
.reduce(0, Math::max);
System.out.println("maxAge = " + maxAge);
// 统计 a 出现的次数
// 1 0 0 1 0 1
Integer count = Stream.of("a", "c", "b", "a", "b", "a")
.map(s -> {
if (s.equals("a")) {
return 1;
} else {
return 0;
}
})
.reduce(0, Integer::sum);
System.out.println("count = " + count);
}
// 输出结果
totalAge = 220
maxAge = 58
count = 3
14. mapToInt
IntStream mapToInt(ToIntFunction<? super T> mapper);
// 其中ToIntFunction中有一个抽象方法
int applyAsInt(T value);
基本使用:
@Test
public void testNumericStream() {
// Integer占用的内存比int多,在Stream流操作中会自动装箱和拆箱
IntStream intStream = Stream.of(1, 2, 3, 4, 5).mapToInt(Integer::intValue);
intStream.filter(n -> n > 3).forEach(System.out::println);
}
// 输出结果
4,5
15. concat
如果有两个流,希望合并成为一个流,那么可以使用 Stream 接口的静态方法 concat:
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
基本使用:
@Test
public void testContact() {
Stream<String> streamA = Stream.of("张三");
Stream<String> streamB = Stream.of("李四");
// 合并成一个流
Stream<String> newStream = Stream.concat(streamA, streamB);
// 注意:合并流之后,不能操作之前的流啦.
// streamA.forEach(System.out::println);
newStream.forEach(System.out::println);
}
// 输出结果:
张三 李四