【问题标题】:How to handle nullable lists using java 8?如何使用 java 8 处理可空列表?
【发布时间】:2018-12-26 23:09:37
【问题描述】:

我正在拨打服务电话并尝试处理响应。 响应可能有一些东西的列表。该列表可能为空。

此外,如果列表不为空或不为空,则 它需要被过滤。 如果过滤没有给出任何结果或响应列表为空或为空,则代码中的“条目”引用可能为空。

目前,当我尝试在空响应列表上使用 stream() 时,我得到了 NPE。 我该如何处理这种情况?

@Getter
public class ServiceResponse {  
    List<ResponseEntry> entryList;
}

@Getter
public class ResponseEntry {
    String value;
}


ServiceResponse serviceResponse = service.getServiceResponse();
ResponseEntry entry = serviceResponse.getEntryList()
    .stream()
    .filter(e -> "expectedValue".equals(e.getValue()))
    .findFirst()
    .orElse(null);

if (entry == null) { ... }

【问题讨论】:

  • 为什么列表可能为空?没有回复的列表值方法的首选返回是emptyList()

标签: java java-8 java-stream optional


【解决方案1】:

如果列表不为空或不为空,则需要过滤。

此处不需要 Optional,因为它不打算替换简单的 if 检查。

ResponseEntry entry = null;
List<ResponseEntry> responseEntries = serviceResponse.getEntryList();
if(responseEntries != null && !responseEntries.isEmpty()){
    entry = responseEntries.stream()
                .filter(e -> "expectedValue".equals(e.getValue()))
                .findFirst()
                .orElse(null);
}
  • 读取“如果responseEntries 不为空且responseEntries 不为空,则应用过滤操作并查找第一项,否则为空”。非常易读。

另一方面,可选方法:

ResponseEntry entry = Optional.ofNullable(serviceResponse.getEntryList())
                              .orElseGet(() -> Collections.emptyList())
                              .stream()
                              .filter(e -> "expectedValue".equals(e.getValue()))
                              .findFirst();

if(!entry.isPresent()){ ... } // or entry.ifPresent(e -> ...) depending on the logic you're performing inside the block
  • 不必要地创建可以避免的对象,而不是真正的可选项意图用作简单“if”检查的替代品。

【讨论】:

    【解决方案2】:

    Stream.ofNullable (Java-9)

    返回包含单个元素的顺序流,如果非空否则返回一个空流

    当前代码

    ResponseEntry entry = serviceResponse.getEntryList() // List<ResponseEntry>
            .stream() // NPE here   // Stream<ResponseEntry>
            .filter(e -> "expectedValue".equals(e.getValue())) // filter
            .findFirst() // Optional<ResponseEntry>
            .orElse(null); // or else null
    

    更新代码

    ResponseEntry entry = Stream.ofNullable(serviceResponse.getEntryList()) // Stream<List<ResponseEntry>>
            .flatMap(List::stream) // Stream<ResponseEntry>
            .filter(e -> "expectedValue".equals(e.getValue())) // filter here
            .findFirst() // Optional<ResponseEntry>
            .orElse(null); // or else null
    

    Optional.stream (Java-9)

    返回一个连续的Stream,包含只包含那个值否则 返回一个空流

    ResponseEntry entry = Optional.ofNullable(serviceResponse.getEntryList())
            .stream() // Stream<List<ResponseEntry>>
            .flatMap(List::stream) // Stream<ResponseEntry>
            .filter(e -> "expectedValue".equals(e.getValue())) // filter here
            .findFirst() // Optional<ResponseEntry>
            .orElse(null); // or else null
    

    Optional.isEmpty(Java-11)

    如果值不存在,则返回true否则 false

    Optional<ResponseEntry> entry = Optional.ofNullable(serviceResponse.getEntryList()) // Optional<List<ResponseEntry>>
            .orElseGet(Collections::emptyList) // or else empty List
            .stream() // Stream<ResponseEntry>
            .filter(e -> "expectedValue".equals(e.getValue())) // filter
            .findFirst(); // Optional<ResponseEntry>
    
    if (entry.isEmpty()) { // !entry.isPresent in java-8
       // Do your work here
    }
    

    【讨论】:

      【解决方案3】:

      在 Java 9 中,您可以使用新方法 Objects.requireNonNullElse(T,T)

      Objects.requireNonNullElse(serviceResponse.getEntryList(),
                                 Collections.emptyList())
      

      Apache Commons Collections 实际上有一个方法ListUtils.emptyIfNull(List&lt;T&gt;),如果参数列表是null,它会返回一个空列表。这更好,但Objects.requireNonNullElse 是 Java SE 中最接近它的东西。

      如果您仅限于 Java 8,那么我同意 Aomine 的回答,即尝试执行诸如通过 Optional 之类的操作比使用 if 语句更糟糕。

      【讨论】:

        【解决方案4】:

        您可以简单地使用三元运算符:

        ServiceResponse serviceResponse = service.getServiceResponse();
        List<ResponseEntry> list = serviceResponse.getEntryList();
        
        ResponseEntry entry = (list == null ? Collections.emptyList() : list)
            .stream()
            .filter(e -> "expectedValue".equals(e.getValue()))
            .findFirst()
            .orElse(null);
        
        if (entry == null) { ... }
        

        有时,传统的 IMO 更好。

        【讨论】:

          【解决方案5】:

          另一种选择是使用Optionalmonad

          Optional<ResponseEntry> entry = Optional.ofNullable(serviceResponse.getEntryList()).flatMap(list ->
              list.stream().filter(e -> "expectedValue".equals(e.getValue())).findFirst()
          );
          
          if (!entry.isPresent()) {
              …
          }
          

          如果您的目标是构建(并返回)一个值,而不是执行副作用,您甚至可以使用 orElseGet 而不是 if 语句。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-03-31
            • 1970-01-01
            • 2013-04-19
            • 2013-10-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多