断点处可以打印一些变量日志,方便后面查看当时断点处的变量值,以免debug到后面去了忘了前面的值。另外,不用写在代码中,省去了万一忘记删除日志的麻烦。
代码:
public static void main(String[] args) { ThreadLocalRandom localRandom = ThreadLocalRandom.current(); int count = 0; for (int i = 0; i < 5; i++) { if(isInterested(localRandom.nextInt(100))){ count++; } } } private static boolean isInterested(int i){ return i % 2 == 0; }
打个断点,鼠标右键这个断点,点击More(Ctrl+Shift+F8),
打印日志效果
isInterested:57 isInterested:12 isInterested:16 isInterested:50 isInterested:93
显示具体哪一行
Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) isInterested:49 Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) isInterested:25 Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) isInterested:8 Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) isInterested:66 Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) isInterested:9
完整堆栈
Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) at com.fangqiang.anothertest.testttt.test.Test04.main(Test04.java:19) isInterested:84 Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) Breakpoint reached at com.fangqiang.anothertest.testttt.test.Test04.isInterested(Test04.java:26) at com.fangqiang.anothertest.testttt.test.Test04.main(Test04.java:19) isInterested:89
可用于定位某个字段在何时被赋值,何时被赋成这个值,在源码阅读时,经常搞不懂这个变量的值从哪里来的,这个断点可以很好解决这个问题
给测试类加上name,age属性
private String name; private Integer age; //测试代码 Test04 test04 = new Test04(); test04.setName("888"); test04.setName("444"); test04.setName("555"); test04.setName("哈哈哈"); test04.setName("999"); test04.getName();
还是一样的操作,此时断点变成了红色眼睛。
看看勾选Field access效果。跳到getName方法处
勾选Field modification效果。跳到第一个调用setName处,后面每次setName都会经过这个断点
也可以加上条件判断,这个变量啥时候被赋成这个值的,勾选Condition,填写表达式
代码报错抛出异常了,知道是啥类型异常,希望在抛异常之前,看看数据是什么样的,为啥异常了,就可以使用这种方法,比如最常见的空指针异常
我们打个断点,点击左下角两个叠加的红色圆圈,可以查看所有断点,然后点击加号,出现5中类型断点,选择第三个Java Exception Breakpoints,选择空指针异常
打好断点后,再次debug,再发生异常前,会停留在即将发生异常的那行代码上
当一个接口的实现类特别多,比如spring里面比比皆是,变量类型为接口,实际调用时,可以通过强制进入方法内可以看进入哪个子类,也可采用接口方法打断点方式来选择走到哪个子类
上代码,一个接口,两个子类。测试方法中使用接口类型的变量调用print方法。
在接口的print()方法打断点,是红色方块形的断点,然后运行
public interface TestInterface { public void print(); static class A implements TestInterface{ @Override public void print() { System.out.println("I'm A!"); } } static class B implements TestInterface{ @Override public void print() { System.out.println("I'm B!"); } } public static void main(String[] args) { TestInterface testInterface = new A(); testInterface.print(); } }
Java8加入了Stream流特性,把集合的操作变简单了,同时可读性也降低了。一阵链式操作,行云流水,却把人搞得丈二和尚摸不着头脑,啥玩意
idea也提供了一个很方便的功能,那就是Trace Current Stream Chain
上代码
public class Test03 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(6); list.stream().filter(i -> i % 2 == 0).count(); List<Optional<Person>> persons = Arrays.asList( Optional.of(new Person("方大大", 18)), Optional.of(new Person("六打打", 17)), Optional.of(new Person("李大大", 16)), Optional.empty(), Optional.of(new Person("喜大大", 15)), Optional.of(new Person("乐大大", 14)), Optional.of(new Person("克大大", 13)) ); long num = persons.stream().flatMap(c -> c.map(Stream::of).orElse(Stream.empty())) .filter(c -> c.getAge() > 15).count(); } public static class Person { private String name; private Integer age; public Person(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } }
打个断点,运行,点击红框中的按钮
点击后效果如下
两种模式,点击Mode按钮就可以切换。很清晰展现出stream每一步操作后数据是怎么变化的。先开始数据6个,过滤偶数还剩3个,最后count就是3。上面代码后面还有个例子,也可以试试。