Gibt es eine Möglichkeit, den Namen der aktuell ausgeführten Methode in Java abzurufen?
Gibt es eine Möglichkeit, den Namen der aktuell ausgeführten Methode in Java abzurufen?
Antworten:
Thread.currentThread().getStackTrace()
enthält normalerweise die Methode, von der Sie es aufrufen, aber es gibt Fallstricke (siehe Javadoc ):
Einige virtuelle Maschinen können unter bestimmten Umständen einen oder mehrere Stapelrahmen aus der Stapelverfolgung weglassen. Im Extremfall darf eine virtuelle Maschine, die keine Stapelverfolgungsinformationen zu diesem Thread enthält, ein Array mit der Länge Null von dieser Methode zurückgeben.
Technisch wird das funktionieren ...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
Während der Kompilierungszeit wird jedoch eine neue anonyme innere Klasse erstellt (z YourClass$1.class
. B. ). Das schafft also eine.class
für jede Methode, die diesen Trick ausführt Datei erstellt. Zusätzlich wird bei jedem Aufruf zur Laufzeit eine ansonsten nicht verwendete Objektinstanz erstellt. Dies mag also ein akzeptabler Debug-Trick sein, bringt jedoch einen erheblichen Overhead mit sich.
Ein Vorteil dieses Tricks ist die getEncosingMethod()
Rückgabe, mit java.lang.reflect.Method
der alle anderen Informationen der Methode einschließlich Anmerkungen und Parameternamen abgerufen werden können. Dies ermöglicht die Unterscheidung zwischen gleichnamigen Methoden (Methodenüberladung).
Beachten Sie, dass laut JavaDoc getEnclosingMethod()
dieser Trick kein a werfen sollteSecurityException
da innere Klassen mit demselben Klassenlader geladen werden sollten. Daher müssen die Zugriffsbedingungen auch dann nicht überprüft werden, wenn ein Sicherheitsmanager vorhanden ist.
Es ist getEnclosingConstructor()
für Konstruktoren erforderlich . Gibt bei Blöcken außerhalb von (benannten) Methoden getEnclosingMethod()
zurück null
.
getEnclosingMethod
Ruft den Namen der Methode ab, in der die Klasse definiert ist. this.getClass()
wird dir überhaupt nicht helfen. @wutzebaer warum brauchst du das überhaupt? Sie haben bereits Zugriff darauf.
Januar 2009:
Ein vollständiger Code wäre (unter Berücksichtigung der Einschränkung von @ Bombe ):
/**
* Get the method name for a depth in call stack. <br />
* Utility function
* @param depth depth in the call stack (0 means current method, 1 means call method, ...)
* @return method name
*/
public static String getMethodName(final int depth)
{
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
//System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
// return ste[ste.length - depth].getMethodName(); //Wrong, fails for depth = 0
return ste[ste.length - 1 - depth].getMethodName(); //Thank you Tom Tresansky
}
Mehr in dieser Frage .
Update Dezember 2011:
bläuliche Kommentare:
Ich verwende JRE 6 und gebe mir einen falschen Methodennamen.
Es funktioniert, wenn ich schreibeste[2 + depth].getMethodName().
0
istgetStackTrace()
,1
istgetMethodName(int depth)
und2
ruft die Methode auf.
virgo47 ‚s Antwort (upvoted) berechnet tatsächlich den richtigen Index anzuwenden , um den Namen der Methode zurück zu bekommen.
StackTraceElement
Array zum Debuggen zu drucken und festzustellen , ob 'main' tatsächlich die richtige Methode ist?
ste[2 + depth].getMethodName()
. 0 ist getStackTrace()
, 1 ist getMethodName(int depth)
und 2 ruft die Methode auf. Siehe auch die Antwort von @ virgo47 .
Wir haben diesen Code verwendet, um die potenzielle Variabilität des Stack-Trace-Index zu verringern. Rufen Sie jetzt einfach methodName util auf:
public class MethodNameTest {
private static final int CLIENT_CODE_STACK_INDEX;
static {
// Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6
int i = 0;
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
i++;
if (ste.getClassName().equals(MethodNameTest.class.getName())) {
break;
}
}
CLIENT_CODE_STACK_INDEX = i;
}
public static void main(String[] args) {
System.out.println("methodName() = " + methodName());
System.out.println("CLIENT_CODE_STACK_INDEX = " + CLIENT_CODE_STACK_INDEX);
}
public static String methodName() {
return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX].getMethodName();
}
}
Scheint überentwickelt, aber wir hatten eine feste Nummer für JDK 1.5 und waren etwas überrascht, dass sie sich geändert hat, als wir zu JDK 1.6 gewechselt sind. Jetzt ist es in Java 6/7 dasselbe, aber man weiß es einfach nie. Es ist kein Beweis für Änderungen in diesem Index zur Laufzeit - aber hoffentlich macht HotSpot das nicht schlecht. :-)
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
Name hat den Wert foo.
null
Beide Optionen funktionieren für mich mit Java:
new Object(){}.getClass().getEnclosingMethod().getName()
Oder:
Thread.currentThread().getStackTrace()[1].getMethodName()
Der schnellste Weg, den ich gefunden habe, ist folgender:
import java.lang.reflect.Method;
public class TraceHelper {
// save it static to have it available on every call
private static Method m;
static {
try {
m = Throwable.class.getDeclaredMethod("getStackTraceElement",
int.class);
m.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getMethodName(final int depth) {
try {
StackTraceElement element = (StackTraceElement) m.invoke(
new Throwable(), depth + 1);
return element.getMethodName();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Es greift direkt auf die native Methode getStackTraceElement (int depth) zu. Und speichert die zugängliche Methode in einer statischen Variablen.
new Throwable().getStackTrace()
5614 ms dauerte.
Verwenden Sie den folgenden Code:
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
String methodName = e.getMethodName();
System.out.println(methodName);
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
}
Dies ist eine Erweiterung der Antwort von virgo47 (oben).
Es bietet einige statische Methoden, um die aktuellen und aufrufenden Klassen- / Methodennamen abzurufen.
/* Utility class: Getting the name of the current executing method
* /programming/442747/getting-the-name-of-the-current-executing-method
*
* Provides:
*
* getCurrentClassName()
* getCurrentMethodName()
* getCurrentFileName()
*
* getInvokingClassName()
* getInvokingMethodName()
* getInvokingFileName()
*
* Nb. Using StackTrace's to get this info is expensive. There are more optimised ways to obtain
* method names. See other stackoverflow posts eg. /programming/421280/in-java-how-do-i-find-the-caller-of-a-method-using-stacktrace-or-reflection/2924426#2924426
*
* 29/09/2012 (lem) - added methods to return (1) fully qualified names and (2) invoking class/method names
*/
package com.stackoverflow.util;
public class StackTraceInfo
{
/* (Lifted from virgo47's stackoverflow answer) */
private static final int CLIENT_CODE_STACK_INDEX;
static {
// Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6
int i = 0;
for (StackTraceElement ste: Thread.currentThread().getStackTrace())
{
i++;
if (ste.getClassName().equals(StackTraceInfo.class.getName()))
{
break;
}
}
CLIENT_CODE_STACK_INDEX = i;
}
public static String getCurrentMethodName()
{
return getCurrentMethodName(1); // making additional overloaded method call requires +1 offset
}
private static String getCurrentMethodName(int offset)
{
return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getMethodName();
}
public static String getCurrentClassName()
{
return getCurrentClassName(1); // making additional overloaded method call requires +1 offset
}
private static String getCurrentClassName(int offset)
{
return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getClassName();
}
public static String getCurrentFileName()
{
return getCurrentFileName(1); // making additional overloaded method call requires +1 offset
}
private static String getCurrentFileName(int offset)
{
String filename = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getFileName();
int lineNumber = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getLineNumber();
return filename + ":" + lineNumber;
}
public static String getInvokingMethodName()
{
return getInvokingMethodName(2);
}
private static String getInvokingMethodName(int offset)
{
return getCurrentMethodName(offset + 1); // re-uses getCurrentMethodName() with desired index
}
public static String getInvokingClassName()
{
return getInvokingClassName(2);
}
private static String getInvokingClassName(int offset)
{
return getCurrentClassName(offset + 1); // re-uses getCurrentClassName() with desired index
}
public static String getInvokingFileName()
{
return getInvokingFileName(2);
}
private static String getInvokingFileName(int offset)
{
return getCurrentFileName(offset + 1); // re-uses getCurrentFileName() with desired index
}
public static String getCurrentMethodNameFqn()
{
return getCurrentMethodNameFqn(1);
}
private static String getCurrentMethodNameFqn(int offset)
{
String currentClassName = getCurrentClassName(offset + 1);
String currentMethodName = getCurrentMethodName(offset + 1);
return currentClassName + "." + currentMethodName ;
}
public static String getCurrentFileNameFqn()
{
String CurrentMethodNameFqn = getCurrentMethodNameFqn(1);
String currentFileName = getCurrentFileName(1);
return CurrentMethodNameFqn + "(" + currentFileName + ")";
}
public static String getInvokingMethodNameFqn()
{
return getInvokingMethodNameFqn(2);
}
private static String getInvokingMethodNameFqn(int offset)
{
String invokingClassName = getInvokingClassName(offset + 1);
String invokingMethodName = getInvokingMethodName(offset + 1);
return invokingClassName + "." + invokingMethodName;
}
public static String getInvokingFileNameFqn()
{
String invokingMethodNameFqn = getInvokingMethodNameFqn(2);
String invokingFileName = getInvokingFileName(2);
return invokingMethodNameFqn + "(" + invokingFileName + ")";
}
}
Um den Namen der Methode zu erhalten, die die aktuelle Methode aufgerufen hat, können Sie Folgendes verwenden:
new Exception("is not thrown").getStackTrace()[1].getMethodName()
Dies funktioniert sowohl auf meinem MacBook als auch auf meinem Android-Handy
Ich habe auch versucht:
Thread.currentThread().getStackTrace()[1]
aber Android wird "getStackTrace" zurückgeben. Ich könnte dies für Android mit beheben
Thread.currentThread().getStackTrace()[2]
aber dann bekomme ich auf meinem MacBook die falsche Antwort
getStackTrace()[0]
als zu verwenden getStackTrace()[1]
. YMMV.
Thread.currentThread().getStackTrace()[2]
Util.java:
public static String getCurrentClassAndMethodNames() {
final StackTraceElement e = Thread.currentThread().getStackTrace()[2];
final String s = e.getClassName();
return s.substring(s.lastIndexOf('.') + 1, s.length()) + "." + e.getMethodName();
}
SomeClass.java:
public class SomeClass {
public static void main(String[] args) {
System.out.println(Util.getCurrentClassAndMethodNames()); // output: SomeClass.main
}
}
final StackTraceElement e = Thread.currentThread().getStackTrace()[2];
arbeitet; Geben Sie e.getClassName();
den vollständigen Klassennamen und e.getMethodName()
den Methonnamen zurück.
getStackTrace()[2]
ist falsch, es muss sein, getStackTrace()[3]
weil: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] Die Funktion a (), die diese aufruft
Dies kann StackWalker
seit Java 9 erfolgen.
public static String getCurrentMethodName() {
return StackWalker.getInstance()
.walk(s -> s.skip(1).findFirst())
.get()
.getMethodName();
}
public static String getCallerMethodName() {
return StackWalker.getInstance()
.walk(s -> s.skip(2).findFirst())
.get()
.getMethodName();
}
StackWalker
ist so konzipiert, dass es faul ist, daher ist es wahrscheinlich effizienter als beispielsweise Thread.getStackTrace
ein Array für den gesamten Callstack. Weitere Informationen finden Sie auch im JEP.
Eine alternative Methode besteht darin, eine Ausnahme zu erstellen, aber nicht auszulösen und das Objekt zu verwenden, von dem die Stack-Trace-Daten abgerufen werden, da die einschließende Methode dies normalerweise tut den Index 0 hat - solange die JVM diese Informationen speichert, wie andere oben erwähnt. Dies ist jedoch nicht die billigste Methode.
Von Throwable.getStackTrace () (dies ist mindestens seit Java 5 dasselbe):
Das nullte Element des Arrays (unter der Annahme, dass die Länge des Arrays nicht Null ist) repräsentiert die Oberseite des Stapels. Dies ist der letzte Methodenaufruf in der Sequenz. In der Regel ist dies der Punkt, an dem dieses Wurfobjekt erstellt und geworfen wurde.
Das folgende Snippet geht davon aus, dass die Klasse nicht statisch ist (aufgrund von getClass ()), aber das ist eine Seite.
System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);
Ich habe eine Lösung mit diesem (In Android)
/**
* @param className fully qualified className
* <br/>
* <code>YourClassName.class.getName();</code>
* <br/><br/>
* @param classSimpleName simpleClassName
* <br/>
* <code>YourClassName.class.getSimpleName();</code>
* <br/><br/>
*/
public static void getStackTrace(final String className, final String classSimpleName) {
final StackTraceElement[] steArray = Thread.currentThread().getStackTrace();
int index = 0;
for (StackTraceElement ste : steArray) {
if (ste.getClassName().equals(className)) {
break;
}
index++;
}
if (index >= steArray.length) {
// Little Hacky
Log.w(classSimpleName, Arrays.toString(new String[]{steArray[3].getMethodName(), String.valueOf(steArray[3].getLineNumber())}));
} else {
// Legitimate
Log.w(classSimpleName, Arrays.toString(new String[]{steArray[index].getMethodName(), String.valueOf(steArray[index].getLineNumber())}));
}
}
Ich weiß nicht, was die Absicht ist, den Namen der aktuell ausgeführten Methode zu erhalten, aber wenn dies nur zum Debuggen dient, können Protokollierungsframeworks wie "logback" hier helfen. Bei der Rückmeldung müssen Sie beispielsweise nur das Muster "% M" in Ihrer Protokollierungskonfiguration verwenden . Dies sollte jedoch mit Vorsicht angewendet werden, da dies die Leistung beeinträchtigen kann.
Nur für den Fall, dass die Methode, deren Namen Sie kennen möchten, eine Junit-Testmethode ist, können Sie die Junit-TestName-Regel verwenden: https://stackoverflow.com/a/1426730/3076107
Die meisten Antworten hier scheinen falsch zu sein.
public static String getCurrentMethod() {
return getCurrentMethod(1);
}
public static String getCurrentMethod(int skip) {
return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
}
Beispiel:
public static void main(String[] args) {
aaa();
}
public static void aaa() {
System.out.println("aaa -> " + getCurrentMethod( ) );
System.out.println("aaa -> " + getCurrentMethod(0) );
System.out.println("main -> " + getCurrentMethod(1) );
}
Ausgänge:
aaa -> aaa
aaa -> aaa
main -> main
Ich habe die Antwort des Maklemenz ein wenig umgeschrieben :
private static Method m;
static {
try {
m = Throwable.class.getDeclaredMethod(
"getStackTraceElement",
int.class
);
}
catch (final NoSuchMethodException e) {
throw new NoSuchMethodUncheckedException(e);
}
catch (final SecurityException e) {
throw new SecurityUncheckedException(e);
}
}
public static String getMethodName(int depth) {
StackTraceElement element;
final boolean accessible = m.isAccessible();
m.setAccessible(true);
try {
element = (StackTraceElement) m.invoke(new Throwable(), 1 + depth);
}
catch (final IllegalAccessException e) {
throw new IllegalAccessUncheckedException(e);
}
catch (final InvocationTargetException e) {
throw new InvocationTargetUncheckedException(e);
}
finally {
m.setAccessible(accessible);
}
return element.getMethodName();
}
public static String getMethodName() {
return getMethodName(1);
}
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
getEnclosingMethod()
wirft ein NullPointerException
für mich in Java 7.
Was ist falsch an diesem Ansatz:
class Example {
FileOutputStream fileOutputStream;
public Example() {
//System.out.println("Example.Example()");
debug("Example.Example()",false); // toggle
try {
fileOutputStream = new FileOutputStream("debug.txt");
} catch (Exception exception) {
debug(exception + Calendar.getInstance().getTime());
}
}
private boolean was911AnInsideJob() {
System.out.println("Example.was911AnInsideJob()");
return true;
}
public boolean shouldGWBushBeImpeached(){
System.out.println("Example.shouldGWBushBeImpeached()");
return true;
}
public void setPunishment(int yearsInJail){
debug("Server.setPunishment(int yearsInJail=" + yearsInJail + ")",true);
}
}
Und bevor die Leute verrückt nach der Verwendung werden System.out.println(...)
, können und sollten Sie immer eine Methode erstellen, damit die Ausgabe umgeleitet werden kann, z.
private void debug (Object object) {
debug(object,true);
}
private void dedub(Object object, boolean debug) {
if (debug) {
System.out.println(object);
// you can also write to a file but make sure the output stream
// ISN'T opened every time debug(Object object) is called
fileOutputStream.write(object.toString().getBytes());
}
}