Java8 新特性之 Stream 常用方法总结

Stream

当我们在需要对集合中的元素进行操作的时候,除了必需的添加,删除,获取外,最典型的就是遍历数组了

public static void main(String[] args) {
  List<String> list = Arrays.asList("AAA","ABB","As","CC","DD");

  // 获取所有以 A 开头的数据
  List<String> list1 = new ArrayList<>();
  for (String s : list) {
    if(s.startsWith("A")){
      list1.add(s);
    }
  }

  List<String> list2 = new ArrayList<>();
  // 获取长度为 3 的数据
  for (String s : list1) {
    if (s.length() == 3) {
      list2.add(s);
    }
  }
  for (String s : list2) {
    System.out.println(s);
  }
}

以上代码可以看出有很多的循环,只要有了不同的需求,就需要进行一遍循环,是很繁琐的,因此,通过 JDK8 新特性的stream流可以解决这个问题。

Stream 更加优雅的代码解决方案

public static void main(String[] args) {
  List<String> list = Arrays.asList("AAA","ABB","As","CC","DD");

  // 获取所有以 A 开头的数据
  // 获取长度为 3 的数据
  list.stream()
          .filter(s -> s.startsWith("A"))
          .filter(s -> s.length() == 3)
          .forEach(System.out::println);
}

以上代码含义:获取流,过滤“A”,过滤长度,逐一打印。代码相比于上面的案例更加简介直观

1. Stream流式思想概述

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fn4gKmnO-1634008524745)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011160711052.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OulnHAHm-1634008524748)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011160727728.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RgN3M35B-1634008524750)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011160738570.png)]

Stream API 可以让我们快速完成许多复制的操作,如筛选,切片,映射,查找,去重复,统计,匹配和归约

2. Stream流的获取方式

2.1 根据Collection获取

首先, java.util.Collection 接口中加入了 defatult 方法 Stream,也就是说 Collection 接口下的所有的实现都可以通过 stream 方法来获取 Stream 流。

public static void main(String[] args) {
  List<String> list = Arrays.asList("AAA","ABB","As","CC","DD");
  list.stream();

  Set<String> set = new HashSet<>();
  set.stream();

  Vector vector = new Vector();
  vector.stream();
}

对于集合 Map 接口没有实现 Collection 接口,那么,我们可以根据 Map 获取对应的 key 和 value 的集合

2.2 通过 Stream 的 of 方法

在实际开发中我们不可避免的还是会操作到数组中的数据,由于数组对象不可能添加默认方法,所有Stream接口中提供了静态方法 of

public static void main(String[] args) {
  Stream<String> a1 = Stream.of("a1", "a2", "a3");
  String[] arr1 = {"aa","bb","cc"};
  Stream<String> arr11 = Stream.of(arr1);
  Integer[] arr2 = {1,2,3,4};
  Stream<Integer> arr21 = Stream.of(arr2);
  arr21.forEach(System.out::println);

  // 注意:基本数据类型的数组是不会将其中的元素一个一个给打印出来的
  int[] arr3 = {1,2,3,4};
  Stream.of(arr3).forEach(System.out::println);
}

3. Stream 常用方法

3.1 forEach —— 终结方法

forEach 用来遍历流中的数据的

void forEach(Consumer<? super T> action);

该方法接受一个 Consumer 接口,会将每一个流元素交给函数处理

public static void main(String[] args) {
  Stream.of("aa","bb","cc","dd").forEach(System.out::println);
}

3.2 count —— 终结方法

Stream流中的 count 方法用来统计其中的元素个数的

long count();

该方法返回一个 long 值,代表元素的个数

long count = Stream.of("aa", "bb", "cc", "dd").count();
System.out.println(count);

3.3 filter

filter 方法的作用是用来过滤数据数据的。返回符合条件的数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zaZDuJJr-1634008524752)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011171340994.png)]

可以通过filter方法将一个流转换成另一个子集流

Stream<T> filter(Predicate<? super T> predicate);

该接口接收一个 Predicate 函数式接口参数作为筛选条件

