garrnoel guilietta zarick

0 views
Skip to first unread message

Lyric Maro

unread,
Aug 3, 2024, 1:47:08 AM8/3/24
to erdenhumen

If a file with breakpoints was modified externally, for example, updated through a VCS or changed in an external editor, and the line numbers have changed, breakpoints will be moved accordingly. Note that IntelliJ IDEA must be running when such changes are made, otherwise they will pass unnoticed.

Field watchpoints: suspend the program when the specified field is read or written to. This allows you to react to interactions with specific instance variables. For example, if at the end of a complicated process you are ending up with an obviously wrong value on one of your fields, setting a field watchpoint may help determine the origin of the fault.

Exception breakpoints: suspend the program when Throwable or its subclasses are thrown. They apply globally to the exception condition and do not require a particular source code reference. Unlike stack traces, suspending an application on an exception allows you to examine the surrounding context or data while it is still available.

Caller filters: limit the breakpoint operation depending on the caller of the current method. Select if you need to stop at a breakpoint only when the current method is called (or not called) from a certain method.

Classes and methods are specified using fully qualified names. If a filter is specified through a class name, it points at the class itself and all its subclasses which use its members via inheritance.

You can use patterns that begin or end with the * wildcard to define groups of classes or methods, for example *.Foo or java.*. A filter specified through a pattern points at classes/methods whose fully qualified names match this pattern.

In caller filters, use descriptors for parameters and return types, for example: mypackage.MyObject.addString(Ljava/lang/String;)V. For detailed information on descriptors, refer to the official Oracle documentation.

Select to make the breakpoint work when the specified exception was not caught. This allows you to examine the program state and detect the cause before the program or thread crashes due to unhandled exception.

If it is technically possible to suspend the program at the breakpoint, however there are issues related to it, the debugger sets the breakpoint status to warning. This may happen, for example, when it is impossible to suspend the program at one of the method's implementations.

Use non-suspending logging breakpoints (sometimes referred to as watchpoints in other debuggers) instead of inserting print statements in your code. This provides a more flexible and centralized way of handling debug log messages.

To set a non-suspending logging breakpoint, hold Shift and click the gutter. This will not suspend the program execution and instead log a message like Breakpoint reached at ocean.Whale.main(Whale.java:5). If you want to log some expression that is in front of you in the editor, select it before holding Shift and clicking the gutter.

If you have many breakpoints in your project, you can add descriptions to breakpoints for ease of search. To do this, right-click a breakpoint in the Breakpoints dialog Ctrl+Shift+F8 and select Edit description from the menu. Now when you start typing the breakpoint name, it gets the focus.

Due to JVM design, method references don't provide meaningful information in stack traces, as opposed to lambda expressions. Moreover, it is impossible to set a breakpoint on a method reference. If a method reference reduces traceability where it is critical, consider using a lambda instead.

As exception breakpoints work with Throwable, you can also use them to suspend the program when a subclass of Error is thrown. This is useful for investigating the causes of errors like OutOfMemoryError and StackOverflowError. With an exception breakpoint set up for them, you will be able to look into what happened in the program before it crashes.

A good way to find out if a multi-threaded program is robust in terms of concurrency is to use breakpoints that only suspend one thread when hit. Stopping a single thread may reveal problems in the design of the application, which would not otherwise be evident.

The solution is simple. Filter out the catching classes if they are in the java or sun root packages. We can do this in the current breakpoint dialog using the filter -java.* -sun.*, notice the - character used to filter out the packages. This one small class filter will remove that redundant noise and let you focus on exceptions that you catch or don't. An uncaught exception is almost always useful in the debugger, as it can lead to an application fatal error.

This limits the breakpoint to the current object. This is something I would normally use a conditional breakpoint for. The problem is that conditions might cause a mistake, e.g. in a case where instances are harder to differentiate. Conditions also require more work.

Class filter seems redundant at first until we look at the more elaborate breakpoints we have in place. A good example is field watchpoint, which can be triggered by access from a different class, assuming the field isn't private.

