Когда-то приятными маленькими особенностями большинства отладчиков, которыми я занимался в последнее время, является возможность записывать информацию в точку останова. Это может быть действительно полезным, чтобы понять код без необходимости его изменения, это связано с модификацией байтового кода.
Давайте рассмотрим эту очень тривиальную и неэффективную реализацию функции для возврата n-го числа в последовательности Фибоначчи.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public class Fib { public long fib(long number) { return number < 1 ? 0 : // Breakpoint here number < 2 ? 1 : fib(number - 2) + fib(number - 1); } public static void main(String[] args) { Fib fib = new Fib(); System.out.println(fib.fib(10L)); }} |
Теперь мы добавляем простую точку останова, я собираюсь немного ее изменить, чтобы она не остановилась; но он будет записывать простое выражение, которое дает нам текущее значение number
Это дает следующий вывод для нашего довольно неэффективного кода:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
ebugger connected to local process.Source breakpoint: Fib.java:11, evaluate(number)=10 (long)Source breakpoint: Fib.java:11, evaluate(number)=8 (long)Source breakpoint: Fib.java:11, evaluate(number)=6 (long)Source breakpoint: Fib.java:11, evaluate(number)=4 (long)Source breakpoint: Fib.java:11, evaluate(number)=2 (long)Source breakpoint: Fib.java:11, evaluate(number)=0 (long)Source breakpoint: Fib.java:11, evaluate(number)=1 (long)Source breakpoint: Fib.java:11, evaluate(number)=3 (long)Source breakpoint: Fib.java:11, evaluate(number)=1 (long)Source breakpoint: Fib.java:11, evaluate(number)=2 (long)... sometime laterSource breakpoint: Fib.java:11, evaluate(number)=1 (long)Source breakpoint: Fib.java:11, evaluate(number)=2 (long)Source breakpoint: Fib.java:11, evaluate(number)=0 (long)Source breakpoint: Fib.java:11, evaluate(number)=1 (long)55 |
Итак, что мы сделали здесь, так это добавили трассировку post-hoc, вы можете даже не иметь доступа к источнику и все же иметь возможность получить полезную информацию о том, что делает код.
Теперь очевидный вывод из приведенного выше примера состоит в том, что мы вычисляем одно и то же значение снова и снова. Итак, вот еще одна версия кода, которая вместо этого использует карту для хранения ранее вычисленных значений в последовательности. Заметьте также, что добавление трассировки в этот код труднее, чем в предыдущем случае, не делая Lambda менее привлекательной.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import java.util.HashMap;import java.util.Map;public class Fib { Map<Long, Long> data = new HashMap<>(); { data.put(1L, 1L); } public long fib(long number) { return data.computeIfAbsent(number, n -> n < 1 ? 0 : fib(n - 2) + fib(n - 1)); // Breakpoint here } public static void main(String[] args) { Fib fib = new Fib(); System.out.println(fib.fib(10L)); }} |
Здесь стоит отметить две вещи: во-первых, ваше выражение журнала точек останова должно оценивать значение лямбда-параметра n а во-вторых, вы всегда должны помещать свое выражение в новую строку, чтобы будущий разработчик мог легко его установить. (Неважно, теперь намного меньше / красивее / умнее, это выглядело бы, если бы вы поместили код в один).
Таким образом, вывод трассировки теперь выглядит намного лучше, поскольку каждое значение вычисляется только один раз.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
Debugger connected to local process.Source breakpoint: Fib.java:17, evaluate(n)=10Source breakpoint: Fib.java:17, evaluate(n)=8Source breakpoint: Fib.java:17, evaluate(n)=6Source breakpoint: Fib.java:17, evaluate(n)=4Source breakpoint: Fib.java:17, evaluate(n)=2Source breakpoint: Fib.java:17, evaluate(n)=0Source breakpoint: Fib.java:17, evaluate(n)=3Source breakpoint: Fib.java:17, evaluate(n)=5Source breakpoint: Fib.java:17, evaluate(n)=7Source breakpoint: Fib.java:17, evaluate(n)=955 |
Снимки экрана в этом блоге от Jdeveloper; но аналогичные функции доступны в Intelij , Netbeans, и если вы немного хитры , вы можете получить нечто подобное в Eclipse .
