23

I need to convert Scala Option to Java Optional. I managed to wrote this:

public <T> Optional<T> convertOption2Optional(Option<T> option) {
    return option.isDefined() ? Optional.of(option.get()) : Optional.empty();
}

But I don't like it.

Is there a simple way to do it, or a built-in scala converter? I'm looking for something like:

Options.asJava(option);
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
mjjaniec
  • 793
  • 1
  • 8
  • 19

8 Answers8

19

The shortest way I can think of in Java is:

Optional.ofNullable(option.getOrElse(null))

@RégisJean-Gilles actually suggested even shorter if you are writing the conversion in Scala:

Optional.ofNullable(option.orNull)

By the way you must know that Scala does not support Java 8 until Scala 2.12, which is not officially out yet. Looking at the docs (which may change until the release) there is no such conversion in JavaConversions.

Ben McCann
  • 18,548
  • 25
  • 83
  • 101
Dici
  • 25,226
  • 7
  • 41
  • 82
  • Sure, this is why I couldn't find it there :) – mjjaniec Jul 12 '16 at 10:14
  • Just a note, it is not recomended to use `JavaConversions` at all. `JavaConverters` is a preferable way. Anyway neither of them supports `Optional` at the time – dk14 Jul 12 '16 at 11:27
  • @dk14 recommended by who, and why ? As far as I can tell they do rigorously the same thing with a slightly different syntax. `JavaConverters` arguably provides a nicer syntax but this will only work from Scala code, not from Java code trying to convert Scala collections since Java does not support implicits. There is nothing wrong with `JavaConversions` – Dici Jul 12 '16 at 11:52
  • @Dici http://googlyadventures.blogspot.com/2015/06/today-i-learned-javaconverters-vs.html http://stackoverflow.com/questions/8301947/what-is-the-difference-between-javaconverters-and-javaconversions-in-scala I can google it all day. Basically JavaConvertions are too implicit, you're not always sure which collection do you have Java or Scala, and even IDE can't help with that – dk14 Jul 12 '16 at 13:16
  • @Dici "but this will only work from Scala code, not from Java code" Neither of them work from Java Code as BOTH of them use implicits. The right way of doing from it Java is `scala.collection.convert` package: http://stackoverflow.com/a/27110969/1809978. It's the right way because both JavaConvertios and JavaConverters are actually using it. and they basically are DSLs for that – dk14 Jul 12 '16 at 13:20
  • I have definitely used `JavaConversions` from Java code, but you're right it uses implicits too. You can actually use it anyway by calling explicitly into these methods, my bad. However, I'm not sure I'm strongly buying the argument of the blogger. I think in both cases you know the type of the returned object and you case easily check it by using the Scala compiler nice type inference feature (usually just require to hover on the variable to see its type in an IDE) – Dici Jul 12 '16 at 13:38
  • 7
    `option.getOrElse(null)` can be shortened to `option.orNull` – Régis Jean-Gilles Jul 12 '16 at 14:50
  • 2
    http://stackoverflow.com/questions/38320708/implicit-conversion-between-java-and-scala-collections-using-javaconversions/38320930#38320930 – som-snytt Jul 12 '16 at 19:25
  • @som-snytt since you appear to have been close to the deprecation process, could you tell us the motivations ? – Dici Jul 12 '16 at 22:03
  • deprecation of JavaConversions? There's a note at http://www.scala-lang.org/api/2.12.0-M5/scala/collection/JavaConversions$.html . Basically, either, you get multiple conversions unexpectedly; or inference suffers. – som-snytt Jul 12 '16 at 22:11
  • @som-snytt I don't really see how this is different. It's not like `asJava` or `asScala` tells you the concrete type which is going to be returned. You still don't know if you will end up with an `Arraylist` or a `LinkedList`, for example. Don't you have to check the doc or use the compiler's inference in both cases to determine the underlying type ? And even then, it will just give you an interface type, not the real concrete type. Anyway, thanks – Dici Jul 13 '16 at 00:13
  • 1
    I was thinking of unexpected multiple conversions in an expr, but googling scala javaconversions evil yields https://gist.github.com/xuwei-k/8870ea35c4bb6a4de05c which is pretty good. I should add I don't have strong feelings about it, and Jason Zaugg thinks it's useful for concision. The deprecation was largely to help newbies avoid pitfalls (IMO). – som-snytt Jul 13 '16 at 05:16
  • @som-snytt cool, thanks for taking the time to explain this. It must be pretty cool to be close to such a project, I'm a bit envious :D – Dici Jul 13 '16 at 10:04
  • 3
    The first one does not work in Java. `None.getOrElse(null)` throws an NPE because `getOrElse` takes a by-name argument, which translates to a `scala.Function0`. – Jan Van den bosch Aug 07 '18 at 08:02
  • Works perfectly fine for me: `Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_181). Type in expressions to have them evaluated. Type :help for more information. scala> Optional.ofNullable(None.getOrElse(null)) res4: java.util.Optional[Null] = Optional.empty` – Dici Aug 07 '18 at 09:50
  • 1
    @Dici: I said *in Java*. You're running it in a Scala interpreter. – Jan Van den bosch Aug 07 '18 at 10:22