Let's say you have a public field and you're concerned someone is reading or writing to it from outside of your class. Your code can't be changed as there's too much legacy. Usage info shows you who's using it, but it's spread all over the place... You just want to see if someone from outside the class is physically accessing the field at this frame of time...

Have you ever reached a breakpoint and looked at the stack... Then kept pressing continue until that stack changed to include the method you wanted in the stack. The one that invoked your call. This is where the caller filter comes in. You can exclude a specific stack element from consideration or require a specific method.

You may recall I mentioned you shouldn't use method breakpoints... They're usually just emulated by line breakpoints to avoid their typical overhead. So there's no actual need for them when placing one on a method.

But there's another approach. You can add a breakpoint using filters/names, e.g. you can add a breakpoint to all the methods starting with the word "is" in all the classes starting with the word "Prime" as we can see here.

This might sound excessive, but there's a common and valid use case. Imagine using a complex polymorphic API that follows a naming convention. It's hard to know which method is invoked to handle which behavior. This way, you can grab all suspects using a simple pattern.So how do you deal with the excessive noise?

For the last section, I'm going to go to the watch instead of the current breakpoint discussion. This is a feature that's so cool and so simple... Yet unfamiliar to many developers. When you right click an Object in the IntelliJ watch you can ask to show "all objects". This literally means ALL OBJECTS in the process!

When you do that on a Thread object, you see the JIT compiler thread. You can see internal JVM const message strings when doing it on a String array. When you're looking at a specific object and wondering "is this the right instance", well... You can review all instances and verify with a right click.

I hope this blew your mind. There are so many debugger capabilities that we sometimes gloss over when trying to build an application. The tools we discussed today are all designed for debugging large code bases. Where the capabilities of these tools really shine.

LinkedIn and 3rd parties use essential and non-essential cookies to provide, secure, analyze and improve our Services, and to show you relevant ads (including professional and job ads) on and off LinkedIn. Learn more in our Cookie Policy.

Continuing from part 1, here are some more debugging features that IntelliJ provides, with a short summary of each. Like part 1, this draws from the official IntelliJ documentation. This is a little wordier, but hopefully more informative.

IntelliJ lets you specify class/instance filters so that breakpoints only suspend when they are within a particular instance or class. This can be useful if you want to set a breakpoint in only a certain child of an abstract class, or only in a particular instance of a class.

To do so, right click on a breakpoint to get to the options. Then, specify the class/instance, either use the ID from the variables view or, once the breakpoint is hit, press alt + Enter and you should be able to enable the breakpoint only within that class/instance.

You can set a method breakpoint on an interface, to break on any implementation of the method. From the breakpoint options window you can also specify a wildcard pattern for the class the method should be in. One interesting use for the method breakpoint is to find the main method in the application (though I guess search should also yield this).

An exception breakpoint can be added from the breakpoint options window. This is particularly useful as it will break just before the exception is thrown, retaining all program state! This allows you to inspect variable values to determine why the exception may have been thrown. Further, you can specify either the specify exception to break on, or even stop on any exception (if the "any exception" option doesn't appear at first, try adding an exception breakpoint). In the breakpoint options window, you can also filter by caught/uncaught exceptions and even which class catches the exception (catch class filter)!

Reset frame lets you, well, drop the current frame. For example, if you're in a method, dropping the frame would take you out of the method (back in time!). Be wary if there are global state changes when dropping frames.

If you love pair programming, you can allow others to connect to your machine using remote debug. This requires the application to be started with certain parameters that allow remote connections (security risk, so make sure to shut down the application when done).

Renderers allow you to display information about instances in the variable window. This is useful for objects where the default toString method does not provide useful data, and/or where you are not in control of the toString method (for example, an object in a library you're using). You can specify a renderer by right-clicking on the variable and clicking on "View As -> Create Renderer". You can also specify how sub-entries should be rendered (for example, for a map).

c01484d022
Reply all
Reply to author
Forward
0 new messages