Подтвердить что ты не робот

Динамически получить текущий номер строки

Есть ли способ в Java динамически получить текущий номер строки через отражение или какой-нибудь удивительный API? Так же, как и при исключениях, номер строки печатается в трассировке стека следующим образом:

at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)

Теперь есть способ печатать или записывать, как в приведенном ниже коде?

log.error("Error in: " + this.getClass.getName() + "at line #"+ this.getClass.getActualLine());

Вы можете спросить, почему бы мне просто не напечатать номер строки? Хорошо, потому что код может быть удален или добавлен до вызова метода log.error().

4b9b3361

Ответ 1

Вы можете создать Throwable и использовать StackTraceElements:

  System.err.println(new Throwable().getStackTrace()[0].getLineNumber());

Как сказал @Joachim, вы также можете использовать Thread.getStackTrace(), например. как

  System.err.println(Thread.currentThread().getStackTrace()[1].getLineNumber());

Помните, что второй подход возвращает несколько другой массив - вам нужно использовать элемент массива с индексом 1, чтобы получить номер строки current, поскольку он включает вызов getStackTrace() сам по себе как первый элемент.

Также обратите внимание на комментарии к журналу и производительности из ответа @Joachim.

Ответ 2

Прежде всего: если что-либо, тогда это должен сделать шаблон регистрации (или планировщик или что-то другое, что ваша система ведения журнала вызывает эту часть). Вызов регистратора в вашем коде должен содержать только фактическую деловую информацию. Информация о том, где должен быть добавлен регистратор.

Далее: получение такой операции дорого (с точки зрения времени), потому что Java не оптимизирован для этого. Во время выполнения JVM необходимо проверить свое состояние, загрузить/разбить информацию об отладке и найти номер строки, соответствующий данной инструкции. Вот почему такая информация обычно предоставляется только при возникновении исключения (в этом случае у нас уже есть проблема и знаем, что затраченное время обычно будет стоить того).

И последнее, но не менее важное: , если по какой-то причине вам нужна эта информация сама по себе, вы можете использовать Thread.getStackTrace() и проверите второй StackTraceElement на нем.

Ответ 3

Мне удалось использовать метод Thread.currentThread(). getStackTrace() для создания набора функций, которые работают вместе, чтобы создать номер строки кода, который вызвал первый метод, например:

/** @return The line number of the code that ran this method
 * @author Brian_Entei */
public static int getLineNumber() {
    return ___8drrd3148796d_Xaf();
}

/** This methods name is ridiculous on purpose to prevent any other method
 * names in the stack trace from potentially matching this one.
 * 
 * @return The line number of the code that called the method that called
 *         this method(Should only be called by getLineNumber()).
 * @author Brian_Entei */
private static int ___8drrd3148796d_Xaf() {
    boolean thisOne = false;
    int thisOneCountDown = 1;
    StackTraceElement[] elements = Thread.currentThread().getStackTrace();
    for(StackTraceElement element : elements) {
        String methodName = element.getMethodName();
        int lineNum = element.getLineNumber();
        if(thisOne && (thisOneCountDown == 0)) {
            return lineNum;
        } else if(thisOne) {
            thisOneCountDown--;
        }
        if(methodName.equals("___8drrd3148796d_Xaf")) {
            thisOne = true;
        }
    }
    return -1;
}

Надеюсь, это поможет! Я помещаю их в класс утилиты, чтобы они были в стороне, но все еще легко доступны. Второй метод является приватным, чтобы предотвратить любой другой метод, отличный от первого метода, от его вызова, чтобы он всегда работал правильно.