Как получить номера столбцов строк в Java stacktraces

в некоторых языках можно получить номер столбца строки в stacktrace, однако в Java у нас есть только номера строк.

чтобы дать вам пример, на другом языке мы можем иметь:

Error
    at <anonymous>:2:2
    at Object.InjectedScript._evaluateOn (<anonymous>:641:39)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:580:52)
    at Object.InjectedScript.evaluate (<anonymous>:495:21)"

хотя это может быть плохой пример, поскольку я вызываю ошибку из консоли браузера, вы можете увидеть номера столбцов, которые действительно полезны при решении ошибок.

чтобы дать вам пример в Java ( да, имена были изменены ) :

Caused by: java.lang.IllegalArgumentException: path was null
    at org.jboss.resteasy.specimpl.ResteasyUriBuilder.path(ResteasyUriBuilder.java:362)
    at enterprise.money.service(AbstractSomething.java:88)

это приводит к строке 88, которая содержит

URI uri = uriInfo.getBaseUriBuilder().path(objectA).path(objectB).build();

С stacktrace у меня есть, я не могу проверить, какой .path звонок вызвал исключение. Поэтому мой вопрос в том, есть ли какие-либо решения, которые позволяют мне получить ссылку на столбец?

(чтобы защитить от некоторых возможных альтернативных ответов, нам нужно решение, чтобы получить номера столбцов, другие ответы, такие как как шаг через отладчик или рефакторинг каждого строителя картина, etc., не ответит на вопрос)

3 ответов


Это невозможно.

вы можете обойти его, форматируя свой код таким образом:

URI uri = uriInfo
           .getBaseUriBuilder()
           .path(objectA)
           .path(objectB)
           .build();

В Oracle Java 8 можно писать

public static void main(String... ignored) {
    List<String> s = new ArrayList<>();
    s.add("hello");

    Predicate<? super String> predicate1 = (t) -> t.length() > 0;
    Predicate<? super String> predicate2 = (t) -> t.length() < 8;
    Predicate<? super String> predicate3 = null;

    List<String> collect = s.stream()
            .filter(predicate1) // 16
            .filter(predicate2) // 17
            .filter(predicate3) // 18
            .collect(Collectors.toList());
}

и вы

Exception in thread "main" java.lang.NullPointerException
    at java.util.Objects.requireNonNull(Objects.java:203)
    at java.util.stream.ReferencePipeline.filter(ReferencePipeline.java:161)
    at Example.main(Example.java:18)

для Oracle JDK это, по-видимому, только в Java 8, а не Java 7.


обратное проектирование для Java было бы довольно болезненным. Теоретически вы можете проанализировать исходный источник и выяснить, какое выражение(ы) может вызвать такое исключение.

если у вас есть это как проблема, весьма вероятно, что ваши линии слишком сложны/плотны. Большинство IDE упрощает рефакторинг выражений для извлечения частей кода. Это даст вам больше разрешения того, где было создано исключение.


другое решение этого конкретная проблема заключается в том, чтобы иметь методы с @NotNull, и IDE может определить, какие аргументы могут быть null, но никогда не должны быть.

URI uri = uriInfo.getBaseUriBuilder().path(objectA)
                                     .path(/*highlighted*/objectB).build();

IDE может предупредить вас, что вы передаете переменную методу, который не может принять null Если вы сделаете это, вы подберете эти ошибки намного раньше, и это сделает его легче исправить. (IDE поставляется с некоторыми быстрыми исправлениями)

Примечание: вообще говоря, неправильно передал null аргумент API должен вызывать исключение NullPointerException ИМХО, однако часто IllegalArgumentException бросается несколько непоследовательно.

как я вижу, аргументом для IllegalArgumentException является то, что;

  • IllegalArgumentException-это то, что вы можете ожидать от приложения. Ловить NullPointerException действительно пахнет.
  • обработка недействительным будет таким же, как и другие неправильные аргументы, такие как длина -1

ИМХО передает null к методу, который не принимает null это ошибка программирования, а не вопрос о том, чтобы обеспечить неправильный ввод.


вы не можете получить столбцы из трассировки стека.

что вы можете сделать, это использовать промежуточные переменные, так что у вас есть каждый вызов метода в другой строке:

UriBuilder builder = uriInfo.getBaseUriBuilder();
builder = builder.path(objectA);
builder = builder.path(objectB);
URI uri = builder.build();

это болезненно, но это может временно помочь найти проблему, тогда вы можете вернуть ее, как она была.