Java
Scala
Collection
StreamAPI

ScalaでJavaのStreamAPIを使ったら妙にハマった


はじめに


概要

Scalaに不慣れな筆者が、JavaとScalaのListをごちゃ混ぜにしたところハマりました。普段Javaを書いていてScalaは初心者だよっていう人はハマりやすいかもと思ったので、原因と解決策をシェアします。


環境


  • Scala2.12.6

  • Java10.0.2


やりたいこと

Twitter4JのAPIで返ってくるツイートのリスト(ResponseList[Status])から必要な情報だけを抜き出して、自作クラスTweet型のListを取得したい。

JavaだとStreamAPIを使えば瞬殺できそう。


元のコード


コード

Twitter4JのAPIから返却されるResponseListはStreamAPIを使えるので、Java風に書くとこんな感じになりました。

※動きません。

val statuses: ResponseList[Status] = twitter.getUserTimeline(paging)

val tweets: List[Tweet] = statuses
.stream()
.map(status => new Tweet(status.getId, status.getText, status.getUser.getName))
.collect(Collectors.toList) //なぜかここでコンパイルエラーが…


原因

StreamAPIの終端操作.collect(Collectors.toList)で戻るのはjava.util.Listなのに、格納する変数の型がScalaのList型になっていること。

ScalaではScalaのAPIもJavaのAPIも使えますが、両者は別物。同じ名前の型を両者ともに提供していますが、ごちゃまぜに使ってはいけません。


書き直す方針


1.仕方がないのでjava.util.Listを変数の型に採用する

一番楽。

val statuses: ResponseList[Status] = twitter.getUserTimeline(paging)

val tweets: java.util.List[Tweet] = statuses
.stream()
.map(status => new Tweet(status.getId, status.getText, status.getUser.getName))
.collect(Collectors.toList)

だけど、メソッドで変数tweetsを戻すなら、ScalaのListが良い!だってScalaだもの。


2.JavaのコレクションクラスをScalaのコレクションクラスに変換

Scalaのドキュメントによると、ScalaとJavaのコレクションは相互に変換できる模様。

//JavaConvertersクラスがコレクションの変換を担う

import scala.collection.JavaConverters._

val statuses: ResponseList[Status] = twitter.getUserTimeline(paging)
val tweets: List[Tweet] = statuses
//ResponseList(Java) => mutable.Buffer(Scala)
.asScala
//あとはScalaコレクション操作APIを使用
.map(status => new Tweet(status.getId, status.getText, status.getUser.getName))
.toList


JavaConvertersについて補足


ScalaのコレクションとJavaのコレクションの対照表

Scala
Java

Iterator
java.util.Iterator

Iterator
java.util.Enumeration

Iterable
java.lang.Iterable

Iterable
java.util.Collection

mutable.Buffer
java.util.List

mutable.Set
java.util.Set

mutable.Map
java.util.Map

mutable.ConcurrentMap
java.util.concurrent.ConcurrentMap


使い方

import collection.JavaConverters._と宣言した上で、asJavaメソッドやasScalaメソッドを使うことで、変換をすることが可能。ただ、万能というわけでもないらしいので気をつけて使ってください。詳しくは公式ドキュメント


参考URL

Scala Documentation JAVAとSCALA間のコレクションの変換