16

Starting Scala 2.13, there is a dedicated converter from scala's Option to java's Optional.

From Java (the explicit way):

import scala.jdk.javaapi.OptionConverters;

// val option: Option[Int] = Some(42)
OptionConverters.toJava(option);
// java.util.Optional[Int] = Optional[42]

From Scala (the implicit way):

import scala.jdk.OptionConverters._

// val option: Option[Int] = Some(42)
option.toJava
// java.util.Optional[Int] = Optional[42]
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
12

There is an asJava starting in 2.10:

import scala.compat.java8.OptionConverters._

val o = Option(2.7)
val oj = o.asJava        // Optional[Double]
val ojd = o.asPrimitive  // OptionalDouble
val ojds = ojd.asScala   // Option(2.7) again

More details here.

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
JavaNoScript
  • 2,345
  • 21
  • 27
4

I am doing this:

import java.util.{Optional => JOption}

package object myscala {

    implicit final class RichJOption[T](val optional: JOption[T]) {

        def asScala: Option[T] = optional match {
            case null => null
            case _ => if (optional.isPresent) Option(optional.get()) else None
        }

    }

    implicit final class RichOption[T](val option: Option[T]) {

        def asJava: JOption[T] = option match {
            case null => null
            case _ => if (option.isDefined) JOption.of(option.get) else JOption.empty()
        }

    }
}

so, you can use it like this, :)

import myscala._

object Main extends App {

    val scalaOption = java.util.Optional.ofNullable("test").asScala
    println(scalaOption)

    val javaOption = Option("test").asJava
    println(javaOption)

}
Zhuo YING
  • 972
  • 3
  • 11
  • 19
3

You can also use some of the abundant utilities out there on the github, e.g.:

https://gist.github.com/julienroubieu/fbb7e1467ab44203a09f

https://github.com/scala/scala-java8-compat

Michal M
  • 1,521
  • 14
  • 35
1

For a given input parameter opt: Option[T] of some class, you can define a method inside that class as such:

def toOptional(implicit ev: Null <:< T): Optional[T] =
  Optional.ofNullable(opt.orNull)
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
Hari Bage
  • 31
  • 3
0

Another nice lib:

https://github.com/AVSystem/scala-commons

import com.avsystem.commons.jiop.JavaInterop._
Optional.of("anything").asScala
mjjaniec
  • 793
  • 1
  • 8
  • 19
-1

Scala 2.13 has some useful converters in scala.jdk.OptionConverters.{RichOption, FutureConverters} for example.

RichOption adds implicit methods for converting between scala and java options so you can do this...

    import scala.jdk.OptionConverters.RichOption
    
    val scalaOpt = Some("hello")
    val javaOpt = scalaOpt.toJava

under the hood this is just a match statement on the scala option...

    def toJava: Optional[A] = o match { case Some(a) => Optional.ofNullable(a); case _ => Optional.empty[A] }