A quick and dirty way to throw unchecked exceptions

95 views
Skip to first unread message

Christian Catchpole

unread,
Aug 25, 2009, 11:30:20 PM8/25/09
to The Java Posse
Compile this.. (any package you like, or no package at all)

public class Rethrow {
public static void unchecked(Throwable t) {
t=t;
}
}

javap reports the byte code as..

public static void unchecked(java.lang.Throwable);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: astore_0
2: return

which in hex is:

2A 4B B1

open the class file in the hex editor, search for that and change it
to:

2A BF B1

javap now reports the byte code as..

public static void unchecked(java.lang.Throwable);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: athrow
2: return

jar that class up or otherwise protect it from re-write.

In your code you can now call this without wrapping with a runtime
exception. And the stack trace is still that of the original
exception.

} catch(Exception e) {
Rethrow.unchecked(e);
}

Obviously, use at your own risk. No warrenties etc. :)

Marcelo Fukushima

unread,
Aug 25, 2009, 11:44:11 PM8/25/09
to java...@googlegroups.com
theres also a throwException(Throwable) in sun.misc.Unsafe - though to
use that you really have to want to
--
http://mapsdev.blogspot.com/
Marcelo Takeshi Fukushima

Christian Catchpole

unread,
Aug 25, 2009, 11:54:37 PM8/25/09
to The Java Posse
Yeah, i was reading about that one. But it's only in the Sun VMs and
probably subject to change.

But hey, I just listed this as an exercise. It just shows the
difference between checked and unchecked is one little byte. :)

Reinier Zwitserloot

unread,
Aug 26, 2009, 4:36:37 AM8/26/09
to The Java Posse
WTF? I already posted a much better version of this in the
supermegauber thread. no need for class file hacking. sun.misc.Unsafe
is an even worse idea (Security Manager issues, as well as a
dependency on running in sun VMs).

public class SneakyThrow {
public static RuntimeException sneakyThrow(Throwable t) {
if ( t == null ) throw new NullPointerException("t");
SneakyThrow.<RuntimeException>sneakyThrow0(t);
return null;
}

@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow0(Throwable t)
throws T {
throw (T)t;
}
}


Note also how this is much more thought through: Java does not know
that calling this method automatically triggers a throw statement, so
the compiler will whine that you need to return something, and the DA
rules are all messed up. Therefore, the suggested usage is:

public int myMethod() {
throw sneakyThrow(new IOException());
}

Note the 'throw' in front of 'sneakyThrow'. If you've read up on your
JLS and JVMS, you'll know that this code is perfectly valid java (and,
given sun's dogged adherence to backwards compatibility, should mean
it'll continue to work just fine), and that it'll work on every java-
compatible VM.

On Aug 26, 5:54 am, Christian Catchpole <christ...@catchpole.net>
wrote:

Christian Catchpole

unread,
Aug 26, 2009, 5:20:32 AM8/26/09
to The Java Posse
Ok, that's cool. But don't you think it's weird that the return value
isn't real. I mean, might someone not change the 'throw' to another
statement and get unexpected results?

I stand by my 'implementations' purity.. even if its not readily
compilable.

Fabrizio Giudici

unread,
Aug 26, 2009, 5:53:27 AM8/26/09
to java...@googlegroups.com
Christian Catchpole wrote:
> Compile this.. (any package you like, or no package at all)
>
> public class Rethrow {
> public static void unchecked(Throwable t) {
> t=t;
> }
> }
>
> javap reports the byte code as..
>
> public static void unchecked(java.lang.Throwable);
> Code:
> Stack=1, Locals=1, Args_size=1
> 0: aload_0
> 1: astore_0
> 2: return
>
I'm surprised - I expected that the compiler would optimize out the
useless operation and only output the return...

--
Fabrizio Giudici - Java Architect, Project Manager
Tidalwave s.a.s. - "We make Java work. Everywhere."
weblogs.java.net/blog/fabriziogiudici - www.tidalwave.it/blog
Fabrizio...@tidalwave.it - mobile: +39 348.150.6941

Christian Catchpole

unread,
Aug 26, 2009, 6:09:08 AM8/26/09
to The Java Posse
yeah, don't take too much notice of that. i noticed that if you
disassemble a "throw", it doesn't have a return. but the a=a does.
maybe its requirement of bytecode that a method that does return,
finishes with return byte code. but its like Java strings being a
char array with a size. there's no need to terminate it. it cant run
off the end.

On Aug 26, 7:53 pm, Fabrizio Giudici <fabrizio.giud...@tidalwave.it>
wrote:
> Fabrizio.Giud...@tidalwave.it - mobile: +39 348.150.6941

Christian Catchpole

unread,
Aug 26, 2009, 6:09:58 AM8/26/09
to The Java Posse
Oops. i totally misread your comment.. yeah, i was surprised as
well. :)

