scala.jdk
The jdk package contains utilities to interact with JDK classes.
This packages offers a number of converters, that are able to wrap or copy types from the scala library to equivalent types in the JDK class library and vice versa:
- CollectionConverters, converting collections like scala.collection.Seq, scala.collection.Map, scala.collection.Set, scala.collection.mutable.Buffer, scala.collection.Iterator and scala.collection.Iterable to their JDK counterparts - OptionConverters, converting between Option and java.util.Optional and primitive variations - StreamConverters, to create JDK Streams from scala collections - DurationConverters, for conversions between scala scala.concurrent.duration.FiniteDuration and java.time.Duration - FunctionConverters, from scala Functions to java java.util.function.Function, java.util.function.UnaryOperator, java.util.function.Consumer and java.util.function.Predicate, as well as primitive variations and Bi-variations.
By convention, converters that wrap an object to provide a different interface to the same underlying data structure use .asScala and .asJava extension methods, whereas converters that copy the underlying data structure use .toScala and .toJava.
In the javaapi package, the same converters can be found with a java-friendly interface that don't rely on implicit enrichments.
Additionally, this package offers Accumulators, capable of efficiently traversing JDK Streams.
Type members
Classlikes
Accumulators are mutable sequences with two distinct features:
Accumulators are mutable sequences with two distinct features:
An accumulator can be appended efficiently to another
There are manually specialized Accumulators for
Int
,Long
andDouble
that don't box the elements
These two features make Accumulators a good candidate to collect the results of a parallel Java
stream pipeline into a Scala collection. The
scala.collection.convert.StreamExtensions.StreamHasToScala.toScala extension method on Java
streams (available by importing
scala.jdk.StreamConverters._
) is specialized for
Accumulators: they are built in parallel, the parts are merged efficiently.
Building specialized Accumulators is handled transparently. As a user, using the Accumulator object as a factory automatically creates an IntAccumulator, LongAccumulator, DoubleAccumulator or AnyAccumulator depending on the element type.
Note: to run the example, start the Scala REPL with scala -Yrepl-class-based
to avoid
deadlocks, see https://github.com/scala/bug/issues/9076.
scala> import scala.jdk.StreamConverters._
import scala.jdk.StreamConverters._
scala> def isPrime(n: Int): Boolean = !(2 +: (3 to Math.sqrt(n).toInt by 2) exists (n % _ == 0))
isPrime: (n: Int)Boolean
scala> val intAcc = (1 to 10000).asJavaParStream.filter(isPrime).toScala(scala.jdk.Accumulator)
intAcc: scala.jdk.IntAccumulator = IntAccumulator(1, 3, 5, 7, 11, 13, 17, 19, ...
scala> val stringAcc = (1 to 100).asJavaParStream.mapToObj("<>" * _).toScala(Accumulator)
stringAcc: scala.jdk.AnyAccumulator[String] = AnyAccumulator(<>, <><>, <><><>, ...
There are two possibilities to process elements of a primitive Accumulator without boxing:
specialized operations of the Accumulator, or the Stepper interface. The most common collection
operations are overloaded or overridden in the primitive Accumulator classes, for example
IntAccumulator.map or IntAccumulator.exists.
Thanks to Scala's function specialization,
intAcc.exists(x => testOn(x))
does not incur boxing.
The scala.collection.Stepper interface provides iterator-like hasStep
and nextStep
methods, and is
specialized for Int
, Long
and Double
. The intAccumulator.stepper
method creates an
scala.collection.IntStepper that yields the elements of the accumulator without boxing.
Accumulators can hold more than Int.MaxValue
elements. They have a sizeLong method that
returns the size as a Long
. Note that certain operations defined in scala.collection.Seq
are implemented using length, so they will not work correctly for large accumulators.
The Accumulator class is a base class to share code between AnyAccumulator (for reference types) and the manual specializations IntAccumulator, LongAccumulator and DoubleAccumulator.
- Companion:
- object
- Source:
- Accumulator.scala
Contains factory methods to build Accumulators.
Contains factory methods to build Accumulators.
Note that the Accumulator
object itself is not a factory, but it is implicitly convert to
a factory according to the element type, see Accumulator.toFactory.
This allows passing the Accumulator
object as argument when a collection.Factory, and
the implicit Accumulator.AccumulatorFactoryShape instance is used to build a specialized
Accumulator according to the element type:
scala> val intAcc = Accumulator(1,2,3)
intAcc: scala.collection.convert.IntAccumulator = IntAccumulator(1, 2, 3)
scala> val anyAccc = Accumulator("K")
anyAccc: scala.collection.convert.AnyAccumulator[String] = AnyAccumulator(K)
scala> val intAcc2 = List(1,2,3).to(Accumulator)
intAcc2: scala.jdk.IntAccumulator = IntAccumulator(1, 2, 3)
scala> val anyAcc2 = List("K").to(Accumulator)
anyAcc2: scala.jdk.AnyAccumulator[String] = AnyAccumulator(K)
- Companion:
- class
- Source:
- Accumulator.scala
An Accumulator for arbitrary element types, see Accumulator.
An Accumulator for arbitrary element types, see Accumulator.
- Companion:
- object
- Source:
- AnyAccumulator.scala
This object provides extension methods that convert between Scala and Java collections.
This object provides extension methods that convert between Scala and Java collections.
When writing Java code, use the explicit conversion methods defined in javaapi.CollectionConverters instead.
Note: to create Java Streams that operate on Scala collections (sequentially or in parallel), use StreamConverters.
import scala.jdk.CollectionConverters._
val s: java.util.Set[String] = Set("one", "two").asJava
The conversions return adapters for the corresponding API, i.e., the collections are wrapped, not converted. Changes to the original collection are reflected in the view, and vice versa:
scala> import scala.jdk.CollectionConverters._
scala> val s = collection.mutable.Set("one")
s: scala.collection.mutable.Set[String] = HashSet(one)
scala> val js = s.asJava
js: java.util.Set[String] = [one]
scala> js.add("two")
scala> s
res2: scala.collection.mutable.Set[String] = HashSet(two, one)
The following conversions are supported via asScala
and asJava
:
scala.collection.Iterable <=> java.lang.Iterable
scala.collection.Iterator <=> java.util.Iterator
scala.collection.mutable.Buffer <=> java.util.List
scala.collection.mutable.Set <=> java.util.Set
scala.collection.mutable.Map <=> java.util.Map
scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
The following conversions are supported via asScala
and through
specially-named extension methods to convert to Java collections, as shown:
scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
In addition, the following one-way conversions are provided via asJava
:
scala.collection.Seq => java.util.List
scala.collection.mutable.Seq => java.util.List
scala.collection.Set => java.util.Set
scala.collection.Map => java.util.Map
The following one way conversion is provided via asScala
:
java.util.Properties => scala.collection.mutable.Map
In all cases, converting from a source type to a target type and back again will return the original source object. For example:
import scala.jdk.CollectionConverters._
val source = new scala.collection.mutable.ListBuffer[Int]
val target: java.util.List[Int] = source.asJava
val other: scala.collection.mutable.Buffer[Int] = target.asScala
assert(source eq other)
- Source:
- CollectionConverters.scala
A specialized Accumulator that holds Double
s without boxing, see Accumulator.
A specialized Accumulator that holds Double
s without boxing, see Accumulator.
- Companion:
- object
- Source:
- DoubleAccumulator.scala
This object provides extension methods that convert between Scala and Java duration types.
This object provides extension methods that convert between Scala and Java duration types.
When writing Java code, use the explicit conversion methods defined in javaapi.DurationConverters instead.
- Source:
- DurationConverters.scala
This object provides extension methods that convert between Scala and Java function types.
This object provides extension methods that convert between Scala and Java function types.
When writing Java code, use the explicit conversion methods defined in javaapi.FunctionConverters instead.
Using the .asJava
extension method on a Scala function produces the most specific possible
Java function type:
scala> import scala.jdk.FunctionConverters._
scala> val f = (x: Int) => x + 1
scala> val jf1 = f.asJava
jf1: java.util.function.IntUnaryOperator = ...
More generic Java function types can be created using the corresponding asJavaXYZ
extension
method:
scala> val jf2 = f.asJavaFunction
jf2: java.util.function.Function[Int,Int] = ...
scala> val jf3 = f.asJavaUnaryOperator
jf3: java.util.function.UnaryOperator[Int] = ...
Converting a Java function to Scala is done using the asScala
extension method:
scala> List(1,2,3).map(jf2.asScala)
res1: List[Int] = List(2, 3, 4)
- Source:
- FunctionConverters.scala
This object provides extension methods that convert between Scala scala.concurrent.Future and Java java.util.concurrent.CompletionStage
This object provides extension methods that convert between Scala scala.concurrent.Future and Java java.util.concurrent.CompletionStage
When writing Java code, use the explicit conversion methods defined in javaapi.FutureConverters instead.
Note that the bridge is implemented at the read-only side of asynchronous handles, namely
scala.concurrent.Future (instead of scala.concurrent.Promise) and java.util.concurrent.CompletionStage (instead of
java.util.concurrent.CompletableFuture). This is intentional, as the semantics of bridging
the write-handles would be prone to race conditions; if both ends (CompletableFuture
and
Promise
) are completed independently at the same time, they may contain different values
afterwards. For this reason, toCompletableFuture
is not supported on the created
CompletionStage
s.
- Source:
- FutureConverters.scala
A specialized Accumulator that holds Int
s without boxing, see Accumulator.
A specialized Accumulator that holds Int
s without boxing, see Accumulator.
- Companion:
- object
- Source:
- IntAccumulator.scala
A specialized Accumulator that holds Long
s without boxing, see Accumulator.
A specialized Accumulator that holds Long
s without boxing, see Accumulator.
- Companion:
- object
- Source:
- LongAccumulator.scala
This object provides extension methods that convert between Scala Option
and Java Optional
types.
This object provides extension methods that convert between Scala Option
and Java Optional
types.
When writing Java code, use the explicit conversion methods defined in javaapi.OptionConverters instead.
Scala Option
is extended with a toJava
method that creates a corresponding Optional
, and
a toJavaPrimitive
method that creates a specialized variant (e.g., OptionalInt
) if
applicable.
Java Optional
is extended with a toScala
method and a toJavaPrimitive
method.
Finally, specialized Optional
types are extended with toScala
and toJavaGeneric
methods.
Example usage:
import scala.jdk.OptionConverters._
val a = Option("example").toJava // Creates java.util.Optional[String] containing "example"
val b = (None: Option[String]).toJava // Creates an empty java.util.Optional[String]
val c = a.toScala // Back to Option("example")
val d = b.toScala // Back to None typed as Option[String]
val e = Option(2.7).toJava // java.util.Optional[Double] containing boxed 2.7
val f = Option(2.7).toJavaPrimitive // java.util.OptionalDouble containing 2.7 (not boxed)
val g = f.toScala // Back to Option(2.7)
val h = f.toJavaGeneric // Same as e
val i = e.toJavaPrimitive // Same as f
- Source:
- OptionConverters.scala
A type class implementing conversions from a generic Scala Option
or Java Optional
to
a specialized Java variant (for Double
, Int
and Long
).
A type class implementing conversions from a generic Scala Option
or Java Optional
to
a specialized Java variant (for Double
, Int
and Long
).
- Type parameters:
- A
the primitive type wrapped in an option
- O
the specialized Java
Optional
wrapping an element of typeA
- Companion:
- object
- Source:
- OptionShape.scala
This object provides extension methods to create Java Streams that operate on Scala collections (sequentially or in parallel).
This object provides extension methods to create Java Streams that operate on Scala collections (sequentially or in parallel). For more information on Java streams, consult the documentation (https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html).
When writing Java code, use the explicit conversion methods defined in javaapi.StreamConverters instead.
The methods asJavaSeqStream
and asJavaParStream
convert a collection to a Java Stream:
scala> import scala.jdk.StreamConverters._
scala> val s = (1 to 10).toList.asJavaSeqStream
s: java.util.stream.IntStream = java.util.stream.IntPipeline$Head@7b1e5e55
scala> s.map(_ * 2).filter(_ > 5).toScala(List)
res1: List[Int] = List(6, 8, 10, 12, 14, 16, 18, 20)
Note: using parallel streams in the Scala REPL causes deadlocks, see
https://github.com/scala/bug/issues/9076. As a workaround, use scala -Yrepl-class-based
.
scala> def isPrime(n: Int): Boolean = !(2 +: (3 to Math.sqrt(n).toInt by 2) exists (n % _ == 0))
isPrime: (n: Int)Boolean
scala> (10000 to 1000000).asJavaParStream.filter(isPrime).toScala(Vector)
res6: scala.collection.immutable.Vector[Int] = Vector(10007, 10009, 10037, 10039, ...
A Java Stream provides operations on a sequence of elements. Streams are created from Spliterators, which are similar to Iterators with the additional capability to partition off some of their elements. This partitioning, if supported by the Spliterator, is used for parallelizing Stream operations.
Scala collections have a method stepper
that
returns a scala.collection.Stepper for the collection, which in turn can be converted to a
Spliterator for creating a Java Stream.
The asJavaSeqStream
extension method is available on any Scala collection. The
asJavaParStream
extension method can only be invoked on collections where the return type of
the stepper
method is marked with the
scala.collection.Stepper.EfficientSplit marker trait. This trait is added to steppers that
support partitioning, and therefore efficient parallel processing.
The following extension methods are available:
Collection Type | Extension Methods |
---|---|
| |
| |
| |
| |
| |
| |
Strings | |
Java streams | |
The asJavaPrimitiveStream
method converts a Stream[Int]
to an IntStream
. It is the dual
of the boxed
method defined on primitive streams (e.g., IntStream.boxed
is a
Stream[Integer]
).
The toScala
extension methods on Java streams collects the result of a stream pipeline into a
Scala collection, for example stream.toScala(List)
, stream.toScala(Vector)
. Note that
transformation operations on streams are lazy (also called "intermediate"), terminal operations
such as forEach
, count
or toScala
trigger the evaluation.
Collecting a parallel stream to a collection can be performed in parallel. This is beneficial if
the target collection supports efficient merging of the segments that are built in parallel.
To support this use case, the Scala standard library provides the Accumulator collection.
This collection supports efficient parallel construction, and it has specialized subtypes for
Int
, Long
and Double
so that primitive Java streams can be collected to a Scala collection
without boxing the elements.
- Source:
- StreamConverters.scala