IntelliJ IDEA. Debugger Essentials (2021)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone on the youtube on the meet and in the room i um really like to see you here in person because there there's a huge demand for this talk uh mostly from the english-speaking audience i i will speak um in english from my heart um so let's start uh today i'm going to talk about uh intelligent debugger essentials and the essentials because we i tried to tell everything about the debugger but the rehearsal took more than three hours so it seems like we need to split that into several parts and today we uh i will present the first part which is the very very very super basic like the things that most people who use the debugger knows already but maybe it would be nice to have the basis to speak on one language so first of all why do we debug and what is the debugger uh the debugger is a special tool uh debugger exists actually not only for java of course for many other languages and it allows to run the application in the strictly controlled environment usually allowing to execute the program line by line and to see the inner state of the application and to change it and to do some many many many other interesting things so first of all why we debug at all and the word debug and debugger has the has a bug inside so usually this tool is used for finding and fixing bugs and this is what it was created for and most people tend to believe that this is the only use case for this tool but it's not and i want to show you some more usages we are not going to talk about all of them today just about several and on the next lecture about the advanced debugging uh i will cover all of this so the second thing is code analysis which is the debugger could be used for and by code analysis i mean not the analysis inside the ide itself but the analysis by the user so when you see the code and you want to understand what it does you can basically interpret and execute the code in your mind in your head or you can use the debugger so using the runtime information having all the values and the and seeing the branches which the execution follows uh making uh understanding of the code much easier so just looking at the code with your eyes is much harder so people are coming please uh see okay so as i said what parts of the code are executed and the values of the variables and memory gives you much more information about your code also if you having problems figuring out what's happening inside the fully unknown huge code base usually it's much easier to start with debugging it because you will be able to easily see which part of the code is executed which are not and how are they executed so once again the dynamic part dynamic information from the runtime gives you much more understanding of the code also debugger allows you to change the behavior of your application because you can not only see the inner state of the program but you can also change it however you want and usually by changing the inner state people think about changing the source code which will change the in the inner state of the application with the debugger it's not the case you can modify the data uh anyhow you want so without changing the source code on the so if you need to reproduce for example the complicated setup [Music] you can either do that with your hands so sometimes it's really complicated and takes a lot of time or you can debug dive inside your application change the state of the variables of the memory and quickly appear in the state where the bug is reproducible sometimes it saves a lot of time also you can switch the application state on the fly so for example if your application like idea has a special test unit test mode you can switch it on the fly you don't need to restart it and there can be other application states and modes which you can once again switch on the fly and see how the application works in different condition without the need to restart it and reset variables or any other input information also i've heard about at least one company who did the patching of the real production um application and because the debugger has the hot swap ability which allows you to change the source code or change the code of the methods on the fly so you can easily change the application behavior on the fly fix box on the fly and do that even in the production i don't say it's a good way but anyway i've heard at least at least once about this experience and also i did that more than once with my idea which i used on my machine if i find a bug which is blocking me from my everyday activities i can quickly attach the debugger fix the bug hot swap my working idea and continue working until the for example next nightly build is available with the fix so this is kind of strange usage but any way possible uh what else with the regular source code if you need logging in your code you need to add some logging statements inside the source code and then you recompile rerun it reproduce the problem and see the log and i'll analyze this with the debugger you can do that on the fly without the need to restart the application recompile it and without even the need to change the source code so you can add any logging information at any place in the source code and see the data appearing as as you run it further on it user interface developers uh in the intellij for example but actually anywhere using intellij debugger could do painting debugging so intellij debugger could show you the image of any image object in the debug process so you can actually line by line debug the painting of the components in the user interface and by line by line i don't mean the line of lines of code but lines of the shape which is being painted on the screen um debugger can provide information about the memory so like any memory analyzer or the memory snapshot viewer it can show you all the contents of the java heap so any any object of any class could be analyzed and changed and you can do whatever you want with it just like in any memory analyzer of course the functionality it provides is kind of less smart and it's just minimal but for many many use cases it is enough and actually there's a lot of more usages here i want to say about one of them which i call a breakpoint bump and uh this is funny technique so when you uh struggling to reproduce a bug on your machine and what i do i set a bug a bug a breakpoint with a special condition so that this breakpoint is triggered only when the bug appears and then i forget about it so i use the debugged idea for some time and usually after day or two i can reproduce suddenly i hit this break point and bumps the bug is reproduced so i don't do anything i put a breakpoint bump and someday it will blow and i will find myself in the situation where the bug is reproduced so what's the point in that if we can set more logging in that place and the reason why this is better is that with the logging you only get the stack trace and the information you set it to log to be locked if you stop on a breakpoint you can observe any data any state of the application so that the analysis of how you got into this situation is much easier when you have the running application in the debugger okay as i said there's actually much more usages of the debugger i will not talk about all of this today but you got it thank you well actually it's not all now we switch to the demo so the rest of the presentation will be in the idea i hope you are familiar with the basic presentation of the code and the idea this is a presentation mode so there's no funny tool windows and so on but hopefully you can see the the code so this is a sample application i i just did for for this presentation it reads the input it it prints it back it does some simple filtering of the input and it does some simple processing uh after that and it's all done in the endless loop so that we can see what's happening in the debugger inside so how do you run the application in the debug mode um the talk is about essentials so you just start it with the debug action of course so you can do run or you can debug for debug you do debug it's easy so now we have the application running in the debug mode and why i'm talking about this many people are used to the idea that the once again debugger is a tool for finding bugs and if i don't find i don't if i'm not looking for bugs i don't need debugger as i said before it may be not true because if you run your application you may appear in a situation where you need to analyze the inner structures and if you run it and not have started it with the debug action for java it is not possible to debug it after that so you may be able to do the thread dumps but you will not be able to observe the in a structure to run it line by line and so on so i prefer to always start the idea using the debug action just in case because historically debuggers slow down the execution of the application but it's not the case today the overhead exists but for many many many use use cases it's really really small so i usually use my own idea in with the debug options and it may be slow in some cases but for most cases it's not visible at all and also if at any time i experience a bug and i can ask my colleague to debug me dmitry please debug me i always say to my colleague so he can attach to my machine debug my idea and quickly find the root cause of the problem so if i didn't start the idea in the debug mode this will not be possible i will have to restart the application and possibly or probably the bug will not be reproduced after that if you started with the debug once again you can easily and quickly debug it and find the root cause of the problem so now we have the application running in the debug mode what do we do well actually we can do anything you want so we can see that the application is working it accepts the input it does some output and what do we do next so um once again if this code wasn't this simple it may be hard to understand where to start the analysis from so in the debugger there is a special action called the pause program or the suspend and whatever you want to call it which will stop your application right there when it works right now so here you can switch to the debugger tab and see the all the threads which are working inside the application and now we are in the main thread i hope you can see that yeah and the call stack what is the call stack the call stack is the sequence of the method calls which uh led to the the place where we are right now and we are right now as you can see this highlighting of the line inside the native reed by its method so you can see from the bottom of the stack that we started with the main method and it called the read method you can see it on the line and the read method called fill method and the fill code called read again but it's another read and the read called read bytes and the read bytes is native method blocked inside the jdk waiting for the input here so now we can actually see where all of this started from so we can find the user code which led to the current state in the application so we can set a breakpoint what is a breakpoint a breakpoint is a point in the source code uh where the application will be stopped in the debugger if it reach reached this point in in the execution so we can resume now this action resumes the flow of the application inside the debugger and we can type something here and now you can see that we stopped on a break point so we set it here using a click on a gather gutter or you can use the shortcut to to set and then unset it it's easy what else you can do with this you can once again resume it and you can see that that we stopped here once again and that is because actually even though we entered just one letter um the input contains two symbols one is the letter and another one is the line break or the some other symbol probably line break so even the information that we stopped here twice twice gives you something already so we stop here twice i don't believe that many people understand could have understood that from the code itself so we entered only one letter but stopped here twice and this is only possible in debugger so you can understand it from the code that the input would contain two symbols okay so we can move this breakpoint using drag and drop for example or we can delete it there and set it again and put it inside this if so once again we type something here and now we can see that we stopped only once there we stopped twice here we stop only once so even from the fact that we stopped there twice and here once we can understand that filter does its job so it filters out something which is really nice because we haven't yet even saw the the code of the filter and now we see that it does not accept the line break symbol which is obviously that second symbol in in this sequence so what can we do next uh we can set several breakpoints at once so for example you want to stop on every line in this method you can easily do that using the multiple carets feature and you set multiple cards and then um call this set break by breakpoint action and it will set a breakpoint for every um line on on which you have the carrot for and this icon here means that there's no um executable information for this line inside the bytecode so the breakpoint will probably not work well not probably but for sure will not work and this check mark here means that there is information for this line and this breakpoint will work so uh for example for this line we cannot even set a breakpoint because there's no source on this line and for these lines and there is some source but for some reason because of jdk compile it this way for this line we have information for this now so um this is not a kind of really nice way to debug your application using multiple breakpoints i mean on every line and i will talk about this later what for example if you don't need some of your breakpoints temporarily you can disable them so i'm using the alt click or the middle mouse button click on on other operating systems to disable the breakpoints and they will simply stop working so these works and these don't i can disable all of them if i don't need them at the moment but if you really need to disable all of them there is a special action for that which is called mute breakpoints and what it does it simply disables all the breakpoints now you can see they are all became gray and it doesn't work at all so you can do whatever setup you need to prepare for the debugging and then you can enable them all at once again and once again they work so what's next as i said before it's not really nice to debug your application setting a breakpoint on every line so for sure you need a way to execute your application one one line by by one and for that we have special actions uh most useful of them are step over which will basically step over the line uh not going inside the method calls if there are any on the line and step into does the opposite it goes inside the method calls if there's any underline so you can see on this line we will go inside the filter method method yes isn't that nice okay and from here how to step out of here this is really trivial method but there's an action step out which will mostly do the continue execution until the return from the method and then stop so we can do this and now we actually stopped after the filter method okay so let's do some more interesting stuff for example here we have the math max call and if we do the step into we may actually think that we will appear in the max method but it's not true because the max method is from the jdk and by default we filter out such methods because usually people are not interested in the jdk or library methods so we do not step into those methods by default and there's a special filter set in the settings you can modify that if you want but if you really need to step into such methods you can use the force use the force yes the first step into method and it is red red arrow here and it will step into any method skipping all those filters so you can see that now we stopped inside the jdk max method and it's really simple so we step out and now let's step into this println print line it's more more fun so here on the second line you can see that we have two method calls which is right line and value off and if you do the step into here it will highlight both methods giving you the choice so you can choose which of them you want to step into and you can do that with the mouse or with the keyboard or you can just do the step into shortcut again and it will select what is chosen right now so we we do this stepping inside the right line and we appear here um what if you want to skip some lines so like here what if i want to stop on on this line uh without doing step over again and again there's a special action for that called run to cursor and what it does is basically written here it continues until you reach this line so you can think about it as setting a temporary breakpoint on that line and resume and also you can do that using the click on the line numbers and it has the tool tip or on the mac you can do the force touch on the touchpad ah that's great i i never use the force touch but this this one is really useful if if you can get used to this okay so let's continue this and stop and suspend again so here in the stack as i have shown before there are many frames from the jdk and one frame from the user program and you can see that some frames have this yellow background so for me when i started using intellij debugger it took like several months to understand why the background is yellow for some frames and for some frames actually in the idea project the background could be blue and also green so if you don't know the background for any class of file can be yellow green or blue in in the idea project so even in the um project view as you can see the library classes are have yellow background and actually test classes have green background and intellij idea project blue background is used for the open api classes this is actually set up in the file colors and it is not about the debugger but debugger uses this as well for the highlighting in the stack frames so in the idea project there is more settings here for the open api and actually for the c line they use the violet or purple i don't remember just in case you see these strange colors there now you know what it is now you want to know more about the inner structure of the application i mean inner state of the application so how do you see that you stop somewhere the easiest way to see the values of the variables is the inline debugger so you can see here after the end of the line of the source code appeared the information about the values so read has the value of 100 it's i think it's obvious here some people may ask why we show it twice actually we show it once for the nearest usage of the variable so here for example read and the nearest usage is here and this one is for the declaration so we show it here because it is declared here and args is declared on this line and never used so we show the value only once and this one is an empty array this is the easiest way and sometimes you may need more so for example here you can see that the s value is an exclamation mark and text out is a and then the type and the unique number of this object and this object does not provide the tostring information so we only show this here and the information is updated so if you get the values you need from there then you don't need anything else but what if you need more so there is the variables tab where you can see all the values of all the variables available from this context so for this method you have this set of variables visible and you can switch frames and obviously the visible values changes and you can expand this and see the inner structure of the objects all the fields no matter private fields public fields debugger can show you values of anything anywhere and from here you can quickly jump to the declaration of this variable or you can quickly jump to the type source for the objects and what if you want to see something which is not in the inline debugger information or the variables view so for example here on this line let's stop there uh we have a complicated expression containing a method call and and some other logical operations so obviously you can see the value of this simple variable and you can see that in the inline debugger information but you cannot see it for this expression because it involves method calls and we don't invoke methods because debugger is afraid to somehow modify this state of the program so we expect the user to ask the debugger to do that for them and for that we have the quick evaluate functionality the easiest way to use that is to hold the alt uh modifier and to move your uh to hover the mouse over the parts of the expression you want to evaluate it will automatically expand the selection to to the expression uh correct expression so for example you can start with arg and the value is obviously 100 and then evaluate max also 100 and then this expression is zero and of course it's true so this is the easiest way to get the value of an expression which is available in the source code and if you don't use the mouse you can do the same from the keyboard using the quick evaluate shortcut which is as far as i remember command alt f8 and you don't need to do the selection just set the caret somewhere where it's obvious what expression you want to to observe and it will and get the expression and the value itself if you want you can of course do the selection and the old way and and once again hit the quick overlay and see the result and if it is an object you will see the result in a slightly oops sorry a slightly different way it will show you the whole tree with all the fields and and the rest so you can um inspect the object from here and then just close it and forget about that um what if you want to see the value of an expression which is not in the source code so for example here in the print writeline method i want to check if the string contains for example a symbol so i i do that with the evaluate expression dialog here you can write any expression in java or in kotlin or in any other language which you are currently writing in and you write it as uh if you uh been in the code itself so you are in the same context and the variables are available and you can call any methods and do whatever you want and also what's good inside the debugger as i said before you can invoke any methods including private methods and debugger don't care about such things uh so i don't know maybe i want to check if the line starts with one and which is obviously false and once again you can hover and if you forget the value of s and check the value okay and then you can do whatever you want with the oops sorry with the um expression with the result of the expression you get from here so for example you can do the concatenation of the strings and then you can i don't know check something from from other parts of the system um for example get property with the nami osni yep so basically you can do whatever you want just like if you were in the program itself and here here you can switch to the code fragment fragment mode which is basically multi-line version of what we had before and you can write a small program here with any kinds of things you would like so for example i can oops i can dump some numbers and you can see the output in the console and you can once again use the information from the current context so once again basically you can write a small program here and actually many people do this so when they find the bug or the problem in the application and they have the fix they quickly check that the fix works inside the evaluate expression or the code fragment dialogue and then they don't need to apply the fix and check it again because they have done it or already in in the debugger if for some reason you need even more so for example you need to see the the result of an expression in any context debugger has the watch functionality so you go to the variables tab and you hit the new voice action and from here you can write once again any expression and the difference with that evaluate expression dialog is that this expression will be evaluated in on every stop in every frame so you will have it here on top of the variables all the time so if you need this you you may use this once again so for example um uh that thing the with the os name for example you want to know it everywhere so it will be reevaluated on every stop in every um location so for example if you use a local variables here you will probably end up having this expression being unable to evaluate in other contexts but sometimes it is useful and you delete it and you can reorder them if you have more than one and also you can add them from the editor using the add to watches so it once again as in a quick evaluate it will automatically find the expression and add it to the watches and what's more interesting here you can do that from here so for example you you have the deeply nested field or or something else and you want to see it on top so you just drag and drop it from here and it will automatically generate the expression and have it here and once again you can drag and drop from the editor itself to this variables view and that will create the watch for you uh what's more uh what if for example here in the read so as we know filter will filter out the 10 because uh 10 value because it's it's the line break value what if we don't want it to be filtered out so we we check it here filter returns false so obviously we will not go into process so we can go here we can issue the set value and change the value to i don't know ten thousand more so now we change the value and the filter doesn't filter this out so we proceed to the process and well basically here we can change it back so just in case we wanted to check how it works inside the process and then we can actually change not only the primitive values but the values of any object so here s is the exclamation mark we can go here and change it to the question mark for example and we resume the program and in the console we can see that it really printed the new modified data and once again you can do that with any field uh almost any field for final fields it's it's not possible but with almost any field and almost any follicle variables that's true as well this is really useful as i have shown before if you have some branches which you want to see how they work and you don't have the data right now to be able to step into the method so you change the data and you can go into any branch you probably wasn't able to go before um and now the top feature of today's presentation some really experienced developers who were not really familiar with the debugger before like once in a year one of them come and ask about a feature in a debugger and the top voted feature from those people are was the ability to stop on a break point not always but only if certain condition is met and uh hopefully and luckily for them um this feature was uh implemented like almost 20 years ago and it is called um the breakpoint condition so if if you right click on a breakpoint you can see the settings of the breakpoint and i will not talk about any uh other than condition today so the condition is basically an expression which is evaluated on every hit of the breakpoint and if the value of this condition is false we are not stopping the application there so for example here we don't want to stop if the read is 10. so we set a breakpoint condition condition and we don't stop when the value is 10 so that's i will show it to you so now the value is not and for 10 we just haven't stopped and using this technique you can once again here write any expression you want using any local variables or fields or any other information you need from the current context and it greatly reduces the number of hits for certain breakpoints for example if a breakpoint is in the very widely used method you can limit the number of hits using this so um i think basically this is it for today so any questions uh so they might take the mic or it will not be on the i don't know how to turn it on okay automatically yeah and i understand so the question was that the uh conditional breakpoints has uh have the overhead so if you have this breakpoint set in in a really hot loop or or whatever method that is used really really often this may slow down the application uh so much that you will not be able to wait until the the hit of the real hit of the breakpoint is this is true and and the the the question after that was that is it possible to implement it using the hot swap so um currently we're discussing essentials so i will talk about this uh in the next talk uh it is true that uh some people [Music] kind of use a workaround of this so they put this condition here and they do the hot swap uh like re re uh define the method body as i said before and they set a breakpoint on this line so you can do whatever you want here and set a breakpoint and if you hot swap this code it will really work much faster and the breakpoint will be hit in the same conditions as before so the question was is it possible to do that automatically to be able to set such breakpoints without the overhead is that true yes and there is as i remember there is such bug it is possible but right now we just don't do that i i if you really want i can explain you why we don't do that right now but probably after the talk um i have a question about watch uh you said that when you add a watch it's uh it's shown on every stop on every breakpoint so but if i want to show some in watch some local information for example i have two breakpoints and in at one breakpoints it's some combination of local variables so in our place it's uh useless so how to make a watch local for for example i wanted to show it every time in on this break point on this place but not on our hours so there are some ways uh to do that um but once again it's not about the essentials so i will probably talk about this on on the next talk so uh in short um there is a request to really keep the watches context dependent uh to be available only in certain contexts or certain methods or certain classes for your case um you may use the uh class level watches what is called lost level watches i don't want to deep dive into this today but in short you can add a watch inside the class so you do the new class level watch and it will be available inside the uh inside all the objects of this class so this is not exactly what you're asking for but in most cases it really helps so for example you want to see i don't know the get class of this method and in any object of this print stream class you will have this node on top so for many cases this helps but it's not it's not about essentials more questions on the phone okay then we are done thank you you
Info
Channel: IntelliJ IDEA by JetBrains
Views: 14,389
Rating: undefined out of 5
Keywords: debugging java, java, debugging in intellij, intellij java, intellij idea tutorial, intellij idea, debugger
Id: 59RC8gVPlvk
Channel Id: undefined
Length: 45min 37sec (2737 seconds)
Published: Fri Feb 12 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.