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

时间:2014-07-25 02:39:37

标签: java map java-8 java-stream

当输入整数没有输出时,使用Java 8流最佳方式来映射List<Integer>

简单地返回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());

4 个答案:

答案 0 :(得分:46)

我不明白为什么你(以及所有的答案)让它如此复杂。您有映射操作和过滤操作。所以最简单的方法就是一个接一个地应用这些操作。除非您的方法已经返回Optional,否则无需处理Optional

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

可以简化为

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

但是你似乎有更多的理论问题,关于生成什么样的List,一个是缺少值的占位符,另一个是与输入列表不同的大小。

简单的答案是:不生成列表List本身不是目的,因此您应该考虑需要此类列表(或其内容)的操作,并将操作权应用为流的终端操作。然后你得到答案,因为操作决定是否应该过滤掉缺席值或用特殊值表示(以及必须具有的值)。

对于不同的操作,它可能是一个不同的答案......

答案 1 :(得分:29)

map来电替换为flatMapmap操作为每个输入值生成一个输出值,而flatMap操作为每个输入值生成任意数量的输出值 - 包括零。

最直接的方法可能就是更换支票:

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

进一步重构可能会更改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());

flatMap的结果是Stream<Integer>,其中列出了int,但这是可以的,因为您要将它们发送到List。如果您不打算将int值设置为List,则可以使用以下内容将Stream<OptionalInt>转换为IntStream

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

有关处理选项流的进一步讨论,请参阅this question and its answers

答案 2 :(得分:2)

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

答案 3 :(得分:1)

您可以将输出包装到Optional中,该{{3}}可能包含也可能不包含非空值 输出:return Optional.of(out);
没有输出:return Optional.<Integer>empty();

你必须包装一个选项,因为一个数组不能包含任何空值

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

这将确保input.size() == output.size()

稍后您可以使用以下方法排除空的可选:

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