As you may know already, JRuby gives you access to the Java class library, so that you can do things like write Swing applications in Ruby. Of course, that also means that your JRuby code needs to deal with the exceptions that various Java classes can throw.
Exception handling is similar in Ruby and Java, but there are a few small differences. If you know both Java and Ruby you already know that in Java we use try
and catch
whereas in Ruby we use begin
and rescue
. But the principle is the same. Any code that could throw and excpetion goes into a try
(or begin
) block. If an exception is thrown, execution moves to the corresponding catch
(rescue
) block.
But Java has two slightly different types of exceptions: “normal” exceptions and runtime exceptions. The difference is that if you call anything that can throw java.lang.Exception
or one of its subclasses, then you must enclose that code in a try-catch
block. So, for instance, the following code will not compile:
1 public class ForNameTest { 2 public static void main(String[] args) { 3 Class.forName("java.lang.String"); 4 } 5 }
Trying to compile we get:
% javac ForNameTest.java ForNameTest.java:3: unreported exception java.lang.ClassNotFoundException; must be caught or declared to be thrown Class.forName("java.lang.String"); ^ 1 error
In Ruby, however, it is not required to put any code within a begin-rescue
block (in other words, Ruby treats all exceptions as they were Java runtime exceptions). Here is the equivalent JRuby code:
1 #! /usr/local/bin/jruby -w 2 3 require 'java' 4 5 java::lang::Class.forName("java.lang.String")
This will run without any problems. Notice another thing. I have specified the fully qualified name of the Java Class
class. The reason is simple. Both Ruby and Java contain a class called Class
. If I don’t qualify it, JRuby will assume that I want to use the Ruby class, which does not contain a forName
method. Keep that in mind when there is both a Ruby class and a Java class with the same name.
Also note that just because we don’t have to use a begin-rescue
in Ruby doesn’t mean that it is not a good idea. On the contrary, you should use exception handling to trap errors and do something useful when they occur.
Apart from that, dealing with Java exceptions in JRuby is very straightforward. Look at the following example:
1 #! /usr/local/bin/jruby -w 2 3 require 'java' 4 5 include_class 'java.lang.ClassNotFoundException' 6 7 begin 8 # This will work. 9 java::lang::Class.forName("java.lang.String") 10 11 # This will not. 12 java::lang::Class.forName("foo.Bar") 13 rescue ClassNotFoundException => e 14 $stderr.print "Java told me: #{e}n" 15 end
Simple, wasn’t it? The first call to forName
is not problematic because java.lang.String
is a valid class name. The second call will fail, because under normal circumstances we don’t have a foo.Bar
class (unless you have added one).
Leave a comment