Java基础之Stream的使用078

1. Stream 的使用

Stream 是什么?

Stream 是数据渠道,用于操作数据源(数组、集合等)所生成的元素序列。

Java8两大最为重要的改变就是 Lambda表达式Stream API,这两种改变的引入带来的是新的抽象方式 (函数式编程),面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象

Stream 是 Java8 中处理集合的关键抽象概念,可以指定对集合进行的操作,可以执行复杂的查找、过滤、映射数据等操作,Stream API 提供了一种高效且易于使用的处理数据的方式。


四个必须要知道的内置函数接口

  1. 消费型接口: Consumer<T> void accept(T t) 有参数,无返回值的抽象方法;
  2. 供给型接口: Supplier <T> T get() 无参有返回值的抽象方法;
  3. 断定型接口: Predicate<T> boolean test(T t) 有参,但是返回值类型是固定的boolean;
  4. 函数型接口: Function<T,R> R apply(T t) 有参有返回值的抽象方法;
// 消费接口定义
Consumer<Student> greeter = (p) -> System.out.println("Hello, " + p.firstName);
// 消费
greeter.accept(new Student("Luke", "Skywalker"));
复制代码
// 供给接口定义
Supplier<Student> supplier = Student::new;
// 供给
supplier.get();
复制代码
// 断定型接口定义
Predicate<String> predicate = (s) -> s.length() > 0;
// 断定
predicate.test("s");              // true
predicate.test("");     // false
复制代码
// 函数型接口定义
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
// 应用
backToString.apply("123");     // "123"
复制代码


Stream 的使用分为三个步骤

  1. 创建Stream (使用数据源可以是集合、数组来获取流)
  2. 中间操作 (对数据源的数据进行处理)
  3. 终止操作 (先执行中间操作产生结果后终止流,之后不能再使用该流)

惰性求值

中间操作不会执行任何的处理,而是在终止操作时一次性全部处理,这就是惰性求值

// 像这样的代码并未做什么实际工作
lists.stream().filter(x -> x != 1)
复制代码
// 像这种有终止操作的代码才会产生新值
List<Integer> list1 = list.parallelStream().filter(x -> x != 1).collect(Collectors.toList());
复制代码

1.1 创建 Stream 的方式

集合创建

  1. 顺序流:使用顺序方式遍历,每个item读完之后再读下一个item
  2. 并行流:使用并行遍历,将数据分为多个段,各个段的数据都在不同线程下处理

在多核计算机的情况下理论上并行流会比顺序流快上一倍左右

① 顺序执行:default Stream<E> stream() 返回一个顺序流

// 将list列表通过stream()生一个流过滤1最后打印
List<Integer> list1 = list.stream().filter(x -> x != 1).collect(Collectors.toList());
复制代码

② 并行执行:default Stream<E> parallelStream() 返回一个并行流

List<Integer> list1 = list.parallelStream().filter(x -> x != 1).collect(Collectors.toList());
复制代码

数组创建

通过Arrays静态方法获取数组流:static <T> Stream<T> stream(T[] array)

// 将array数组通过Arrays的静态方法生一个流过滤1最后打印
Arrays.stream(array).filter(x -> x != 1).forEach(System.out::println);
复制代码

Stream创建

通过调用Stream类的静态方法创建流 (注意后两个生成的是无限流)

① 通过显示值:public static<T> Stream<T> of(T... values)

// 通过显示值1,2,3,4生成一个流过滤掉1最后打印
Stream.of(1,2,3,4).filter(x -> x != 1).forEach(System.out::println);
复制代码

② 通过迭代:public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)

// 从0开始迭代每次加1生成一个无限流通过limit限制前十位最后打印
Stream.iterate(0, x -> x + 1).limit(10).forEach(System.out::println);
复制代码

③ 通过生成:public static<T> Stream<T> generate(Supplier<T> s)

// 通过Math的随机数函数生成一个无限流通过limit限制前五位最后打印
Stream.generate(Math::random).limit(5).forEach(System.out::println);
复制代码

1.2 中间操作

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

接收Lambda,从流中排除某些元素;

List<Integer> list = Arrays.asList(1,2,3,4);

// filter中传入一个判定型接口Predicate过滤掉遍历这个集合是返回false的结果
List<Integer> list1 = list.stream().filter(x -> x != 1).collect(Collectors.toList());

list1.forEach(System.out::print); // 234
复制代码

Stream<T> distinct();

筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素;

List<Integer> nums = Arrays.asList(1,1,2,3,4);
// 去重
nums.stream().distinct().forEach(System.out::print); // 1234
复制代码

