サービスを呼び出し、応答を処理しようとしています。応答には何かのリストが含まれる場合があります。そのリストは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) { ... }
リストが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
Stream.ofNullable
(Java-9)single element、null以外の場合、/を含む順次ストリームを返しますotherwiseはempty 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その値のみを返す、otherwiseはempty 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
}
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の答えに同意します。
あなたは単に三項演算子を使うことができます:
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つのオプションは、Optional
monad を使用することです。
Optional<ResponseEntry> entry = Optional.ofNullable(serviceResponse.getEntryList()).flatMap(list ->
list.stream().filter(e -> "expectedValue".equals(e.getValue())).findFirst()
);
if (!entry.isPresent()) {
…
}
副作用を実行する代わりに値を作成(および返す)することが目的である場合は、そのorElseGet
ステートメントの代わりに if
を使用することもできます。