为了账号安全,请及时绑定邮箱和手机立即绑定

如果流中的流为空,如何记录消息?

如果流中的流为空,如何记录消息?

Helenr 2023-03-17 15:03:48
给定以下 Java 8 流:scheduleService.list().stream()                      .filter(Schedule::getEnabled)                      .filter(this::runnable)                      .flatMap(s -> s.getJobs().stream())                      // .doSomethingArbitrary(System.out.println("A single message. The total number of                       // elements in the stream after filtering is " + this::count))                      .forEach(this::invoke);在对流应用过滤并应用第一个终端操作之后,如果流为空,我想记录一条调试消息,如果不是,我想在流中的每个元素上调用该方法invoke。这可能吗?
查看完整描述

4 回答

?
暮色呼如

TA贡献1853条经验 获得超9个赞

您可以创建自定义Collector(此处称为StreamInterceptor),即使这并不真正符合收藏家的目的。


自定义收集器将做什么?

  1. 转换Stream<T>List<T>

  2. 调用 Consumer<List>,在您的情况下它将打印列表的长度。

  3. 返回一个新Stream<T>List<T>

主要方法

在这里,我刚刚将您的问题分解为过滤一个简单的字符串列表,并在最后将它们打印到控制台。

    public static void main(String[] args) {

        List<String> myList = List.of("first", "second", "third");

        myList.stream()

                .filter(string -> !string.equals("second"))

                .collect(printCount())

                .forEach(System.out::println);

    }


    /**

     * Creates a StreamInterceptor, which will print the length of the stream 

     */

    private static <T> StreamInterceptor<T> printCount() {

        Consumer<List<T>> listSizePrinter = list -> System.out.println("Stream has " + list.size() + " elements");

        return new StreamInterceptor<>(listSizePrinter);

    }

初始化时,StreamInterceptor您可以定义一个消费者,它接收从流构造的中间列表并对其执行一些操作。在您的情况下,它只会打印列表的大小。


新StreamInterceptor班级

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import java.util.Set;

import java.util.function.*;

import java.util.stream.Collector;

import java.util.stream.Stream;


class StreamInterceptor<T> implements Collector<T, List<T>, Stream<T>> {


    private final Consumer<List<T>> listConsumer;


    public StreamInterceptor(Consumer<List<T>> listConsumer) {

        this.listConsumer = listConsumer;

    }


    @Override

    public Supplier<List<T>> supplier() {

        return ArrayList::new;

    }


    @Override

    public BiConsumer<List<T>, T> accumulator() {

        return List::add;

    }


    @Override

    public BinaryOperator<List<T>> combiner() {

        return (list1, list2) -> {

            list1.addAll(list2);

            return list1;

        };

    }


    @Override

    public Function<List<T>, Stream<T>> finisher() {

        return list -> {

            listConsumer.accept(list);

            return list.stream();

        };

    }


    @Override

    public Set<Characteristics> characteristics() {

        return Collections.emptySet();

    }

}



查看完整回答
反对 回复 2023-03-17
?
婷婷同学_

TA贡献1844条经验 获得超8个赞

您可以peek在将列表转换为stream.


public static void main(String[] args) {

    Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5), Collections.emptyList())

            .filter(x -> x.size() % 2 == 0)

            .peek(s -> System.out.println(s.isEmpty()))

            .flatMap(Collection::stream)

            .forEach(System.out::println);

}

输出


false

4

5

true


查看完整回答
反对 回复 2023-03-17
?
富国沪深

TA贡献1790条经验 获得超9个赞

这根本不是真正的“好”,但您可以使用 peek 查看您的流并设置一个 AtomicBoolean:


AtomicBoolean empty = new AtomicBoolean(true);


scheduleService.list().stream()

                      .filter(Schedule::getEnabled)

                      .filter(this::runnable)

                      .flatMap(s -> s.getJobs().stream())

                      .peek(s -> ab.set(false);)

                      .forEach(this::invoke);


if(empty.get()){

   // is Empty

}


查看完整回答
反对 回复 2023-03-17
?
千万里不及你

TA贡献1784条经验 获得超9个赞

您可以将您包装Stream成如下所示的自定义方法


Stream<???> stream = scheduleService.list().stream()

                                           .filter(Schedule::getEnabled)

                                           .filter(this::runnable)

                                           .flatMap(s -> s.getJobs().stream());


forEachOrElse(stream, this::invoke, () -> System.out.println("The stream was empty"));

随着forEachOrElse存在


public <T> void forEachOrElse(Stream<T> inStream, Consumer<T> consumer, Runnable orElse) {

    AtomicBoolean wasEmpty = new AtomicBoolean(true);

    inStream.forEach(e -> {

        wasEmpty.set(false);

        consumer.accept(e);

    });


    if (wasEmpty.get())

        orElse.run();

}

我现在无法测试它,但它应该会发挥它的魔力


查看完整回答
反对 回复 2023-03-17
  • 4 回答
  • 0 关注
  • 122 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信