简体   繁体   English

从Java 8映射操作返回空元素

[英]Return empty element from Java 8 map operation

Using Java 8 stream what is the best way to map a List<Integer> when you have no output for the input Integer ? 使用Java 8流时,如果没有输入Integer的输出,那么映射List<Integer> 的最佳方法是什么?

Simply return null? 只需返回null? But now my output list size will be smaller than my input size... 但现在我的输出列表大小将小于我的输入大小...

    List<Integer> input = Arrays.asList(0,1,2,3);
    List<Integer> output = input.stream()
                                .map(i -> { 
                                    Integer out = crazyFunction(i);
                                    if(out == null || out.equals(0))
                                        return null;
                                    return Optional.of(out);
                                    })
                                .collect(Collectors.toList());

I don't get why you (and all answers) make it so complicated. 我不明白为什么你(以及所有的答案)让它变得如此复杂。 You have a mapping operation and a filtering operation. 您有映射操作和过滤操作。 So the easiest way is to just apply these operation one after another. 所以最简单的方法就是一个接一个地应用这些操作。 And unless your method already returns an Optional , there is no need to deal with Optional . 除非您的方法已经返回Optional ,否则无需处理Optional

input.stream().map(i -> crazyFunction(i))
              .filter(out -> out!=null && !out.equals(0))
              .collect(Collectors.toList());

It may be simplified to 它可以简化为

input.stream().map(context::crazyFunction)
              .filter(out -> out!=null && !out.equals(0))
              .collect(Collectors.toList());

But you seem to have a more theoretical question about what kind of List to generate, one with placeholders for absent values or one with a different size than the input list. 但是你似乎有更多的理论问题,关于要生成什么类型​​的List ,一个是缺少值的占位符,另一个是与输入列表不同的大小。

The simple answer is: don't generate a list . 简单的答案是: 不生成列表 A List is not an end in itself so you should consider for what kind of operation you need this list (or its contents) and apply the operation right as the terminal operation of the stream. 一个List不是目的本身,所以你应该考虑你需要什么样的操作这个名单(或内容),并申请经营权作为流的终端操作。 Then you have your answer as the operation dictates whether absent values should be filtered out or represented by a special value (and what value that has to be). 然后你得到答案,因为操作规定是否应该过滤掉缺席值或用特殊值表示(以及必须是什么值)。

It might be a different answer for different operations… 对于不同的操作,它可能是一个不同的答案......

Replace the map call with flatMap . flatMap替换map调用。 The map operation produces one output value per input value, whereas the flatMap operation produces any number of output values per input value -- include zero. map操作为每个输入值生成一个输出值,而flatMap操作为每个输入值生成任意数量的输出值 - 包括零。

The most straightforward way is probably to replace the check like so: 最简单的方法可能是更换支票,如下所示:

List<Integer> output = input.stream()
                            .flatMap(i -> { 
                                Integer out = crazyFunction(i);
                                if (out == null || out.equals(0))
                                    return Stream.empty();
                                else
                                    return Stream.of(out);
                                })
                            .collect(Collectors.toList());

A further refactoring could change crazyFunction to have it return an Optional (probably OptionalInt ). 进一步的重构可能会改变crazyFunction以使其返回Optional (可能是OptionalInt )。 If you call it from map , the result is a Stream<OptionalInt> . 如果从map调用它,结果是Stream<OptionalInt> Then you need to flatMap that stream to remove the empty optionals: 然后你需要flatMap该流来删除空的选项:

List<Integer> output = input.stream()
    .map(this::crazyFunctionReturningOptionalInt)
    .flatMap(o -> o.isPresent() ? Stream.of(o.getAsInt()) : Stream.empty())
    .collect(toList());

The result of the flatMap is a Stream<Integer> which boxes up the int s, but this is OK since you're going to send them into a List . flatMap的结果是一个Stream<Integer> ,用于flatMap int ,但是这样就可以了,因为你要将它们发送到List If you weren't going to box the int values into a List , you could convert the Stream<OptionalInt> to an IntStream using the following: 如果您不打算将int值插入List ,则可以使用以下IntStreamStream<OptionalInt>转换为IntStream

flatMapToInt(o -> o.isPresent() ? IntStream.of(o.getAsInt()) : IntStream.empty())

For further discussion of dealing with streams of optionals, see this question and its answers . 有关处理选项流的进一步讨论,请参阅此问题及其答案

Simpler variants of @Martin Magakian 's answer: 更简单的变形@Martin Magakian的答案:

List<Integer> input = Arrays.asList(0,1,2,3);
List<Optional<Integer>> output =
  input.stream()
    .map(i -> crazyFunction(i)) // you can also use a method reference here
    .map(Optional::ofNullable) // returns empty optional
                               // if original value is null
    .map(optional -> optional.filter(out -> !out.equals(0))) // return empty optional
                                                           // if captured value is zero
    .collect(Collectors.toList())
;

List<Integer> outputClean =
  output.stream()
    .filter(Optional::isPresent)
    .map(Optional::get)
    .collect(Collectors.toList())
;

You can wrap the output into an Optional which may or may not contain a non-null value. 您可以将输出包装为Optional ,它可能包含也可能不包含非null值。
With an output: return Optional.of(out); 输出: return Optional.of(out);
Without output: return Optional.<Integer>empty(); 没有输出: return Optional.<Integer>empty();

You have to wrap into an option because an array cannot contain any null value . 您必须包装一个选项,因为数组不能包含任何空值

    List<Integer> input = Arrays.asList(0,1,2,3);
    List<Option<Integer>> output = input.stream()
                                .map(i -> { 
                                    Integer out = crazyFunction(i);
                                    if(out == null || out.equals(0))
                                        return Optional.<Integer>empty();
                                    return Optional.of(out);
                                    })
                                .collect(Collectors.toList());

This will make sure input.size() == output.size() . 这将确保input.size() == output.size()

Later on you can exclude the empty Optional using: 稍后您可以使用以下方法排除空的Optional:

    List<Integer> outputClean = output.stream()
                                   .filter(Optional::isPresent)
                                   .map(i -> {
                                           return i.get();
                                        })
                                   .collect(Collectors.toList());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM