Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut. -The Pragmatic Programmer, Tip #8 "Invest Regularly in Your Knowledge Portfolio", Andrew Hunt & David, Addison Wesley, 1999.
The Java Virtual Machine is no longer Java language exclusive. There is a large number of programming languages available for it, and some of them have grown both in maturity and popularity in the last couple of years, making them usable in production for “serious software development”. The most relevant ones at the time of writing this article are: Groovy, Scala, and Clojure; but there are others that worth been aware of if we are exploring the current JVM's language landscape.
Set your goal
It's very important to have a clear set of objectives when choosing a language to explore. Based on that idea, we can split language exploring in two main categories: choosing a language for learning, education and experimentation purposes; and on the other hand, choosing one for an industry level system development. In the first case, the objectives to satisfy are personal and include gaining knowledge of different programing styles or paradigms that are not readily available on Java. It is learning for the pure excitement of it, to explore the unknown and acquire knowledge keeping our minds as developers open and sharp. In the second case we are exploring a language based on it's usefulness in solving challenging problems in Java, or because there is a framework that fits best to solve a problem but is based on another language. Here we have a set of variables we should measure to make thoughtful, professional decisions including: platform maturity and stability, support ecosystem, community, licensing characteristics and corporate backup among others.
Building great work often requires more than one tool
However, we have to keep in mind that becoming effective polyglot programmers is a lot more than knowing a bunch of languages and mixing them up. It's more about knowing how to use effectively several languages that promote different programming styles and paradigms, as well as being effective in those programming styles, including: procedural, object-oriented, functional, event-driven, generic and metaprogramming among others. A very interesting exercise consist in applying a programming style that is not natively promoted in the chosen language. This kind of exploration is limited by the nature of the JVM and the languages available on it but not impossible.
Another possibility is choosing one of the general purpose, object-oriented, strongly statically typed programming languages that exists for the JVM as Java alternatives. Languages like Ceylon, Kotlin, Scala and Xtend can be used as Java substitutes that target solving some of the the problems in Java Language Design.
Where to start
Below we have a list of some general purpose JVM languages to start exploring:
Ceylon is an object-oriented, strongly statically typed programming language with an emphasis on immutability. The language design focuses on readability, predictability, toolability, modularity, and metaprogrammability.
Clojure is a dialect of the Lisp programming language and shares with Lisp the code-as-data philosophy and a powerful macro system. It is predominantly a functional programming language with a rich set of immutable, persistent data structures, but providing a mutable state when needed.
Frege is a Haskell dialect for the JVM, and thus is a non-strict, pure functional programming language.
Golo is a simple, dynamic, weakly typed language for the JVM, it is largely interoperable with Java and other JVM languages, supports imperative and functional programming patterns, and explicitly wants to serve as a foundation for programming and language derivative experiments.
Gosu is a statically typed, general purpose programming language; it’s a pragmatic low-ceremony language focused on readability.
Groovy is an object-oriented, dynamic, optionally typed language, with static-typing and static compilation capabilities. It’s features include: scripting capabilities, Domain-Specific Language authoring, runtime and compile-time meta-programming, and functional programming.
Kotlin is a statically typed programming language. It is designed to be an industrial-strength, object-oriented language, that is marketed as a better language than Java but still fully interoperable with Java code, allowing companies to make a gradual migration from Java to Kotlin. It supports object-oriented, procedural and functional programming.
the follow up major release will align with ECMAScript Edition 6. You can invoke Nashorn from a Java application using the Java Scripting API to interpret embedded scripts, or you can pass js scripts to the jjs or jrunscript tool. Currently Nashorn lacks some of the js browser APIs such as: HTML5 canvas, HTML5 audio, WebWorkers, WebSockets, and WebGL.
Scala is a multi-paradigm, strong static typed, functional, object-oriented, imperative and concurrent programming language. Designed to be concise and inspired by criticism of many of the shortcomings of Java.
JRuby is an implementation of the Ruby programming language for the JVM. It is tightly integrated with Java to allow the embedding of the interpreter into any Java application with full two-way access between the Java and the Ruby code. JRuby has built-in support for Rails, RSpec, Rake, and RubyGems. It embeds an FFI subsystem to allow the use of C libraries bundled as gems. It also allows launching the Interactive Ruby Shell (irb) as Ruby MRI does.
Jython is an implementation of the Python programming language for the JVM. Except for some standard modules, Jython programs use Java classes instead of Python modules. Jython includes almost all of the modules in the standard Python programming language distribution, lacking only some of the modules implemented originally in C.
Xtend is a general-purpose high-level object-oriented language for the JVM. Syntactically and semantically it has its roots in Java but with a more concise syntax and some additional functionality such as type inference, extension methods, operator overloading, and lambda expressions. It is statically typed and uses Java's type system without modifications. It is compiled to Java code and thereby seamlessly integrates with all existing Java libraries.