In the previous post, I discussed functions in Scala. There's a lot more power and flexibility to come, but for now let's expose a little at a time. In this post, we'll look at the way in which we can integrate with Java objects.
Given that Scala runs inside a JVM, it's possible to interact with Java's types. For example, we can pull a list of system properties trivially in Scala by using the same code as we could in Java:
scala> val properties = System.getProperties() properties: java.util.Properties = {java.runtime.name=Java(TM) 2 Runtime Environment, ... scala> properties.get("user.name") res1: java.lang.Object = alblue scala> properties.size() res2: Int = 55
It's easy enough to refer to methods of objects; it uses the same Java syntax to call methods with '.' — but there are some differences. For example, Scala doesn't have to supply the ()
for empty method calls:
scala> val properties = System.getProperties properties: java.util.Properties = ... scala> properties.size res3: Int = 55
For that matter, you don't even need to use the '.' to call methods; you can use spaces:
scala> System getProperties properties: java.util.Properties = ... scala> properties get "user.name" res4: java.lang.Object = alblue scala> properties size res5: Int = 55
If you're coming from an existing programming language that likes decorating the source code with punctuation, feel free to use it. Until you get comfortable with the syntax, it's possibly easier to use that form. To avoid confusion, I'll try and decorate the calls with syntax although in practice I rarely use it (so I might miss some places).
So, System
is a reference to a Java class (java.lang.System
) and we can invoke static
methods. We've also seen how we can get an instance of another class (with getProperties()
) and invoke instance methods. This is much like how Java deals with method invocation; and in fact, one of Scala's key benefits is to be able to quickly manipulate and process Java systems, much like you can with JRuby, JPython or even Groovy.
If we want, we can import
static methods in the System class, which makes them available without having to prefix calls with System
:
scala> import System.getProperties import System.getProperties scala> getProperties() res6: java.util.Properties: {java.runtime.name=...
If we wanted to import everything in System
, we'd use the wildcard. Unlike Java and C based languages, the wildcard in Scala is an underscore (_
), a convention from other languages like Prolog and ML. (In those languages, it's supposed to represent a 'hole', like a fill-in-the-blanks space, and can match against anything. Don't worry too much about it, and mentally translate _ to * until you get used to it.) We can now use other System methods like getProperty
:
scala> import System._ import System._ scala> getProperty("user.name") res7: java.lang.String = alblue
What if we want to use a method, but by a different name? We can do that by creating a mapping of old names and new names in the import statement:
scala> import System.{getProperty => property, getProperties => properties} import System.{getProperty=>property, getProperties=>properties} scala> property("user.name") res8: java.lang.String = alblue
In the syntax for the mapping we have here, we're using =>
in order to define the mapped values. This is a common operator in Scala, but rather than thinking of it as 'equal greater' (or confusing it with the greater-than-or-equal operator >=
) it helps to translate it mentally to 'leads to' or 'goes to' or even just 'arrow'. It's an ASCII equivalent of a fairly standard math symbol (⇒).
Creating new instances is easy; we just use the new
operator, as we would in Java:
scala> new java.net.URL("http://localhost") res9: java.util.URL = http://localhost
The import is used to import classes from a package, much like Java does, and also like Java, you can import either a single class or everything:
scala> import java.net.URL import java.net.URL scala> new URL("http://localhost") res10: new java.net.URL = http://localhost scala> import java.util._ import java.util._
So, if we can import a class method under a new name, and it's the same import style as for importing classes from a package, can we do the same here?
scala> import java.net.{URL => UniformResourceLocator} import java.net.{URL=>UniformResourceLocator} scala> new UniformResourceLocator("http://localhost") res11: java.net.URL = http://localhost scala> import java.awt.{Color => Colour} import java.awt.{Color=>Colour}
Now you can finally fix all those annoying typos in the Java language! Mind you, there are also valid times when you'd want to do this; if you want to (statically) enable or disable some logging or security component, you might want to use this to define a pseudo-type Factory
and then alias it to LoggingFactory
or SecureFactory
.
The imports are valid until the end of the block that defines them (or the end of the file). In the interpreter, they last until the end of the session. If you want, you can define imports inside class definitions or even in individual function blocks. It's possible to define multiple imports on the same line by comma separating the imports, or you can have them on several lines; but that doesn't work in the interpreter.
Armed with the ability to use and instantiate simple Java objects, we'll leave this post here; next time, we'll be looking at how to create objects in Scala.