Stream<T> limit(long maxSize);

截断流,使其元素不超过给定数量

// 通过Math的随机数函数生成一个无限流通过limit限制前五位最后打印
Stream.generate(Math::random).limit(5).forEach(System.out::println);
复制代码

Stream<T> skip(long n);

跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

List<Integer> nums = Arrays.asList(1,1,2,3,4);
// 去重
nums.stream().skip(2).forEach(System.out::print); // 234
复制代码

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

接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

List<Integer> nums = Arrays.asList(1,1,2,3,4);
// 通过map对每个元素进行类型转换
List<Long> collect = nums.stream().map(Long::valueOf).collect(Collectors.toList());
复制代码

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

接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

// 合并多个流
List<Integer> result= Stream.of(Arrays.asList(1,3),Arrays.asList(5,6)).flatMap(Collection::stream).collect(Collectors.toList());
复制代码

Stream<T> sorted();

产生一个新流,其中按自然顺序排序

List<Integer> nums = Arrays.asList(8,6,7,3);
// 自然排序
nums.stream().sorted().forEach(System.out::print); // 3678
复制代码

Stream<T> sorted(Comparator<? super T> comparator);

产生一个新流,其中按比较器顺序排序

List<Integer> nums = Arrays.asList(8,6,7,3);
// 比较器排序
nums.stream().sorted((x,y) -> (y-x)).forEach(System.out::print); // 8763
复制代码

1.3 终止操作

boolean allMatch(Predicate<? super T> predicate);

检查是否匹配所有元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 检查是否集合里面的元素都等于1
System.out.println(nums.stream().allMatch(x -> x == 1)); // false
复制代码

boolean anyMatch(Predicate<? super T> predicate);

检查是否至少匹配一个元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 检查是否集合里面的元素有等于1的
System.out.println(nums.stream().anyMatch(x -> x == 1)); // true
复制代码

boolean noneMatch(Predicate<? super T> predicate);

检查是否没有匹配所有元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 检查是否集合里面的元素都不等于1
System.out.println(nums.stream().noneMatch(x -> x == 1)); // false
复制代码

Optional<T> findFirst();

返回第一个元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 拿到集合第一个元素用Optional存储可以通过get取出来
System.out.println(nums.stream().findFirst()); // Optional[1]
System.out.println(nums.stream().findFirst()); // 1
复制代码

Optional<T> findAny();

返回当前流中的任意元素

List<Integer> nums = Arrays.asList(1,1,7,3);
// 拿到集合任意元素用Optional存储可以通过get取出来
System.out.println(nums.stream().findFirst()); // Optional[1]
System.out.println(nums.stream().findFirst()); // 1
复制代码

long count();

返回流中元素总数

List<Integer> nums = Arrays.asList(3,7,3);
// 集合大小
System.out.println(nums.stream().count()); // 3
复制代码

Optional<T> max(Comparator<? super T> comparator);

返回流中最大值

List<Integer> nums = Arrays.asList(3,7,3);
// 返回比较器下的最大值用Optional存储通过get取出(注意这里的比较器是从大到小排序)
System.out.println(nums.stream().max((x, y) -> (y - x)).get()); // 3
复制代码

Optional<T> min(Comparator<? super T> comparator);

返回流中最小值

List<Integer> nums = Arrays.asList(3,7,3);
// 返回比较器下的最小值用Optional存储通过get取出(注意这里的比较器是从大到小排序)
System.out.println(nums.stream().min((x, y) -> (y - x)).get()); // 7
复制代码

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

内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代)

List<Integer> nums = Arrays.asList(3,7,3);
// 内部迭代
nums.stream().forEach(System.out::print); // 373
复制代码

Optional<T> reduce(BinaryOperator<T> accumulator);

可以将流中元素反复结合起来,得到一个值。返回 T

List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
// 将集合的值变成double类型并抹个零通过reduce反复结合即相加得到总和
double bill = costBeforeTax.stream().map((cost) -> 0.1 * cost).reduce(Double::sum).get();
System.out.println(bill); // 150.0
复制代码

T reduce(T identity, BinaryOperator<T> accumulator);

可以将流中元素反复结合起来,得到一个值。返回 Optional<T>

double bill = 100.0;
List<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
// 跟上面的比就是多一个初始值在反复结合
bill = costBeforeTax.stream().map((cost) -> 0.1 * cost).reduce(bill, Double::sum);
System.out.println(bill); // 250.0
复制代码

<R, A> R collect(Collector<? super T, A, R> collector);

将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值