JRuby: Mit Java und Ruby die Entwicklungsarbeit optimieren

(http://www.zdnet.de/magazin/39159723/jruby-mit-java-und-ruby-die-entwicklungsarbeit-optimieren.htm)

von Chris Duckett, 20. Dezember 2007

EIn Ruby-Interpreter in Java - das kann doch nur Spielerei sein? Keineswegs: Der Artikel zeigt, wie JRuby die Vorteile zweier Programmiersprachen vereint, und liefert Beispielcode, der den Einstieg erleichtert.

JRuby ist eine 100-prozentige Java-Implementierung eines Ruby-Interpreters. Sie weist zwar nicht alle Funktionen von Ruby auf, verfügt aber dennoch über die meisten der eingebauten Klassen dieser Sprache. ZDNet demonstriert, wie JRuby die positiven Eigenschaften von Java und Ruby kombiniert. Außerdem liefert der Artikel einige wichtige Tipps und ein erstes längeres Code-Beispiel.

Es verseht sich von selbst, dass man sich sowohl mit Java als auch mit Ruby auskennen muss, um optimal mit JRuby zu arbeiten. Reine Java-Programmierer sollten also vielleicht erst einmal die einführenden[1] Artikel[2] zu Ruby[3] lesen, die gleichzeitig die Grenzen dessen abstecken, was hier erläutert wird.

Wo bekommt man JRuby?

Um mit JRuby zu arbeiten, empfiehlt es sich zunächst, die aktuelle Version des Archivs jruby-bin über die Codehaus-Website[4] zu beschaffen. Es enthält alles, was benötigt wird. Dannach muss die Archivdatei an einem beliebigen Ort extrahiert und der Pfad-Variablen your-jruby-dir/bin hinzugefügt werden.

Nun sollte Folgendes ausgeführt werden können:


jruby -v
ruby 1.8.5 (2007-08-23 rev 4201) [ppc-jruby1.0.1]

Erste Arbeitsschritte

Zunächst wird die interaktive Konsole verwendet, die mit diesem Befehl aufgerufen wird:


jirb
irb(main):001:0>

Da es sich bei JRuby um einen Ruby-Interpreter handelt, können beliebige Ruby-Programmzeilen ausgeführt werden.

Das ist soweit keine Überraschung. Doch der wahre Grund, diese Zeilen so auszuführen, statt mit dem nativen Ruby-Interpreter, besteht darin, sich Java zunutze zu machen. Nun kommt das Java-Framework ins Spiel:


irb(main):003:0> require 'java'
=> true

Der Versuch, einfach einige Standardzeilen Java-Code auszuführen, funktioniert jedoch nicht.

Um das Hello world-Beispiel zum Laufen zu bringen, muss man weit zurückdenken. Es geht um ein paar Angelegenheiten, die einem bei Java bereits selbstverständlich geworden sind.

Ein Besuch auf einer API-Seite[5], die wohl viele seit langem nicht mehr gesehen haben, bringt die Lösung: System ist ja ein Element des java.lang-Pakets, out ist ein Feld von System und println stellt wiederum eine Methode von out dar.

Deshalb ist für einen korrekten Aufruf Folgendes erforderlich:


irb(main):005:0> java.lang.System::out.println("Hello World")
Hello World
=> nil

Um die Sache interessanter zu machen - auch das funktioniert:


irb(main):005:0> java.lang.System.out.println("Hello World")
Hello World
=> nil

Und um zu zeigen, dass man Ruby und Java in derselben Zeile verwenden kann:


irb(main):006:0>  puts java.lang.System::err.println("Hello World")
Hello World
nil
=> nil

Bis jetzt wurde die Java-Methode zur Übergabe von Parametern verwendet. Dank Ruby kann man jedoch die Klammern weglassen.


irb(main):007:0> java.lang.System::out.println "Hello World"
Hello World
=> nil

Ein weiterer Vorteil von Ruby liegt darin, dass man leicht Einblick in Objekte erlangen kann. Die Reflection-API von Java wird dadurch quasi überflüssig.

Um einen Überblick über alle Methoden zu erhalten, muss einfach die methods-Funktion des Objekts aufgerufen werden, so wie man es auch in Ruby tun würde.

Auf ähnliche Weise lassen sich auch die Konstanten ausfindig machen:


irb(main):009:0> java.lang.Math.constants
=> ["PI", "E"]

Oder die Vorläufer einer Klasse:


irb(main):011:0> java.lang.Math.ancestors
=> [Java::JavaLang::Math, Java::JavaLang::Object, 
ConcreteJavaProxy, JavaProxy, JavaProxyMethods, Object, Kernel]

Sogar der Typ der Klasse lässt sich so anzeigen:


irb(main):012:0> java.lang.Math.class
=> Class
irb(main):013:0> java.lang.class
=> Module

Das Ausschreiben der vollständigen Namen von Paketen ist ermüdend. Um eine Klasse zu importieren, lässt sich auch die Funktion include_class einsetzen.


irb(main):015:0> include_class java.lang.System
=> Java::JavaLang::System

Die Klasse lässt sich dann genauso verwenden, als hätte man eine Anweisung in Java importiert.


irb(main):016:0> System.out.println("Wir wurden importiert")
Wir wurden importiert
=> nil

Das Importieren einer Klasse schlägt jedoch fehl, wenn versucht wird, eine Klasse zu laden, die im Ruby-Namensraum bereits existiert.


irb(main):014:0> include_class java.lang.Math
(eval):1 warning: already initialized constant Math
=> Java::JavaLang::Math

Die Lösung liegt hier in der Umbenennung der Klasse. In diesem Fall wird aus der Klasse Math die Klasse JMath.


irb(main):017:0> include_class('java.lang.Math')
{|package,name| "J#{name}"}
=> ["java.lang.Math"]

Diese kann dann folgendermaßen eingesetzt werden:

Bisher handelte es sich um ein paar nette Beispiele, aber nichts wirklich Großes. Nun geht es darum, den Code von dieser Seite[6] zu nehmen und dieselben Ergebnisse mit Ruby zu erzielen.

Einige Änderungen sind dafür erforderlich:


Der vollständige Code lautet somit:

Wenn man aus diesem Listing eine Datei macht, lässt sich diese folgendermaßen in JRuby aufrufen:


jruby testwin.rb

Oberflächlich besteht kein Unterschied zwischen der JRuby- und der Java-Version des Codes. Neben der offensichtlichen Performancebeeinträchtigung durch die Verwendung von JRuby besteht ein klarer Vorteil darin, dass Code mit gleicher Funktionalität weit schneller geschrieben werden kann.

Es lässt sich schon jetzt mit Spannung auf die Geschwindigkeitsverbesserungen warten, die sich ergeben werden, wenn JRuby einen JIT-Compiler erhält. Doch in der Zwischenzeit kann man, falls die Geschwindigkeit nicht so wichtig ist, schon einmal das eine oder andere mit JRuby ausprobieren.

URLs in diesem Artikel:
[1] = http://www.zdnet.de/builder/program/0,39023551,39141885,00.htm
[2] = http://www.zdnet.de/builder/program/0,39023551,39142011,00.htm
[3] = http://www.zdnet.de/builder/program/0,39023551,39157473,00.htm
[4] = http://dist.codehaus.org/jruby/
[5] = http://java.sun.com/javase/6/docs/api/java/lang/System.html
[6] = http://www.zdnet.de/builder/program/0,39023551,39157002-2,00.htm