Scala code is highly compatible with Java, most of time you can combine the languages worrying very much. The chapter will describe two aspects of combining Java and Scala. Firstly, it discussess how Scala is translated to Java which is important if you call Scala code from Java and secondly, it discusss the use of Java annotation in Scala, an important feature if you wan to to use Scala with existing Java framework.
Scala feature maps dierectly onto the equivalent java features, scala classes, methods, strings, exception, for examples, are all compiled to te same Java bytes as their Java counterparts. Scala trait does not have equivalent in java, Scala generic is different from Java one.
a value type like Int can be transalted in two different ways to Java, whenever possible, 1. to java int to get better performance, 2. to Wrapper classes java.lang.Integer when it is has to be wrapped to inside a Java object .
there is noting like the signleton object in Java, and how does the compiler translate it to java code.
Given a simple example, suppose that you have the followig code.
object App { def main(args : Array[String]) { println("hello, world!") } }and if you run some javap command.
// in scala 2.9.1. if you have just the object app, this is what you get the from the javap javap app.class Compiled from "31_1_UsingScalaFromJava.scala" public final class App { public static final void main(java.lang.String[]); } javap app$.class Compiled from "31_1_UsingScalaFromJava.scala" public final class App$ implements scala.ScalaObject { public static final App$ MODULE$; public static {}; public void main(java.lang.String[]); }and if you have a App class, then you compile them to examine the byte code you will get.
class App { }and you run the javap code ,you will get.
// and if you have a App class above, with javap javap App.class Compiled from "31_1_UsingScalaFromJava.scala" public class App implements scala.ScalaObject { public static final void main(java.lang.String[]); public App(); } javap App$.class Compiled from "31_1_UsingScalaFromJava.scala" public final class App$ implements scala.ScalaObject { public static final App$ MODULE$; public static {}; public void main(java.lang.String[]); }
if the trait has no members, then it will be translated to java interface, while if otherwise.
we have some standard annotation, and we will introduce on how them apply on the scala code.
Additional effects from standard annotations
several annotation cause the compilter to emit extra information when targeting Java platform. It first process it according to the general Scala rules, and then it does something extra for it
@deprecation
@volatile field , scala has the same semantic towards the java semantics
@serializable: @SerialVersionUID(1234L)
@serializable @SerialVersionUID(1234L) class SeriazableClass {}
// when compiled // the @SerialVersionUID(1234L) will be converted to the following java Field definition /*javap SeriazableClass.class Compiled from "31_2_Annotations.scala" public class SeriazableClass implements scala.ScalaObject,scala.Serializable { public static final long serialVersionUID; public static {}; public SeriazableClass(); }*/Exception throw
Scala does not check for exception , unlike the Java language, however, all Scala methods are translated to Java methods that declare no throws exceptions. to interface with Java, you might want to declare the method throw exceptions .. here is what you have .
and how do you instruct java system that you code may throws exceptions that the java code can add handler tro those exceptions.
import java.io._ class Reader (fname : String) { private val in = new BufferedReader(new FileReader(fname)) @throws (classOf[IOException]) def read = in.read() }and if you check the compiled bytecode.
// you will have this on the compiled code. // /*javap Reader.class Compiled from "31_2_Annotations.scala" public class Reader implements scala.ScalaObject { public int read() throws java.io.IOException; public Reader(java.lang.String); }*/
as an example of other java annotation (other than those standard annotation such as @deprecation which is an instruct to compiler), let's take the Junit's @Test annotation for example.
// Java annotations // import org.junit.Test import org.junit.Assert.assertEquals class SetTest { @Test def testMultiAdd { val set = Set() + 1 + 2 + 1 + 2 + 3 assertEquals(3, set.size) } }Compile and run it, you get the following.
scalac -cp junit-4.11.jar;.;hamcrest-core-1.3.jar SetTest.scala scala -cp junit-4.11.jar;.;hamcrest-core-1.3.jar SetTest when run it scala -cp junit-4.11.jar;.;hamcrest-core-1.3.jar org.junit.runner.JUnitCore SetTest JUnit version 4.11 . Time: 0.366 OK (1 test)
now we are going to create our own annotations, like the below.
// file // Ignore.java // description: // show you how you can create a Java annotation import java.lang.annotation.*; import java.lang.annotation.ElementType; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Ignore { }and we write the following scala code.
// suppose we have the Ignore annotation declare in Java object Tests { @Ignore def testData = List(0, 1, 1, 5, -5) def test1 { assert(testData == testData.head :: testData.tail) } def test2 { assert(testData.contains(testData.head)) } }and we write a function that finding the Tests.
object FindTests { def main(args : Array[String]) { for { method <- Tests.getClass.getMethods if method.getName.startsWith("test") if method.getAnnotation(classOf[Ignore]) == null } { println("found a test method : " + method) } } } /*$ scala FindTests found a test method : public void Tests$.test1() found a test method : public void Tests$.test2()*/
A note that we may use to build the code is like this:
$javac Ignore.java $scalac Tests.scala $scalac FindTests.scala $scala FindTests
foreword
for java types, you have Iterator<Component> in Java and Iterator<Component> in Scala, but what for the type Iterator<?> or Iterator<? extends Component> or even raw type Iterator.
We have the existential type. as follow.
// existential type are fully supported in Scala, type forSome { declaration }the {declaration} part is a list of abstract vals and types. the interpretation is that the declared variable and types exist but are unknown, just like abstract members of a class.
Java Iterator<?> would be written in Scala as :
type forSome { type T}
Java Iterator<? extends Component> would be written in Scala as :
type forSome { type T <: Component>}placeholder syntax. it means the same as the type forSome { declaration } (with the type forSome { type T}
Iterator[_]
Iterator[_ <: Component]for the declaration as follow for the code is as follow. "type forSome { type T <: Component>}"
to test the placeholder and the existential type, we write the following java code.
import java.util.Collection; import java.util.Vector; // FIle // Wild.java // Description: // this show you a java class with Wildcard public class Wild { public Collection<?> contents() { Collection<String> stuff = new Vector<String>(); stuff.add("a"); stuff.add("b"); stuff.add("see"); return stuff; } }and with this, we can test with the following scala code.
// run it with the following commands // scala // :cp . // val contents = (new Wild).contents val contents = (new Wild).contents contents.size()this is a no-brainer. however, let's see a more convoluted example as follow.
// a more complicated examples is as follow. import scala.collection.mutable.Set val iter = (new Wild).contents.iterator val set = Set.empty[???] // quandry here , what we fill in here while (iter.hasMore) set += iter.next()as above, what value we provide in the ??? place? there are two solutions to attack this problem.
import scala.collection.mutable.Set import java.util.Collection abstract class SetAndType { type Elem val set : Set[Elem] } def javaSet2ScalaSet[T](jset : Collection[T]): SetAndType = { val sset = Set.empty[T] val iter = jset.iterator while (iter.hasNext) sset += iter.next() return new SetAndType { type Elem = T // not val Elem = T val set = sset } }so in general, when programming against Scala, prefer abstract member instead of existence type.
for compatibility's sake, Scala provides access to Java's concurrency primitives, the wait, notify, and notifyAll methods can be called in Scala, and they have the same meaning as in Java, Scala doesn't technically have a synchronized keyword, but it includes a predefined synchronized method that can be called as follow.
var counter = 0 synchronized { // One thread in here at a time counter = counter + 1 }
scalac has support to compile against Java Source code as well as Java calss. scalac compiler won't compile those source code, but it will scan them to see what they contains. later you can compile those java code with those Scala source code.
scalac -d bin InventoryAnalysis.scala InventoryItem.java Inventory.java javac -cp bin -d bin Inventory.java InventoryItem.java InventoryManagement.java scala -cp bin InventoryManagement