Is er een manier om de naam te krijgen van de methode die momenteel wordt uitgevoerd in Java?
Antwoord 1, autoriteit 100%
Technisch werkt dit…
String name = new Object(){}.getClass().getEnclosingMethod().getName();
Er wordt echter tijdens het compileren een nieuwe anonieme binnenklasse gemaakt (bijvoorbeeld YourClass$1.class
). Dit zal dus een .class
bestand maken voor elke methode die deze truc toepast. Bovendien wordt bij elke aanroep tijdens runtime een anders ongebruikte objectinstantie gemaakt. Dit kan dus een acceptabele debug-truc zijn, maar het brengt wel aanzienlijke overhead met zich mee.
Een voordeel van deze truc is dat getEnclosingMethod()
java.lang.reflect.Method
retourneert die kan worden gebruikt om alle andere informatie van de methode op te halen, inclusief annotaties en parameternamen. Dit maakt het mogelijk om onderscheid te maken tussen specifieke methoden met dezelfde naam (method overload).
Merk op dat volgens de JavaDoc van getEnclosingMethod()
deze truc geen SecurityException
zou moeten veroorzaken, aangezien innerlijke klassen met dezelfde klassenlader moeten worden geladen. Het is dus niet nodig om de toegangsvoorwaarden te controleren, zelfs niet als er een beveiligingsmanager aanwezig is.
Let op: het is vereist om getEnclosingConstructor()
te gebruiken voor constructors. Tijdens blokken buiten (benoemde) methoden, retourneert getEnclosingMethod()
null
.
Antwoord 2, autoriteit 55%
Thread.currentThread().getStackTrace()
bevat meestal de methode van waaruit je het aanroept, maar er zijn valkuilen (zie Javadoc):
Sommige virtuele machines kunnen onder bepaalde omstandigheden een of meer stackframes weglaten uit de stacktracering. In het extreme geval mag een virtuele machine die geen stacktraceerinformatie heeft met betrekking tot deze thread een array met lengte nul retourneren van deze methode.
Antwoord 3, autoriteit 41%
Januari 2009:
Een volledige code zou zijn (te gebruiken met @Bombe’s waarschuwingin gedachten):
/**
* 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
}
Meer in deze vraag.
Update december 2011:
blauwachtigeopmerkingen:
Ik gebruik JRE 6 en geef me een onjuiste methodenaam.
Het werkt als ikste[2 + depth].getMethodName().
schrijf
0
isgetStackTrace()
,1
isgetMethodName(int depth)
en2
roept de methode aan.
virgo47‘s antwoord(upvoted) berekent in feite de juiste index die moet worden toegepast om de naam van de methode terug te krijgen.
Antwoord 4, autoriteit 26%
We hebben deze code gebruikt om mogelijke variabiliteit in de stacktrace-index te verminderen – bel nu methodName util:
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();
}
}
Het lijkt overdreven, maar we hadden een vast nummer voor JDK 1.5 en waren een beetje verbaasd dat het veranderde toen we overstapten naar JDK 1.6. Nu is het hetzelfde in Java 6/7, maar je weet maar nooit. Het is geen bewijs voor veranderingen in die index tijdens runtime – maar hopelijk doet HotSpot dat niet slecht. 🙂
Antwoord 5, autoriteit 14%
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
naam heeft waarde foo.
Antwoord 6, autoriteit 13%
Beide opties werken voor mij met Java:
new Object(){}.getClass().getEnclosingMethod().getName()
Of:
Thread.currentThread().getStackTrace()[1].getMethodName()
Antwoord 7, autoriteit 10%
De snelste manierdie ik heb gevonden is dat:
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;
}
}
}
Het geeft rechtstreeks toegang tot de native methode getStackTraceElement(int depth). En slaat de toegankelijke methode op in een statische variabele.
Antwoord 8, autoriteit 8%
Gebruik de volgende 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);
Antwoord 9, autoriteit 7%
Dit kan worden gedaan met StackWalker
sinds Java 9.
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
is ontworpen om lui te zijn, dus het is waarschijnlijk efficiënter dan, laten we zeggen, Thread.getStackTrace
, dat gretig een array maakt voor de hele callstack. Zie ook de JEP voor meer informatie.
Antwoord 10, autoriteit 6%
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
}
Antwoord 11, autoriteit 4%
Dit is een uitbreiding op het antwoord van virgo47’s antwoord(hierboven).
Het biedt een aantal statische methoden om de huidige en aanroepende klasse- / methodenamen te krijgen.
/* Utility class: Getting the name of the current executing method
* https://stackoverflow.com/questions/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. https://stackoverflow.com/questions/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 + ")";
}
}
Antwoord 12, autoriteit 4%
Om de naam te krijgen van de methode die de huidige methode aanroept, kun je het volgende gebruiken:
new Exception("is not thrown").getStackTrace()[1].getMethodName()
Dit werkt zowel op mijn MacBook als op mijn Android-telefoon
Ik heb ook geprobeerd:
Thread.currentThread().getStackTrace()[1]
maar Android geeft “getStackTrace” terug
Ik kan dit voor Android oplossen met
Thread.currentThread().getStackTrace()[2]
maar dan krijg ik het verkeerde antwoord op mijn MacBook
Antwoord 13, autoriteit 3%
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
}
}
Antwoord 14
Een alternatieve methode is om een Exception te maken, maar niet te gooien, en dat object te gebruiken om de stacktrace-gegevens op te halen, aangezien de omsluitende methode meestalwees op index 0 – zolang de JVM die informatie opslaat, zoals anderen hierboven hebben vermeld. Dit is echter niet de goedkoopste methode.
Van Throwable.getStackTrace()(dit is hetzelfde sinds Java 5 tenminste):
Het nulde element van de array (ervan uitgaande dat de lengte van de array niet nul is) vertegenwoordigt de bovenkant van de stapel, wat de laatste methode-aanroep in de reeks is. Normaal gesprokenis dit het punt waarop deze worp is gemaakt en gegooid.
Het onderstaande fragment gaat ervan uit dat de klasse niet-statisch is (vanwege getClass()), maar dat is terzijde.
System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
Antwoord 15
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);
16
Ik weet niet wat de intentie is achter het krijgen van de naam van de momenteel uitgevoerde methode, maar als dat alleen voor debuggendoel is, kan het registreren van frameworks zoals “NODBACK”. Bijvoorbeeld, alles wat u hoeft te doen, is het bij de Gebruik het patroon “% m” in uw logboekconfiguratie . Dit moet echter met voorzichtigheid worden gebruikt, omdat dit de prestaties kan degraderen.
17
Voor het geval de methode welke naam u wilt weten, is een JUNIST-testmethode, dan kunt u Junit Testname-regel gebruiken: HTTPS: //stackoverflow.com/a/1426730/3076107
Antwoord 18
Ik gebruik dit codefragment met de nieuwste Android Studio met de nieuwste Java-update. Het kan worden aangeroepen vanuit elke activiteit, fragment, enz.
public static void logPoint() {
String[] splitPath = Thread.currentThread().getStackTrace()[3]
.toString().split("\\.");
Log.d("my-log", MessageFormat.format("{0} {1}.{2}",
splitPath[splitPath.length - 3],
splitPath[splitPath.length - 2],
splitPath[splitPath.length - 1]
));
}
noem het zo
logPoint();
uitvoer
... D/my-log: MainActivity onCreate[(MainActivity.java:44)]
Antwoord 19
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
Antwoord 20
Wat is er mis met deze aanpak:
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);
}
}
En voordat mensen gek worden van het gebruik van System.out.println(...)
, zou je altijd een methode kunnen en moeten maken zodat de uitvoer kan worden omgeleid, bijvoorbeeld:
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());
}
}