はじめに
javaに触れ始め、複雑なPGをする中で処理速度改善のためにstreamAPIを知り、無邪気にfor文から置き換えて使っていた際に本記事の表題にあるエラーが表示されました。
コンパイルエラーとなり、buildができない動かない。。。
エラーメッセージで検索してもクリティカルな記事を見つけられず、StreamAPIのリファレンスを再度確認して、Javaのバージョンが原因であることが判明。
Javaのバージョンを無暗に変更することもできない状況で、なんとか動くように修正した内容を備忘(また類似の内容でつまずいた方へ)のために記事を作成いたします。
エラー内容
①「シンボルを見つけられません
シンボル: メソッド isEmpty()
場所: タイプjava.util.Optionalの変数 」
②「シンボルを見つけられません
シンボル: メソッド stream()
場所: タイプjava.util.Optional>の変数」
原因
javaのバージョン合わないことが原因
自分の環境:java11
デプロイ先の環境:java8
javaのドキュメントを確認すると、エラーで表示されたOptional.isEmpty()はjava11以降、Optional.stream()はjava9以降で動作することが記載されています。
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Optional.html
開発も終盤に差し掛かり、java8で動いているものをjava11に修正するリスクよりは、PGを修正する選択を取らざるを得ない状況だったため、修正いたしました。
エラー内容①、②の修正前のソースコード
// エラー内容①の元の処理
// listAのnameがtaroのデータが複数件ある場合、ageが最大のものをリストに追加する
Optional<Object> test1 = testA.stream()
.filter(i -> i.get("name").equals("taro"))
.max((s1, s2) -> Integer.parseInt(s1.get("age")) - Integer.parseInt(s2.get("age")))
.map(x -> x.get("age"));
// testAが空の場合、ageは20として設定する
// ここがエラーの原因
if (testA.isEmpty()) {
age = "20";
}
// エラー内容②の元の処理
// listBのname毎にデータをグルーピング、ageが最大のものをリストに追加
Map<String, Optional<Map<String, Object>>> test2 = testB.stream()
.collect(Collectors.groupingBy(data -> data.get("userName")
Collectors.maxBy(Comparator.comparing(data -> (long) data.get("age")))));
// flatMapでtest2を平坦にする
// ここがエラーの原因
List<Map<String, Object>> testC = test2.values().stream()
.flatMap(opt -> opt.stream())
.collect(Collectors.toList());
エラー内容①、②の修正後のソースコード
// エラー内容①の修正後の処理
Object test1 = testA.stream()
.filter(i -> i.get("name").equals("taro"))
.max((s1, s2) -> Integer.parseInt(s1.get("age")) - Integer.parseInt(s2.get("age")))
.map(x -> x.get("age"))
.orElse(null);
if (testA == null) {
age = "20";
}
// エラー内容②の修正後の処理
Map<String, Optional<Map<String, Object>>> test2 = testB.stream()
.collect(Collectors.groupingBy(data -> data.get("userName")
Collectors.maxBy(Comparator.comparing(data -> (long) data.get("age")))));
List<Map<String, Object>> testC = test2.values().stream()
.flatMap(opt -> opt.isPresent() ? Stream.of(opt.get()) : Stream.empty())
.collect(Collectors.toList());
解説
■エラー内容①について
終端処理にorElse(null)を付記することで、test1の定義をOptionalではなく、Objectにする。
filter条件に一致しない場合はnullが返却させることで、testA.isEmpty()ではなくtestA == nullとすることで対応。
■エラー内容②について
Optional>が存在することを確認して、いたらStream化して返す。
それをflatMapで配列に変換することで対応。
終わりに
javaを使った開発を行うにあたって、初歩的な「バージョンによって使えるライブラリが異なる」という原因のエラーでつまずきました。
javaのバージョンを変えずに、試行錯誤して叶えたい実装を行う必要がある際、本記事が一助となれば幸いです。
参考
・StreamAPI
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Optional.html