Stream.of("a1","a2","a3","s","sa","d","f","cc","xx")
        .filter(s -> s.contains("a"))
        .forEach(System.out::println);

输出:

a1
a2
a3
sa

3.4 limit

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z63wMhx6-1634008524754)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011171927940.png)]

limit 方法可以对流进行截取处理,只取前 n 个数据

Stream<T> limit(long maxSize);

参数是一个 long 类型的数值,如果集合当前长度大于参数就进行截取,否则不进行操作

Stream.of("a1","a2","a3","s","sa","d","f","cc","xx")
        .limit(3)
        .forEach(System.out::println);

输出

a1
a2
a3

3.5 skip

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eM8zUyRy-1634008524754)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011172252849.png)]

如果希望跳过前面几个元素,可以使用 skip 方法获取一个截取之后的新流

Stream<T> skip(long n);

操作:

Stream.of("a1","a2","a3","s","sa","d","f","cc","xx")
        .skip(3)
        .forEach(System.out::println);

输出:

s
sa
d
f
cc
xx

3.6 map

如果我们需要将流中的元素映射到另一个流中,可以使用 map 方法

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQNgXCTc-1634008524756)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011173934032.png)]

该接口需要一个Function函数式接口参数,可以将当前流中的 T 类型数据转换成另一种 R 类型的数据

Stream.of("1","2","3","4","5","6","7")
        .map(Integer::parseInt)
        .forEach(System.out::println);

3.7 sorted

如果需要将数据排序,可以使用 sorted 这个方法

Stream<T> sorted();

在使用的时候可以根据自然规则排序,也可以通过比较来指定对应的排序规则

Stream.of("1","3","2","0","9","4","7")
        .map(Integer::parseInt)
        .sorted() // 根据数据日然顺序排序
        .sorted((o1,o2) -> 02 - o1)
        .forEach(System.out::println);

3.8 distinct

如果要去掉重复的数据,可以使用该方法

Stream<T> distinct();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w23fHmMv-1634008524757)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211011174430756.png)]

使用

Stream.of("1","3","2","2","7","4","7")
        .map(Integer::parseInt)
        .sorted() // 根据数据日然顺序排序
        .sorted((o1,o2) -> 02 - o1)
        .distinct()
        .forEach(System.out::println);

Stream.of(
        new Person("张三",18),
        new Person("李四",22),
        new Person("张三",18)
).distinct()
        .forEach(System.out::println);

Stream 流中的 distinct 基本数据类型是可以直接去重的,但是自定义数据类型,我们需要重写 hashCodeequals 方法来进行去重

3.9 match

anyMatch、allMatch、noneMatch

anyMatch 表示判断的条件里,任意一个元素成功,返回 true

allMatch 表示判断里的元素,所有的都是,返回 true

noneMatch 跟 allMatch 相反,判断条件里的元素,所有的都不是,返回 true

List<String> strs = Arrays.asList("a", "a", "a", "a", "b");
boolean aa = strs.stream().anyMatch(str -> str.equals("a"));
boolean bb = strs.stream().allMatch(str -> str.equals("a"));
boolean cc = strs.stream().noneMatch(str -> str.equals("a"));
long count = strs.stream().filter(str -> str.equals("a")).count();
System.out.println(aa);// TRUE
System.out.println(bb);// FALSE
System.out.println(cc);// FALSE
System.out.println(count);// 4

3.10 find

findFirst、findAny

findFirst:返回列表中的第一个元素。

findAny:返回的元素是不确定的,对于同一个列表多次调用 findAny() 有可能会返回不同的值。使用 findAny() 是为了更高效的性能。如果是数据较少,串行的情况下,一般会返回第一个结果,如果是并行的情况,那就不能确保是第一个。

List<String> lst1 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
List<String> lst2 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
 
Optional<String> findFirst = lst1.parallelStream().filter(s -> s.startsWith("D")).findFirst();
Optional<String> fidnAny = lst2.parallelStream().filter(s -> s.startsWith("J")).findAny();
 
System.out.println(findFirst.get()); //总是打印出David
System.out.println(fidnAny.get()); //会随机地打印出Jack/Jill/Julia

