Динамически получить текущий номер строки
Есть ли способ в 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().
Ответы
Ответ 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;
}
Надеюсь, это поможет! Я помещаю их в класс утилиты, чтобы они были в стороне, но все еще легко доступны. Второй метод является приватным, чтобы предотвратить любой другой метод, отличный от первого метода, от его вызова, чтобы он всегда работал правильно.