说明 | 快捷键 |
---|---|
复制代码-copy | ctrl + c |
粘贴-paste | ctrl + v |
剪切-cut | ctrl + x |
撤销-undo | ctrl + z |
反撤销-redo | ctrl + shift + z |
保存-save all | ctrl + s |
全选-select all | ctrl + a |
说明 | 快捷键 |
---|---|
智能提示-edit | alt + enter |
提示代码模板-insert live template | ctrl+j |
使用xx块环绕-surround with … | ctrl+alt+t |
调出生成getter/setter/构造器等结构-generate … | alt+insert |
自动生成返回值变量-introduce variable … | ctrl+alt+v |
复制指定行的代码-duplicate line or selection | ctrl+d |
删除指定行的代码-delete line | ctrl+y |
切换到下一行代码空位-start new line | shift + enter |
切换到上一行代码空位-start new line before current | ctrl +alt+ enter |
向上移动代码-move statement up | ctrl+shift+↑ |
向下移动代码-move statement down | ctrl+shift+↓ |
向上移动一行-move line up | alt+shift+↑ |
向下移动一行-move line down | alt+shift+↓ |
方法的形参列表提醒-parameter info | ctrl+p |
说明 | 快捷键 |
---|---|
批量修改指定的变量名、方法名、类名等-rename | shift+f6 |
抽取代码重构方法-extract method … | ctrl+alt+m |
重写父类的方法-override methods … | ctrl+o |
实现接口的方法-implements methods … | ctrl+i |
选中的结构的大小写的切换-toggle case | ctrl+shift+u |
批量导包-optimize imports | ctrl+alt+o |
说明 | 快捷键 |
---|---|
如何查看源码-go to class… | ctrl + 选中指定的结构 或 ctrl+n |
显示当前类结构,支持搜索指定的方法、属性等-file structure | ctrl+f12 |
退回到前一个编辑的页面-back | ctrl+alt+← |
进入到下一个编辑的页面-forward | ctrl+alt+→ |
打开的类文件之间切换-select previous/next tab | alt+←/→ |
光标选中指定的类,查看继承树结构-Type Hierarchy | ctrl+h |
查看方法文档-quick documentation | ctrl+q |
类的UML关系图-show uml popup | ctrl+alt+u |
定位某行-go to line/column | ctrl+g |
回溯变量或方法的来源-go to implementation(s) | ctrl+alt+b |
折叠方法实现-collapse all | ctrl+shift+ - |
展开方法实现-expand all | ctrl+shift+ + |
说明 | 快捷键 |
---|---|
查找指定的结构 | ctlr+f |
快速查找:选中的Word快速定位到下一个-find next | ctrl+l |
查找与替换-replace | ctrl+r |
直接定位到当前行的首位-move caret to line start | home |
直接定位到当前行的末位 -move caret to line end | end |
查询当前元素在当前文件中的引用,然后按 F3 可以选择 | ctrl+f7 |
全项目搜索文本-find in path … | ctrl+shift+f |
关闭当前窗口-close | ctrl+f4 |
说明 | 快捷键 |
---|---|
格式化代码-reformat code | ctrl+alt+l |
使用单行注释-comment with line comment | ctrl + / |
使用/取消多行注释-comment with block comment | ctrl + shift + / |
选中数行,整体往后移动-tab | tab |
选中数行,整体往前移动-prev tab | shift + tab |
说明 | 快捷键 |
---|---|
单步调试(不进入函数内部)- step over | F8 |
单步调试(进入函数内部)- step into | F7 |
强制单步调试(进入函数内部) - force step into | alt+shift+f7 |
选择要进入的函数 - smart step into | shift + F7 |
跳出函数 - step out | shift + F8 |
运行到断点 - run to cursor | alt + F9 |
继续执行,进入下一个断点或执行完程序 - resume program | F9 |
停止 - stop | Ctrl+F2 |
查看断点 - view breakpoints | Ctrl+Shift+F8 |
关闭 - close | Ctrl+F4 |
苹果电脑或者是用惯Eclipse快捷的,可以选择其他快捷键插件。
编好的程序在执行过程中如果出现错误,该如何查找或定位错误呢?简单的代码直接就可以看出来,但如果代码比较复杂,就需要借助程序调试工具(Debug)来查找错误了。
运行编写好的程序时,可能出现的几种情况:
> 情况1:没有任何bug,程序执行正确!
====================如果出现如下的三种情况,都又必要使用debug=============================
> 情况2:运行以后,出现了错误或异常信息。但是通过日志文件或控制台,显示了异常信息的位置。
> 情况3:运行以后,得到了结果,但是结果不是我们想要的。
> 情况4:运行以后,得到了结果,结果大概率是我们想要的。但是多次运行的话,可能会出现不是我们想要的情况。
比如:多线程情况下,处理线程安全问题。
Debug(调试)程序步骤如下:
1、添加断点
2、启动调试
3、单步执行
4、观察变量和执行流程,找到并解决问题
在源代码文件中,在想要设置断点的代码行的前面的标记行处,单击鼠标左键就可以设置断点,在相同位置再次单击即可取消断点。
IDEA提供多种方式来启动程序(Launch)的调试,分别是通过菜单(Run –> Debug)、图标(“绿色臭虫”)等等。
或
【解释】
:Step Over(F8):进入下一步,如果当前行断点是调用一个方法,则不进入当前方法体内。
:Step Into(F7):进入下一步,如果当前行断点是调用一个自定义方法,则进入该方法体内。
:Force Step Into(Alt +Shift ?+ F7):进入下一步,如果当前行断点是调用一个核心类库方法,则进入该方法体内。(强制进入)
:Step Out(Shift ?+ F8):跳出当前方法体。
:Run to Cursor(Alt + F9):直接跳到光标处继续调试。
:Resume Program(F9):恢复程序运行,但如果该断点下面代码还有断点则停在下一个断点上。(跳到下一个断点)
:Stop(Ctrl + F2):结束调试。
:View Breakpoints(Ctrl + Shift ?+ F8):查看所有断点。
:Mute Breakpoints:使得当前代码后面所有的断点失效, 一下执行到底。
:重新运行。
:显示执行点,若在此行代码中,进入了其中一个函数查看,想要再返回刚才调试的这一行代码,可以点这个按钮。
说明:在Debug过程中,可以动态的下断点。
【案例1】
package com.atguigu.debug;
/**
* ClassName: Debug01
* Package: com.atguigu.debug
* Description: 演示1:行断点 & 测试debug各个常见操作按钮
*/
public class Debug01 {
public static void main(String[] args) {
//1.
int m = 10;
int n = 20;
System.out.println("m = " + m + ",n = " + n);
swap(m, n);
System.out.println("m = " + m + ",n = " + n);
//2.
// int[] arr = new int[] {1,2,3,4,5};
// System.out.println(arr);//地址值
// char[] arr1 = new char[] {'a','b','c'};
// System.out.println(arr1);//abc
}
public static void swap(int m,int n){
int temp = m;
m = n;
n = temp;
}
}
此时得到的不是想要的结果:
此时就可以通过调试来发现问题。
打断点在哪里打呢?一般在你怀疑出错的代码的前面一行打上断点。
比如现在怀疑swap()
方法有问题,就可以将断点打到上面一行,如下:
断点是红色的,用鼠标左键在左边点一下即可。
接下来调试一下,点击“Debug”:
然后代码就会执行到首次添加断点的位置,此时这一行代码还没有执行。如下:
然后执行下一步:
此时想进入swap()方法内部,点击第二个按钮(因为这里的swap方法是自己写的,若是系统函数比如print函数,就需要第三个按钮强制进入):
然后一步一步执行:
此时swap()执行完毕,可以跳出来,不用继续执行后续代码:
【案例2】
package com.atguigu.debug;
/**
* ClassName: Debug01
* Package: com.atguigu.debug
* Description: 演示1:行断点 & 测试debug各个常见操作按钮
*/
public class Debug01 {
public static void main(String[] args) {
//1.
// int m = 10;
// int n = 20;
// System.out.println("m = " + m + ",n = " + n);
// swap(m, n);
// System.out.println("m = " + m + ",n = " + n);
//2.
int[] arr = new int[] {1,2,3,4,5};
System.out.println(arr);//地址值
char[] arr1 = new char[] {'a','b','c'};
System.out.println(arr1);//abc
}
public static void swap(int m,int n){
int temp = m;
m = n;
n = temp;
}
}
打断点进行调试:
强制进入print函数:
再次强制进入valueOf:
可以看到,直接调用toString:
这里可以跳出方法:
对于第二个也可以使用同样的方法进入调试:
【案例1】
package yuyi03.Debug;
/**
* ClassName: Debug02
* Package: com.atguigu.debug
* Description: 演示2: 方法断点
* @Version 1.0
*/
public class Debug02 {
public static void main(String[] args) {
//1.
Son instance = new Son();
instance.test();
// //2.类的多态性
// Father instance1 = new Son();
// instance1.test();
//
// //3.接口的多态性
// Consumer con = new ConsumerImpl();
// con.accept("atguigu");
//4.
// HashMap map = new HashMap();
// map.put("Tom",12);
// map.put("Jerry",11);
// map.put("Tony",20);
}
}
class Father{
public void test(){
System.out.println("Father : test1");
System.out.println("Father : test2");
}
}
class Son extends Father{
@Override
public void test(){
System.out.println("Son : test1");
System.out.println("Son : test2");
}
}
interface Consumer{
void accept(String str);
}
class ConsumerImpl implements Consumer{
@Override
public void accept(String str) {
System.out.println("ConsumerImple:" + str);
}
}
方法断点,比如在这个方法左边打上断点,可以看到是一个菱形:
右键点击菱形,可以看到它指明了在进入方法的时候,会停留一下。
然后开始调试:
可以看到它直接停留在方法这里了:
这是因为上面调用这个方法了:
一调用这个方法,它就停留在这里了。
给方法声明这里加断点,就是看这个方法什么时候调用,调用的时候就重点看方法的执行。
【案例2】
package yuyi03.Debug;
/**
* ClassName: Debug02
* Package: com.atguigu.debug
* Description: 演示2: 方法断点
* @Version 1.0
*/
public class Debug02 {
public static void main(String[] args) {
//1.
// Son instance = new Son();
// instance.test();
//2.类的多态性
Father instance1 = new Son();
instance1.test();
//3.接口的多态性
Consumer con = new ConsumerImpl();
con.accept("atguigu");
//4.
// HashMap map = new HashMap();
// map.put("Tom",12);
// map.put("Jerry",11);
// map.put("Tony",20);
}
}
class Father{
public void test(){
System.out.println("Father : test1");
System.out.println("Father : test2");
}
}
class Son extends Father{
@Override
public void test(){
System.out.println("Son : test1");
System.out.println("Son : test2");
}
}
interface Consumer{
void accept(String str);
}
class ConsumerImpl implements Consumer{
@Override
public void accept(String str) {
System.out.println("ConsumerImple:" + str);
}
}
在方法声明处打上断点:
编写的时候,会认为调用的是父类/接口中的方法,实际执行的时候是子类/实现类中的方法:
那么此时调试会做停留吗?
可以发现其实停留了,而且停留在了子类Son这里,如下:
刚才说了,实际运行的时候,执行的是子类重写父类的方法。
所以这里是真正运行了。
为什么在父类那里打的断点,跳到了子类这里?这是因为子类将父类的方法给覆盖了。
接下来看一下“下一个可能有断点的位置”:
可以看到跳到了Consumer实现类的地方:
通过Debug可以看到真正执行的是哪一个类的方法
现在可以查看一下当前代码中都有哪些位置有断点:
【案例1】
package com.atguigu.debug;
/**
* ClassName: Debug03
* Package: com.atguigu.debug
* Description: 演示3:字段断点
* @Version 1.0
*/
public class Debug03 {
public static void main(String[] args) {
Person p1 = new Person(3);
System.out.println(p1.toString());
}
}
class Person{
private int id = 1; //显示赋值
private String name;
private int age;
public Person() {
}
{
id = 2; //代码块赋值
}
public Person(int id) {
this.id = id; //构造器赋值
}
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
在属性前面加断点是一个小眼睛,比如:
右键可以看到,在修改当前属性的时候,会停留一下(相当于就是看一下哪些位置修改了):
现在我们调试一下,凡是修改了属性的位置都会停下来。
可以看到这里显式赋值算修改了,因为默认值是0。
此时p1对象还没有创建,调用构造器之前先是显示赋值了,所以this里面的id是0,如下:
点击这里,找到下一个断点位置代码块:
此时this里面的id变为了1,说明显示赋值已经执行了。
再下一个位置就是构造器了,如下:
一共就这三个位置修改了id,再次寻找断点位置就会结束。
🎲拓展
若此时让它在访问的时候也停留一下。
右键点击小眼睛,将“字段访问”勾上:
那么在toString的时候也会停留一下:
有的时候会想,在条件满足的情况下停留一下。
package com.atguigu.debug;
/**
* ClassName: Debug04
* Package: com.atguigu.debug
* Description: 演示4:条件断点
* @Version 1.0
*/
public class Debug04 {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10,11,12};
for (int i = 0; i < arr.length; i++) {
int target = arr[i];
System.out.println(target);
}
}
}
针对上述代码,比如现在想在满足arr[i] % 3 == 0
的条件下,执行断点。(若被3除不尽,就直接往后执行即可)
可以在这里加一个断点,然后右键:(在Condition里面添加条件)
若arr[i]除3可以除尽就停留一下。
现在做一个调试:
可以看见控制台已经输出了1和2,在3的位置停留了:
接下来看一下下一个断点的位置,可以发现在6的时候停留了:
以后需要在某个条件的情况下分析就可以使用条件断点,不需要让程序一步一步走
package com.atguigu.debug;
import java.util.Date;
/**
* ClassName: Debug05
* Package: com.atguigu.debug
* Description: 演示5:异常断点
* @Version 1.0
*/
public class Debug05 {
public static void main(String[] args) {
int m = 10;
int n = 0;
int result = m / n;
System.out.println(result);
// Person p1 = new Person(1001);
// System.out.println(p1.getName().toUpperCase());
}
}
通过下图的方式,对指定的异常进行监控:
package com.atguigu.debug;
/**
* ClassName: Debug06
* Package: com.atguigu.debug
* Description: 演示6:线程调试
* @Version 1.0
*/
public class Debug06 {
public static void main(String[] args) {
test("Thread1");
test("Thread2");
}
public static void test(String threadName) {
new Thread(
() -> System.out.println(Thread.currentThread().getName()),
threadName
).start();
}
}
package com.atguigu.debug;
/**
* ClassName: Debug07
* Package: com.atguigu.debug
* Description: 演示7:强制结束
* @Version 1.0
*/
public class Debug07 {
public static void main(String[] args) {
System.out.println("获取请求的数据");
System.out.println("调用写入数据库的方法");
insert();
System.out.println("程序结束");
}
private static void insert() {
System.out.println("进入insert()方法");
System.out.println("获取数据库连接");
System.out.println("将数据写入数据表中");
System.out.println("写出操作完成");
System.out.println("断开连接");
}
}
比如在insert()
的位置加了一个断点,然后调试:
然后进入insert()方法:
假设走到第二行已经知道是什么问题了,不想再往后执行了。
若此时强制停止,可以发现后面的代码也执行了:
那怎么办呢?
选中当前方法,右键“Force Return”:
然后可以看到,中间很多就没有做了:
package com.atguigu.debug;
import java.util.HashMap;
/**
* ClassName: Debug08
* Package: com.atguigu.debug
* Description: 演示8:用户自定义数据视图
* @Version 1.0
*/
public class Debug08 {
public static void main(String[] args) {
HashMap<Integer,String> map = new HashMap<>();
map.put(1,"高铁");
map.put(2,"网购");
map.put(3,"支付宝");
map.put(4,"共享单车");
System.out.println(map);
}
}
设置如下:
问题:使用Step Into时,会出现无法进入源码的情况。如何解决?
方案1:使用 force step into 即可
方案2:点击Setting -> Build,Execution,Deployment -> Debugger -> Stepping
把Do not step into the classess中的java.*
、javax.*
取消勾选即可。
小结:
经验:初学者对于在哪里加断点,缺乏经验,这也是调试程序最麻烦的地方,需要一定的经验。
简单来说,在可能发生错误的代码的前面加断点。如果不会判断,就在程序执行的起点处加断点。
阿里巴巴Java编码规范检查插件,检测代码是否存在问题,以及是否符合规范。
使用:在类中,右键,选择编码规约扫描,在下方显示扫描规约和提示。根据提示规范代码,提高代码质量。
可视化的字节码查看器。
使用:
英文设置:
在 Help -> Edit Custom VM Options …,加上
-Duser.language=en
注册翻译服务(有道智云、百度翻译开放平台、阿里云机器翻译)帐号,开通翻译服务并获取其应用ID和密钥
绑定应用ID和密钥:偏好设置(设置) > 工具 > 翻译 > 常规 > 翻译引擎 > 配置…
使用:鼠标选中文本,点击右键即可自动翻译成多国语言。
注:请注意保管好你的应用密钥,防止其泄露。
实际开发中还有一个非常常见的场景: 我们创建一个对象后,想依次调用 Setter 函数对属性赋值,如果属性较多很容易遗漏或者重复。
可以使用这 GenerateAllSetter 提供的功能,快速生成对象的所有 Setter 函数(可填充默认值),然后自己再跟进实际需求设置属性值。
给括号添加彩虹色,使开发者通过颜色区分括号嵌套层级,便于阅读。
在编辑器右侧生成代码小地图,可以拖拽小地图光标快速定位代码,阅读行数很多的代码文件时非常实用。
代码统计工具。
显示快捷键操作的按键。
快捷键提示插件。当你执行鼠标操作时,如果该操作可被快捷键代替,会给出提示,帮助你自然形成使用快捷键的习惯,告别死记硬背。
按alt+insert
,执行操作:
在 IDEA 里刷力扣算法题
根据 json 生成对象。
使用:使用alt + s 或 alt + insert调取。
举例:
{
"name": "tom",
"age": "18",
"gender": "man",
"hometown": {
"province": "河北省",
"city": "石家庄市",
"county": "正定县"
}
}
对于很多人而言,写代码时略显枯燥的,如果能够安装自己喜欢的主题将为开发工作带来些许乐趣。
IDEA 支持各种主题插件,其中最出名的当属 Material Theme UI。
安装后,可以从该插件内置的各种风格个选择自己最喜欢的一种。