3.11 max 和 min

max
Optional<Person> max = Stream.of(
        new Person("aa", 77),
        new Person("bb", 66),
        new Person("cc", 55),
        new Person("dd", 44),
        new Person("eef", 33),
        new Person("ff", 22)
).max(Comparator.comparingInt(Person::getAge));
System.out.println(max);
max.ifPresent(s -> System.out.println(s.getAge()));

// 结果
Optional[Person{name='aa', age=77}]
77
min
Optional<Person> max = Stream.of(
        new Person("aa", 77),
        new Person("bb", 66),
        new Person("cc", 55),
        new Person("dd", 44),
        new Person("eef", 33),
        new Person("ff", 22)
).min(Comparator.comparingInt(Person::getAge));
System.out.println(max);
max.ifPresent(s -> System.out.println(s.getAge()));

// 结果
Optional[Person{name='ff', age=22}]
22

3.12 reduce 方法

如果需要将所有数据归纳得到又给数据,可以使用 reduce 方法

T reduce(T identity, BinaryOperator)

使用:

public static void main(String[] args) {
  Integer sum = Stream.of(3,4,5,9)
          // identity 默认值
          // 第一次的时候会将默认值赋值给 x
          // 之后每次会将 上一次的操作结果赋值给x  y就是每次从数据中获取的元素
          .reduce(0, (x, y) -> {
            return x + y;
          });
  System.out.println(sum);

  // 获取最大值
  Integer max = Stream.of(4,5,3,9)
          .reduce(0, (x, y) -> {
            return x > y? x : y;
          });
  System.out.println(max);
}

3.13 map 和 reduce 的组合

Integer sum = Stream.of(3,4,5,9)
        // identity 默认值
        // 第一次的时候会将默认值赋值给 x
        // 之后每次会将 上一次的操作结果赋值给x  y就是每次从数据中获取的元素
        .reduce(0, (x, y) -> x + y);
System.out.println(sum);

// 获取最大值
Integer max = Stream.of(4,5,3,9)
        .reduce(0, (x, y) -> x > y? x : y);
System.out.println(max);


Integer sumAge = Stream.of(
        new Person("aa", 22),
        new Person("bb", 32),
        new Person("cc", 12),
        new Person("dd", 56),
        new Person("ee", 43)
).map(Person::getAge)
        .reduce(0, Integer::sum);
System.out.println(sumAge);

// 求年龄的最大值
Integer maxAge = Stream.of(
        new Person("aa", 22),
        new Person("bb", 32),
        new Person("cc", 12),
        new Person("dd", 56),
        new Person("ee", 43)
).map(Person::getAge)
        .reduce(0, Math::max);
System.out.println(maxAge);

Integer count = Stream.of("a", "b", "c", "d").map(ch -> "a".equals(ch) ? 1 : 0)
        .reduce(0, Integer::sum);
System.out.println(count);

3.14 mapToInt

如果需要将 Stream 中的 Integer 类型转换成 int 类型,可以使用 mapToInt 方法来实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ko3ywFDy-1634008524757)(C:\Users\李祥鸿\AppData\Roaming\Typora\typora-user-images\image-20211012090712356.png)]

使用

// Integer 占用的内存比 int 多很多,在 Stream 流操作中会自动装修和拆箱操作
Integer arr[] = {1,2,3,5,6,8};
Stream.of(arr)
        .filter(i -> i > 0)
        .forEach(System.out::println);
System.out.println("----------------");
// 为了提高程序代码的效率,我们可以先将流中的 Integer 数据转换为 int 数据,然后再操作
IntStream intStream = Stream.of(arr)
        .mapToInt(Integer::intValue);
intStream.filter(i -> i > 3)
        .forEach(System.out::println);

3.15 concat

如果有两个流希望合并成一个流,那么可以使用 Stream 接口的静态方法 concat

使用:

Stream<String> stream1 = Stream.of("a","b","c");
Stream<String> stream2 = Stream.of("x","y","z");
// 通过 concat 方法将两个流合并为一个新的流
Stream.concat(stream1, stream2).forEach(System.out::println);
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值