On Aug 26, 7:53 pm, Fabrizio Giudici <fabrizio.giud...@tidalwave.it>
wrote:
> Christian Catchpole wrote:
> > Compile this..  (any package you like, or no package at all)
>
> > public class Rethrow {
> >     public static void unchecked(Throwable t) {
> >         t=t;
> >     }
> > }
>
> > javap reports the byte code as..
>
> > public static void unchecked(java.lang.Throwable);
> >   Code:
> >    Stack=1, Locals=1, Args_size=1
> >    0:   aload_0
> >    1:   astore_0
> >    2:   return
>
> I'm surprised - I expected that the compiler would optimize out the
> useless operation and only output the return...
>
> --
> Fabrizio Giudici - Java Architect, Project Manager
> Tidalwave s.a.s. - "We make Java work. Everywhere."

Christian Catchpole

unread,
Aug 26, 2009, 6:29:48 AM8/26/09
to The Java Posse
of course it's need a return if it's NOT being JITted... im talking a
load of crap tonight.. aload_0 f crap.. get it! :)

On Aug 26, 8:09 pm, Christian Catchpole <christ...@catchpole.net>
wrote:

Reinier Zwitserloot

unread,
Aug 26, 2009, 12:59:36 PM8/26/09
to The Java Posse
The pain of being an idiot, not reading the javadoc on sneakyThrows,
and presuming that the return value has any meaning whatsoever is not
something I'm going to get concerned about. Everyone is an idiot
sometime, but there's a line, and that's far removed from it.

Contrast this to the sheer amount of shit you have to waltz through,
not to mention the lack of compiler help (as the compiler will
_erroneously_ think the thread will keep going and thus FAIL to tell
you about unreachable code!) - which makes this a clear cut case. My
way is superior :P



On Aug 26, 11:20 am, Christian Catchpole <christ...@catchpole.net>

Marcelo Fukushima

unread,
Aug 26, 2009, 1:27:59 PM8/26/09
to java...@googlegroups.com
but your version has the disadvantage of being visible

i (and i hope christian too) was hoping for a more magical way of
throwing checked exceptions

of course you shouldnt use those in an actual app

Marcelo Fukushima

unread,
Aug 26, 2009, 1:32:28 PM8/26/09
to java...@googlegroups.com
i guess nowadays javac translates almost literally the source code
into bytecode, leaving the hard work for JIT

Alexey Zinger

unread,
Aug 26, 2009, 1:54:28 PM8/26/09
to java...@googlegroups.com
There are quite a few optimizations with strings, for sure.  Such as replacing concatenation using "+" operator with StringBuilder and concatenation of literals with a single literal (*).

There's an interesting exception to that rule.  The following will work as expected:
"one " + "two " + "three"
gets turned into
"one two three"

However, in the context of this: public String getOne() { return "one "; }
this: getOne() + "two " + "three"
will not get turned into
getOne() + "two three"

Sorry if this was off-topic.
 
Alexey
2001 Honda CBR600F4i (CCS)
1992 Kawasaki EX500
http://azinger.blogspot.com
http://bsheet.sourceforge.net
http://wcollage.sourceforge.net



From: Marcelo Fukushima <take...@gmail.com>
To: java...@googlegroups.com
Sent: Wednesday, August 26, 2009 1:32:28 PM
Subject: Re: Optimizations? was Re: [The Java Posse] A quick and dirty way to throw unchecked exceptions

Reinier Zwitserloot

unread,
Aug 26, 2009, 2:09:06 PM8/26/09
to The Java Posse
lombok's @SneakyThrows is a magical way of throwing checked
exceptions. the lombok proof of concept spinoff
'disableCheckedExceptions' goes a lot further - though that might be a
bit beyond what you were looking for.

more info:

http://projectlombok.org/features/SneakyThrows.html

http://projectlombok.org/disableCheckedExceptions.html

Casper Bang

unread,
Aug 26, 2009, 2:16:34 PM8/26/09
to The Java Posse
Reinier I wanted to do a less invasive version of
disableCheckedExceptions, however I can not get your initial
disableCheckedExceptions to run:

error: Exception thrown while constructing Processor object:
java.lang.UnsatisfiedLinkError: Error looking up function
'Agent_OnAttach': javac: undefined symbol: Agent_OnAttach

I can see that the annotation processor is being picked up but
something obviously misfires on Java 1.6.0_14 64bit Ubuntu. Did you
mention something about a JNI call into a native platform library?

/Casper

Marcelo Fukushima

unread,
Aug 26, 2009, 2:34:32 PM8/26/09
to java...@googlegroups.com
im guessing its because of the "receiving" side of the append
function? have not tried, but id hope that

"two " + "three " + one()

would become

"two three " + one()

?

Alexey Zinger

unread,
Aug 26, 2009, 2:47:13 PM8/26/09
to java...@googlegroups.com
Correct.

From: Marcelo Fukushima <take...@gmail.com>
To: java...@googlegroups.com
Sent: Wednesday, August 26, 2009 2:34:32 PM

Christian Catchpole

