idea比较好用的断点调试方法

断点处打印日志

断点处可以打印一些变量日志,方便后面查看当时断点处的变量值,以免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();
    }
}

Stream流的debug

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。上面代码后面还有个例子,也可以试试。

posted @ 2022-07-02 22:47  方大大大  阅读(1354)  评论(0编辑  收藏  举报