web-dev-qa-db-ja.com

Java 8を使用してnull許容リストを処理する方法は?

サービスを呼び出し、応答を処理しようとしています。応答には何かのリストが含まれる場合があります。そのリストはnullの可能性があります。

さらに、リストがnullでも空でもない場合は、フィルタリングする必要があります。コードでは、フィルタリングによって何も得られないか、応答リストが空またはnullの場合、「entry」参照はnullになる可能性があります。

現在、null応答リストで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) { ... }
12
Kyle Bak

リストがnullまたは空でない場合は、フィルタリングする必要があります。

単純な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がnullでなく、responseEntriesが空でない場合、フィルター操作を適用して最初のアイテムを見つけるか、nullでない場合」を読み取ります。とても読みやすい。

一方、オプションのアプローチ:

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」チェックの代わりとして使用するオプションの意図は実際にはありません。
13
Aomine

Stream.ofNullable (Java-9)

single elementnull以外の場合、/を含む順次ストリームを返しますotherwiseempty Streamを返します。

現在のコード

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その値のみを返すotherwiseempty 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)

値がnot presentの場合、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
}
8
Naman

Java 9では、新しいメソッド Objects.requireNonNullElse(T,T) を使用できます:

_Objects.requireNonNullElse(serviceResponse.getEntryList(),
                           Collections.emptyList())
_

Apache Commons Collectionには、実際にはメソッド ListUtils.emptyIfNull(List<T>) があり、引数リストがnullの場合、空のリストを返します。それはさらに良いですが、_Objects.requireNonNullElse_はJava SE。

Java 8に制限されている場合、Optionalを通過するようなことをしようとすることはifステートメントよりも悪いというAomineの答えに同意します。

7
Radiodef

あなたは単に三項演算子を使うことができます:

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です。

もう1つのオプションは、Optionalmonad を使用することです。

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

if (!entry.isPresent()) {
    …
}

副作用を実行する代わりに値を作成(および返す)することが目的である場合は、そのorElseGetステートメントの代わりに if を使用することもできます。

1
Bergi