Java'da yürütülmekte olan yöntemin adını almanın bir yolu var mı?
Java'da yürütülmekte olan yöntemin adını almanın bir yolu var mı?
Yanıtlar:
Thread.currentThread().getStackTrace()
genellikle çağırdığınız yöntemi içerir, ancak tuzaklar vardır (bkz. Javadoc ):
Bazı sanal makineler, bazı durumlarda, yığın izlemeden bir veya daha fazla yığın çerçevesini atlayabilir. Aşırı durumda, bu iş parçacığıyla ilgili yığın izleme bilgisi olmayan bir sanal makinenin bu yöntemden sıfır uzunluklu bir dizi döndürmesine izin verilir.
Teknik olarak bu işe yarayacak ...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
Ancak, derleme zamanında yeni bir anonim iç sınıf oluşturulacaktır (örn. YourClass$1.class
). Bu, .class
bu hileyi dağıtan her yöntem için bir dosya oluşturur . Ayrıca, çalışma zamanı sırasında her çağrıda başka bir şekilde kullanılmayan bir nesne örneği oluşturulur. Yani bu kabul edilebilir bir hata ayıklama hilesi olabilir, ancak önemli bir ek yük ile birlikte gelir.
Bu hilenin bir avantajı, ek açıklamalar ve parametre adları da dahil olmak üzere yöntemin diğer tüm bilgilerini almak için kullanılabilen getEncosingMethod()
getirilerdir java.lang.reflect.Method
. Bu, aynı ada sahip belirli yöntemler (yöntem aşırı yüklenmesi) arasında ayrım yapmayı mümkün kılar.
getEnclosingMethod()
Bu SecurityException
sınıfın JavaDoc ' a göre iç sınıflar aynı sınıf yükleyici kullanılarak yüklenmelidir. Bu nedenle, bir güvenlik yöneticisi mevcut olsa bile erişim koşullarını kontrol etmeye gerek yoktur.
Yapıcılar için kullanılması gerekir getEnclosingConstructor()
. (Adlandırılmış) yöntemlerin dışındaki bloklar sırasında getEnclosingMethod()
döndürür null
.
getEnclosingMethod
sınıfın tanımlandığı yöntemin adını alır. this.getClass()
sana hiç yardım etmeyecek. @wutzebaer neden gerek bile? Bunlara zaten erişiminiz var.
Ocak 2009:
Tam kod ( @ Bombe'un uyarısı göz önünde bulundurularak kullanılacak) olacaktır:
/**
* 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
}
Bu soruda daha fazlası .
Aralık 2011 Güncellemesi:
mavimsi yorumlar:
JRE 6 kullanıyorum ve bana yanlış yöntem adı veriyor.
Yazarsam çalışırste[2 + depth].getMethodName().
0
olduğunugetStackTrace()
,1
olduğugetMethodName(int depth)
ve2
yöntemi çağırıyor.
virgo47 'ın cevabı (upvoted) aslında yöntem adını geri almak için uygulamak için sağ endeksi hesaplar.
StackTraceElement
diziyi hata ayıklama amacıyla yazdırmaya ve 'main' öğesinin gerçekten doğru yöntem olup olmadığını görmeye çalıştınız mı?
ste[2 + depth].getMethodName()
. 0 getStackTrace()
, 1 getMethodName(int depth)
ve 2 çağrı yöntemidir. Ayrıca bkz. @ Virgo47'nin yanıtı .
Bu kodu yığın izleme dizinindeki olası değişkenliği azaltmak için kullandık - şimdi methodName util'i çağırmanız yeterli:
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();
}
}
Görünüşe bakılırsa JDK 1.5 için sabit bir sayıya sahiptik ve JDK 1.6'ya taşındığımızda değiştiğine biraz şaşırdık. Şimdi Java 6/7'de de aynı, ama asla bilemezsiniz. Çalışma sırasında bu dizindeki değişikliklerin kanıtı değildir - ancak umarım HotSpot bunu kötü yapmaz. :-)
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
ad foo değerine sahip olacaktır.
null
Bu seçeneklerin ikisi de Java ile benim için çalışıyor:
new Object(){}.getClass().getEnclosingMethod().getName()
Veya:
Thread.currentThread().getStackTrace()[1].getMethodName()
Bulduğum en hızlı yol :
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;
}
}
}
Doğrudan getStackTraceElement (int deep) yöntemine erişir. Ve erişilebilir Yöntemi statik bir değişkende saklar.
new Throwable().getStackTrace()
, 5614ms aldı.
Aşağıdaki Kodu kullanın:
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();
}
Bu, virgo47'nin cevabındaki bir genişlemedir (yukarıda).
Geçerli ve çağıran sınıf / yöntem adlarını almak için bazı statik yöntemler sağlar.
/* 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 + ")";
}
}
Geçerli yöntemi çağıran yöntemin adını almak için şunları kullanabilirsiniz:
new Exception("is not thrown").getStackTrace()[1].getMethodName()
Bu, MacBook'umda ve Android telefonumda çalışıyor
Ayrıca denedim:
Thread.currentThread().getStackTrace()[1]
ancak Android "getStackTrace" i döndürecektir.
Thread.currentThread().getStackTrace()[2]
ama sonra MacBook'umda yanlış cevap alıyorum
getStackTrace()[0]
yerine benim için daha iyi çalıştı 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];
İşler; e.getClassName();
sınıfın tamamını e.getMethodName()
döndürün ve yöntem adını döndürün.
getStackTrace()[2]
yanlış, bu olmak zorundadır getStackTrace()[3]
, çünkü: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] fonksiyonu () bu bir çağrı
Bu StackWalker
Java 9'dan beri yapılabilir .
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
tembel olacak şekilde tasarlanmıştır, bu nedenle Thread.getStackTrace
, tüm çağrı istasyonu için hevesle bir dizi oluşturan , örneğin daha verimli olması muhtemeldir . Ayrıca daha fazla bilgi için JEP'e bakın.
Alternatif bir yöntem, bir Özel Durum oluşturmak, ancak atmak değil ve yığın izleme verilerinin alınacağı nesneyi kullanmaktır, çünkü kapalı yöntem tipik olarak 0 dizininde olacaktır - JVM bu bilgileri depoladığı sürece, diğerleri yukarıda bahsedilen. Ancak bu en ucuz yöntem değil.
Gönderen Throwable.getStackTrace () (bu en azından Java 5 beri aynı olmuştur):
Dizinin sıfırıncı öğesi (dizinin uzunluğunun sıfır olmadığı varsayılarak), dizideki son yöntem çağrısı olan yığının en üstünü temsil eder. Tipik olarak , bu atılabilir maddenin yaratıldığı ve atıldığı noktadır.
Aşağıdaki snippet, sınıfın statik olmadığını varsayar (getClass () nedeniyle), ancak bu bir yana.
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);
Bunu kullanarak çözümüm var (Android'de)
/**
* @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())}));
}
}
Şu anda yürütülen yöntemin adını almanın arkasındaki niyetin ne olduğunu bilmiyorum, ancak bu sadece hata ayıklama amaçlıysa, "logback" gibi çerçevelerin kaydedilmesi burada yardımcı olabilir. Örneğin, geri oturum açmada tek yapmanız gereken günlük yapılandırmanızda "% M" desenini kullanmaktır . Ancak, performansı düşürebileceğinden bu durum dikkatli kullanılmalıdır.
Bilmek istediğiniz yöntemin bir junit test yöntemi olması durumunda, junit TestName kuralını kullanabilirsiniz: https://stackoverflow.com/a/1426730/3076107
Buradaki cevapların çoğu yanlış görünüyor.
public static String getCurrentMethod() {
return getCurrentMethod(1);
}
public static String getCurrentMethod(int skip) {
return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
}
Misal:
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) );
}
Çıktılar:
aaa -> aaa
aaa -> aaa
main -> main
Maklemenz'in cevabını biraz yeniden yazdım :
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()
NullPointerException
Java 7'de benim için bir atar .
Bu yaklaşımda sorun nedir:
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);
}
}
Ve insanlar kullanım konusunda çıldırmadan önce System.out.println(...)
, çıktının yeniden yönlendirilebilmesi için her zaman bir yöntem oluşturabilir ve etmelisiniz, örneğin:
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());
}
}