unread,
Aug 26, 2009, 5:14:26 PM8/26/09
to The Java Posse
Yes, the desire for the throw dawned on me. Not that you included
such javadoc in this thread.

On Aug 27, 2:59 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
> The pain of being an idiot, not reading the javadoc on sneakyThrows,
> and presuming that the return value has any meaning whatsoever is not
> something I'm going to get concerned about. Everyone is an idiot
> sometime,

Even you Reinier? Not possible :)

Christian Catchpole

unread,
Aug 26, 2009, 6:31:58 PM8/26/09
to The Java Posse
My class did have debug symbols. I guess no point having symbols that
don't point to anything.

Peter Becker

unread,
Aug 26, 2009, 5:43:55 PM8/26/09
to java...@googlegroups.com
Alexey Zinger wrote:
> There are quite a few optimizations with strings, for sure. Such as
> replacing concatenation using "+" operator with StringBuilder and
> concatenation of literals with a single literal (*).
>
> There's an interesting exception to that rule. The following will
> work as expected:
> "one " + "two " + "three"
> gets turned into
> "one two three"
>
> However, in the context of this: public String getOne() { return "one "; }
> this: getOne() + "two " + "three"
> will not get turned into
> getOne() + "two three"
If I am not mistaken the compiler can not replace that without
potentially breaking the code. You method is public and non-final, which
means it can be overwritten, so you need the dynamic dispatch, inlining
is not ok.

The JIT might do a different thing since it knows the state of the
running system. If it should optimize that call it will need to be able
to revert it if a baseclass of the class you describe is loaded.

If the method getOne() would be either final or private, then the
compiler should theoretically be able to inline it. No idea if it would.

Peter

Christian Catchpole

unread,
Aug 27, 2009, 4:20:51 AM8/27/09
to The Java Posse
hmm.. think you missed the point there peter. "two " + "three" ==
"two three" regardless of what comes before it. But I think i might
know why the optimizer picks up

"one " + "two " + "three"

but not

getOne() + "two " + "three"

it probably sees this..

(("one " + "two ") + "three")
==
(("one two ") + "three")
==
("one two three")

It can collapse one two, then the third because they are all constant.

((getOne() + "two ") + "three")

the first collapse produces something unpredictable.

Peter Becker

unread,
Aug 27, 2009, 7:07:08 AM8/27/09
to java...@googlegroups.com
I did miss the point (or in fact the little word "not").

I think your theory is probably right, although in the absence of
arbitrary operator overloading it seems quite clear what the type of
(getOne() + "two ") is and since string concatenation is associative it
would be a valid optimization. But it requires a bit more reasoning.

Even with operator overloading the case would IMO still be clear since
the return type of getOne() is exact due to String's finalness. But
then: we are talking Java, other JVM languages might break some of these
rules.

Peter

Christian Catchpole

unread,
Aug 27, 2009, 8:08:34 AM8/27/09
to The Java Posse
Maybe I missed your point :) I thought the original question was why

getOne() + "two " + "three"

doesnt become

getOne() + "two three"

even if it was

getTotallyRandom() + "two three"

Peter Becker

unread,
Aug 27, 2009, 8:40:08 AM8/27/09
to java...@googlegroups.com
I thought your comment to my post was quite appropriate -- I really had
misread Alexey's post.

But maybe we are just entangled in some weird kind of dance, missing
each others point until the end of time. Or something.

Bedtime.

Peter

Christian Catchpole

unread,
Aug 27, 2009, 8:44:19 AM8/27/09
to The Java Posse
yes that's.. i have a habit of posting.. re-reading.. and doh!-ing :)

Reinier Zwitserloot

unread,
Aug 27, 2009, 8:45:45 AM8/27/09
to The Java Posse
I can confirm that the compiler is completely unaware of multi-arity
operators (the notion that + takes 2 OR MORE elements - it just takes
2 elements, no more, and multiple applications are merely this notion
chained), and that these are always resolved in a strict left-to-right
fashion.

You can see the same weird shenanigans when trying to add numbers and
non-numbers together:

5 + 3 + "foo" = "8foo".
"foo" + 5 + 3 = "foo53".

On Aug 27, 10:20 am, Christian Catchpole <christ...@catchpole.net>
wrote:

Casper Bang

unread,
Aug 27, 2009, 9:08:50 AM8/27/09
to The Java Posse
That's how all compilers I've seen do things. It's all just parser
rules and associativity that maps to unary or binary tree nodes which
then is collapsed in the desugar/optimizer phase. Nothing unusual
about that, classic divide and conquer I'd say.

/Casper

Peter Becker

unread,
Aug 28, 2009, 4:50:48 AM8/28/09
to java...@googlegroups.com
+ is a binary operator. In mathematics it tends to be associative, i.e.
it doesn't matter if you do (a+b)+c or a+(b+c), but it would be resolved
by combining two values at a time.

The Java compiler does do the right thing, but by allowing mixed type
operations with semantics depending on the types the associativity is
broken.

Peter
Reply all
Reply to author
Forward
0 new messages