Daniel Kaplan
Daniel Kaplan

Reputation: 67360

In Intellij, how can I throw an exception at a break point?

I see lots of questions about how to make Intellij break on exceptions. I'm trying to do something different: I want to throw an exception at a breakpoint so that I can see what will happen if an exception were to occur at that code.

I've figured out ways to force this. For example, if I have a variable called willBeUsed, I can hit a breakpoint and add a watch that says willBeUsed = null. This will trigger a NullPointerException eventually.

But I'm in a situation where I want to throw an IOException to see what happens. There's no way to trick my code into doing that. When I add a watch that says throw new IOException() it gives me an error saying, "unexpected tokens".

As a work around, I can modify the code to throw the exception and redeploy. But I'm wondering if there's a way to do this in the debugger without modifying source code.

Upvotes: 35

Views: 26965

Answers (6)

Marek F
Marek F

Reputation: 575

You can right-click on stacktrace and choose 'Throw Exception'

enter image description here

(Since 2018.1 version. See JetBrains issue: IDEA-148408)

Upvotes: 43

mbaranauskas
mbaranauskas

Reputation: 483

In the 'Debbuger' window 'Frames' section right-click current function and select 'Throw Exception'. Then enter exception you want to throw.

enter image description here

Upvotes: 10

MByD
MByD

Reputation: 137322

How about placing the throw statement in an if block, and only change the condition, e.g.:

boolean shouldThrowException = false;
// ....
if ( shouldThrowException ) //place breakpoint here
{
    throw new IOException();
}

When you hit the breakpoint, change the value of shouldThrowException to true.

Upvotes: 8

maba
maba

Reputation: 48065

There is another way where you take advantage of the JVM HotSwapping.

Let's assume that you are deploying code to some server. Then when you start the application make sure that you turn on remote debugging (which I think you have since you are debugging and are talking about deployment). If not then it will work evenly fine in the local debugger.

Now I have two classes, Main and Other.

package com.stackoverflow;

import java.io.IOException;

public class Main {
    public static void main(String[] args) throws IOException {
        doStuff();
    }

    private static void doStuff() throws IOException {
        System.out.println("doStuff");
        Other.otherStuff();
    }

    public static void throwException() throws IOException {
        throw new IOException();
    }
}


package com.stackoverflow;

import java.io.File;
import java.io.IOException;

public class Other {
    public static void otherStuff() throws IOException {
        File file = new File("Some_File.txt");
        file.createNewFile();
    }
}

The throwException() could be placed anywhere as long as it is "globally" available, in some util class for example. Now it is just placed in my Main class for convenience.

Now we can have a breakpoint set in our doStuff() method and while being held there we can change the code in the otherStuff() method so that it calls our static throwException() method.

public static void otherStuff() throws IOException {
    Main.throwException();
    File file = new File("Some_File.txt");
    file.createNewFile();
}

We have to call some method instead of invoking throw new IOException() because otherwise we will have an error with Unreachable statement.

Then we can press Ctrl+Shift+F9 to recompile the Other class. It will now be HotSwapped (a dialog will ask if you really want to do this).

Then press continue and the exception will be thrown.

The code can then be reverted back to normal state.

The good thing about this is that the recompiled class will even be hot swapped "over the wire" to the remote machine.

The important thing is that the code that you recompile must be in another class. The same class where you have your breakpoint won't be reloaded correctly.

As a work around, I can modify the code to throw the exception and redeploy. But I'm wondering if there's a way to do this in the debugger without modifying source code.

You will modify the code but only at the time when you want to, in the debugger. You can then revert back the small change and recompile to hot swap back the old code.

I hope you get the idea (no pun intended).

I can add screenshots if you want to.

Upvotes: 1

maba
maba

Reputation: 48065

I don't know if you have tried this but you could perhaps create a static method that only throws IOException and then call that method by issuing Evaluate Expression.

Simple example code:

package com.stackoverflow;

import java.io.IOException;

public class Main {
    public static void main(String[] args) {

        doStuff();
    }

    private static void throwException() throws IOException {
        throw new IOException();
    }

    private static void doStuff() {
        System.out.println("doStuff");
    }
}

Set a breakpoint on the System.out.println line:

enter image description here

Bring up the Evaluate Expression... window and call the throwException method (evaluate) and then you'll get a stack trace from within doStuff:

enter image description here

The exception will of course be in throwException but you see the whole call stack as well.

Upvotes: 1

Andreas Wederbrand
Andreas Wederbrand

Reputation: 39981

I can't see how this can be done. I've tried two approaches (perhaps my ideas will lead to some other ideas

1) I tried to use the debuggers "log evaluated expression" to throw new IOException() but all I get is a message that IDEA couldn't evaluate the expression.

2) I also tried to set a break point and when it stopped I open up the "evaluate expression" dialog to throw a new exception but that didn't work either.

I don't think the debugger can throw exceptions. @Binyamin's solution will work but you already mentioned that in your question. I can only add that in IDEA it's possible to uncheck the "suspend" checkbox and enter shouldThrowException = true in the "log evaluated expression" box. This will cause the debugger to just change the value (and log it) but not stop which is great in code that have many concurrent threads.

Upvotes: 1

Related Questions