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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24947198/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 15:53:53  来源:igfitidea点击:

Return empty element from Java 8 map operation

javamapjava-8java-stream

提问by Martin Magakian

Using Java 8 stream what is the best wayto map a List<Integer>when you have no output for the input Integer ?

当输入 Integer 没有输出时,使用 Java 8 流映射 a的最佳方法是什么List<Integer>

Simply return null? But now my output list size will be smaller than my input size...

简单地返回null?但是现在我的输出列表大小将小于我的输入大小...

    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());

采纳答案by Holger

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 Listto 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 Listis not an end in itself so you should consider for what kind of operationyou need this list (or its contents) and apply the operation right as the terminal operation of the stream. 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).

简单的答案是:不要生成列表。AList本身不是目的,因此您应该考虑您需要此列表(或其内容)的哪种操作,并将操作权限应用为流的终端操作。然后你就有了答案,因为操作决定了是否应该过滤掉不存在的值或用特殊值(以及必须是什么值)来表示。

It might be a different answer for different operations…

对于不同的操作可能会有不同的答案......

回答by Martin Magakian

You can wrap the output into an Optionalwhich may or may not contain a non-null value.
With an output: return Optional.of(out);
Without output: return Optional.<Integer>empty();

您可以将输出包装到一个Optional 中,它可能包含也可能不包含非空值。
有输出:return Optional.of(out);
无输出: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());

回答by srborlongan

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())
;

回答by Stuart Marks

Replace the mapcall with flatMap. The mapoperation produces one output value per input value, whereas the flatMapoperation produces any number of output values per input value -- include zero.

map呼叫替换为flatMap。该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 crazyFunctionto have it return an Optional(probably OptionalInt). If you call it from map, the result is a Stream<OptionalInt>. Then you need to flatMapthat stream to remove the empty optionals:

进一步的重构可能会改变crazyFunction,让它返回一个Optional(可能是OptionalInt)。如果从 调用它map,结果是Stream<OptionalInt>。然后你需要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 flatMapis a Stream<Integer>which boxes up the ints, but this is OK since you're going to send them into a List. If you weren't going to box the intvalues into a List, you could convert the Stream<OptionalInt>to an IntStreamusing the following:

的结果flatMap是 a Stream<Integer>which 将ints装箱,但这是可以的,因为您要将它们发送到List. 如果您不打算将int值装箱到 a 中List,则可以使用以下命令将 the 转换Stream<OptionalInt>为 an 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.

有关处理可选流的进一步讨论,请参阅此问题及其答案