JavaのリストをScalaのリストに変換しようとしたところ、割と盛大にハマったのでメモ。

By | 2019年7月21日

はじめに

Scalaのいいところは(scala-nativeのことはとりあえず置いといて、)簡潔な表記ができることと、Javaで記述した過去のソフトウェア資産を利用できることであると本Webサイトの管理人たるpandaは理解しています。

ところが、Javaで開発したコード(*1)に含まれるメソッドを実行した結果返されたリストをScalaのリストに変換しようとしたところ、割と盛大にハマってしまいました。

そこで、解決までの道のりをメモすることといたします。🐼

スポンサーリンク

問題を再現させるためのプログラムの作成及び動作の確認

(*1)のコード全体はかなり巨大なものであるため、問題を再現させるための必要最低限のコードを含むプロジェクトをEclipseで作成します。

Scalaプロジェクトの作成

まず、以下の手順でScalaが利用できるEclipse上でScalaプロジェクトを作成します。

  1. Scalaの開発環境を組み込んだEclipseの準備が必要です。準備の方法はこちらを参照ください。なお、この記事を最初に書いた時点(2019年7月)のEclipseのバージョンは2019-06でしたが、リンク先の記述と同様の手順で準備できることを確認しています。
  2. 手順1で準備したEclipseを起動します。
  3. WorkbenchのPackage Explorerで右クリックするとポップアップメニューが表示されますので、「New」→「Scala Project」と選択します。
  4. 「New Scala Project」ウィザードが表示されますので、”Project name”の入力フィールドに適当なプロジェクト名を入力して”Next”をクリックします。
  5. ウィザードの表示が下図のように切り替わりますので、「Create new source folder」(下図の赤矢印)をクリックして、Java及びScalaのコードを置くためのフォルダを作成します。慣習上、Javaのコードを置くフォルダを”src/main/java”、Scalaのコードを置くフォルダを”src/main/scala”としています。
  6. srcを右クリックするとポップアップメニューが表示されますので、「Remove from build path」を選択します。

Java側のコード

Java側のコードは前節で作成した”src/main/java”(下図の赤矢印(a))の下に適当なパッケージ名(“info.pandanote.scalalisttest”としています。)を作成して、Integer型のオブジェクトのListを返すメソッドを含むクラスを作成します。

Scala側のコード

問題発生時のコード

Scala側のコードもJava側と同様に前々節で作成した”src/main/java”(下図の赤矢印(a))の下に適当なパッケージ名(“info.pandanote.scalalisttest”としています。)を作成して、前節のJavaのコードで実装されているメソッドを実行した結果返されたInteger型のオブジェクトのListをScalaのListに変換して表示するコードを作成したつもりだったのですが…

下図の赤矢印のようなエラーが表示されてしまいました。_| ̄|○

1st try: implicit defを使ってみた。

最初は前節のエラーの原因はJavaのInteger型からScalaのInt型への変換ができていないのが原因だろうと考えたので、ListTestオブジェクトのスコープ中に

implicit def javaIntegerToScalaInt(i: java.lang.Integer): Int = i.intValue

 
と書いてみました。

結果は…

何も変わりませんでした。(´・ω・`)

2nd try: Java側のListを疑う。

次に、JavaのInteger→ScalaのIntの他にもList型の型変換ができていないこともエラー発生の原因なのではないかと考えたので、JavaのIntegerのListからScalaのIntのListへの型変換を行うメソッドを下図のように書いてみたのですが…

上図の赤矢印のようなエラーが表示されてしまいます。


スポンサーリンク

ここからは、なんでエラーになるのかの見当がすぐにはつかなかったためにかなり試行錯誤してしまいました。

試行錯誤すること、約2時間。


(※上の画像はイメージです。)

「もしかして、ScalaのListとJavaのListはパッケージ名が違うんじゃね?」

ということに気が付いてしまいました。💡

そこで、以下のようにコードを書いてみました。

上図の赤矢印(a)の部分が変更したところになります。JavaのListのパッケージ名を明示的に指定しています。

上記の修正を行ったところエラーが消えたので、Eclipse上で実行してみたところ上図の赤矢印(b)のようにListの中身がScala側に渡り、その中身を表示することができました。🎉

もうちょっと簡潔に書いてみる。

上図のコードの書き方だとBetter Java的な書き方になりますので、もう少し簡潔に書けないか考えてみることにします。

本記事の参考文献のサイト様の内容を参考にさせていただきながら、さらに試行錯誤して以下のように書いてみたところ、Listの中身がScala側に渡り、その中身を表示することができました。🎊

Better Java的な書き方でもJavaで書くよりは簡潔なのですが、それよりもさらに簡潔な一行コードになりました。😎

まとめ

今後Scalaでコードを書くにあたりEclipseとEmacsのどちらをメインにすべきかについてはこの記事を最初に書いた時点(2019年7月)ではまだ結論を出せていませんが、この記事ではEclipseでScalaプロジェクトを作成し、実装と動作の確認を行いました。なお、Eclipse以外の環境(sbt等)でのビルドの確認はこの記事を最初に書いた時点(2019年7月)では行っておりませんので、その点につきましてはご了承ください。

最初はJava側のIntegerクラスとScala側のIntクラスの変換の問題だろうと思っていましたが、思わぬ罠が待ち構えていました。ScalaとJavaは親和性が高い分だけ、「同一クラス名でScalaとJavaで異なる機能を持つクラス」の存在には要注意かもしれませんね。

Scalaでコードを書くための時間やEmacsを使った開発環境の整備のための時間があまり割けていない状況下ではありますが、この記事で書いた問題と類似の問題は今後も発生する可能性がありますので、問題の発生時には解決策などまで含めた記事を別途書くつもりです。

この記事は以上です。

References / 参考文献