Apakah ada cara untuk mendapatkan nama metode yang sedang dijalankan di Jawa?
Apakah ada cara untuk mendapatkan nama metode yang sedang dijalankan di Jawa?
Jawaban:
Thread.currentThread().getStackTrace()
biasanya akan berisi metode Anda memanggilnya tetapi ada jebakan (lihat Javadoc ):
Beberapa mesin virtual mungkin, dalam beberapa keadaan, menghilangkan satu atau lebih bingkai tumpukan dari jejak tumpukan. Dalam kasus ekstrem, mesin virtual yang tidak memiliki informasi jejak tumpukan mengenai utas ini diizinkan untuk mengembalikan array nol panjang dari metode ini.
Secara teknis ini akan berfungsi ...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
Namun, kelas dalam anonim baru akan dibuat selama waktu kompilasi (misalnya YourClass$1.class
). Jadi ini akan membuat .class
file untuk setiap metode yang menggunakan trik ini. Selain itu instance objek yang tidak digunakan dibuat pada setiap doa selama runtime. Jadi ini mungkin merupakan trik debug yang dapat diterima, tetapi ia datang dengan overhead yang signifikan.
Keuntungan dari trik ini adalah getEncosingMethod()
pengembalian java.lang.reflect.Method
yang dapat digunakan untuk mengambil semua informasi lain dari metode termasuk anotasi dan nama parameter. Hal ini memungkinkan untuk membedakan antara metode tertentu dengan nama yang sama (kelebihan metode).
Perhatikan bahwa menurut JavaDoc getEnclosingMethod()
trik ini tidak boleh membuang SecurityException
sebagai kelas dalam harus dimuat menggunakan loader kelas yang sama. Jadi tidak perlu memeriksa kondisi akses bahkan jika manajer keamanan hadir.
Diperlukan untuk digunakan getEnclosingConstructor()
untuk konstruktor. Selama blok di luar metode (bernama), getEnclosingMethod()
kembali null
.
getEnclosingMethod
mendapat nama metode di mana kelas didefinisikan. this.getClass()
tidak akan membantu Anda sama sekali. @wutzebaer mengapa Anda harus melakukannya? Anda sudah memiliki akses ke mereka.
Januari 2009:
Kode lengkap akan (untuk digunakan dengan peringatan @ Bombe dalam pikiran):
/**
* 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
}
Lebih banyak di pertanyaan ini .
Pembaruan Desember 2011:
komentar kebiruan :
Saya menggunakan JRE 6 dan memberi saya nama metode yang salah.
Ini berfungsi jika saya menulisste[2 + depth].getMethodName().
0
adalahgetStackTrace()
,1
adalahgetMethodName(int depth)
dan2
adalah metode yang memohon.
virgo47 's jawaban (upvoted) benar-benar menghitung indeks yang tepat untuk diterapkan dalam rangka untuk mendapatkan kembali nama metode.
StackTraceElement
array untuk tujuan debugging dan untuk melihat apakah 'main' sebenarnya metode yang tepat?
ste[2 + depth].getMethodName()
. 0 adalah getStackTrace()
, 1 adalah getMethodName(int depth)
dan 2 adalah metode memohon. Lihat juga jawaban @ virgo47 .
Kami menggunakan kode ini untuk mengurangi kemungkinan variabilitas dalam indeks jejak tumpukan - sekarang panggil saja 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();
}
}
Tampaknya overengineered, tetapi kami memiliki beberapa nomor tetap untuk JDK 1.5 dan sedikit terkejut itu berubah ketika kami pindah ke JDK 1.6. Sekarang sama di Jawa 6/7, tetapi Anda tidak pernah tahu. Ini bukan bukti perubahan indeks selama runtime - tetapi mudah-mudahan HotSpot tidak melakukan hal yang buruk. :-)
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
nama akan memiliki nilai foo.
null
Kedua opsi ini berfungsi untuk saya dengan Java:
new Object(){}.getClass().getEnclosingMethod().getName()
Atau:
Thread.currentThread().getStackTrace()[1].getMethodName()
Cara tercepat yang saya temukan adalah:
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;
}
}
}
Ini mengakses metode asli getStackTraceElement (kedalaman int) secara langsung. Dan menyimpan Metode yang dapat diakses dalam variabel statis.
new Throwable().getStackTrace()
mengambil 5614ms.
Gunakan Kode berikut:
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();
}
Ini adalah perluasan dari jawaban virgo47 (di atas).
Ini memberikan beberapa metode statis untuk mendapatkan nama kelas / metode saat ini dan memanggil.
/* 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 + ")";
}
}
Untuk mendapatkan nama metode yang disebut metode saat ini, Anda dapat menggunakan:
new Exception("is not thrown").getStackTrace()[1].getMethodName()
Ini berfungsi pada MacBook saya dan juga pada ponsel Android saya
Saya juga mencoba:
Thread.currentThread().getStackTrace()[1]
tapi Android akan mengembalikan "getStackTrace" Saya bisa memperbaiki ini untuk Android
Thread.currentThread().getStackTrace()[2]
tapi kemudian saya mendapatkan jawaban yang salah di MacBook saya
getStackTrace()[0]
daripada menggunakan 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];
bekerja; e.getClassName();
kembalikan nama kelas penuh dan e.getMethodName()
kembalikan nama methon.
getStackTrace()[2]
salah, itu pasti getStackTrace()[3]
karena: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] Fungsi a () memanggil yang satu ini
Ini bisa dilakukan menggunakan StackWalker
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
dirancang untuk menjadi malas, sehingga cenderung lebih efisien daripada, katakanlah, Thread.getStackTrace
yang dengan bersemangat membuat array untuk seluruh callstack. Lihat juga JEP untuk informasi lebih lanjut.
Metode alternatif adalah membuat, tetapi tidak melempar, Pengecualian, dan menggunakan objek itu untuk mendapatkan data jejak tumpukan, karena metode penutup biasanya akan berada di indeks 0 - selama JVM menyimpan informasi tersebut, seperti yang dimiliki orang lain. disebutkan di atas. Namun ini bukan metode termurah.
Dari Throwable.getStackTrace () (ini sudah sama sejak Java 5 setidaknya):
Elemen nol dari array (dengan asumsi panjang array adalah nol) mewakili bagian atas tumpukan, yang merupakan doa metode terakhir dalam urutan. Biasanya , ini adalah titik di mana lemparan ini dibuat dan dilemparkan.
Cuplikan di bawah ini menganggap kelas adalah non-statis (karena getClass ()), tapi itu samping.
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);
Saya punya solusi menggunakan ini (dalam 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())}));
}
}
Saya tidak tahu apa maksud di balik mendapatkan nama metode yang saat ini dieksekusi, tetapi jika itu hanya untuk tujuan debugging, maka kerangka kerja logging seperti "logback" dapat membantu di sini. Misalnya, dalam logback, yang perlu Anda lakukan adalah menggunakan pola "% M" dalam konfigurasi logging Anda . Namun, ini harus digunakan dengan hati-hati karena ini dapat menurunkan kinerja.
Untuk berjaga-jaga jika metode yang namanya ingin Anda ketahui adalah metode uji junit, maka Anda dapat menggunakan aturan Junit TestName: https://stackoverflow.com/a/1426730/3076107
Sebagian besar jawaban di sini tampaknya salah.
public static String getCurrentMethod() {
return getCurrentMethod(1);
}
public static String getCurrentMethod(int skip) {
return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
}
Contoh:
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) );
}
Output:
aaa -> aaa
aaa -> aaa
main -> main
Saya menulis ulang sedikit jawaban maklemenz :
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()
melempar NullPointerException
untuk saya di Jawa 7.
Apa yang salah dengan pendekatan ini:
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);
}
}
Dan sebelum orang tergila-gila menggunakan System.out.println(...)
Anda selalu, dan harus, membuat beberapa metode sehingga output dapat diarahkan, misalnya:
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());
}
}