Lấy tên của phương thức hiện đang thực thi


Câu trả lời:


177

Thread.currentThread().getStackTrace()thường sẽ chứa phương thức bạn gọi nó từ nhưng có những cạm bẫy (xem Javadoc ):

Một số máy ảo có thể, trong một số trường hợp, bỏ qua một hoặc nhiều khung ngăn xếp từ dấu vết ngăn xếp. Trong trường hợp cực đoan, một máy ảo không có thông tin theo dõi ngăn xếp liên quan đến luồng này được phép trả về một mảng có độ dài bằng không từ phương thức này.


7
Đây có phải là cạm bẫy tương tự đúng cho dấu vết ngăn xếp trong trường hợp ngoại lệ?
Nate Parsons

8
Vâng, đúng vậy. Các tài liệu cho Throwable . [GetStackTrace ()] ( download.oracle.com/javase/1.5.0/docs/api/java/lang/... chứa đoạn cùng chính xác.
Bombe

4
Điều cơ bản là JVM không bắt buộc phải có khả năng cung cấp một stacktrace, nhưng rất nhiều công việc đã đi vào khiến HotSpot trở nên rất đáng tin cậy. Tuy nhiên, bạn cần biết trong trường hợp bạn muốn mã của mình không dựa vào hành vi của một JVM cụ thể.
Thorbjørn Ravn Andersen

Phiên bản của Alexsmail bên dưới không tạo ra dấu vết ngăn xếp và cung cấp cho bạn quyền truy cập vào đối tượng phương thức thực tế, không chỉ tên (vì vậy bạn cũng có thể tìm ra kiểu trả về). Tôi không có ghế dài được đánh dấu nhưng tôi nghi ngờ phương pháp của anh ấy cũng nhanh hơn nhiều vì dấu vết ngăn xếp có xu hướng đắt tiền.
Gus

Câu trả lời của Devin dường như đưa ra một câu trả lời ngắn gọn hơn nhiều cho câu hỏi này.
tăngTide 3/2/2016

310

Về mặt kỹ thuật, nó sẽ hoạt động ...

String name = new Object(){}.getClass().getEnclosingMethod().getName();

Tuy nhiên, một lớp bên trong ẩn danh mới sẽ được tạo trong thời gian biên dịch (ví dụ YourClass$1.class). Vì vậy, điều này sẽ tạo ra một .classtệp cho mỗi phương thức triển khai thủ thuật này. Ngoài ra, một đối tượng không sử dụng khác được tạo trên mỗi lần gọi trong thời gian chạy. Vì vậy, đây có thể là một mẹo gỡ lỗi chấp nhận được, nhưng nó đi kèm với chi phí đáng kể.

Một lợi thế của thủ thuật này là getEncosingMethod()trả về java.lang.reflect.Methodcó thể được sử dụng để lấy tất cả thông tin khác của phương thức bao gồm chú thích và tên tham số. Điều này cho phép phân biệt giữa các phương thức cụ thể có cùng tên (quá tải phương thức).

Lưu ý rằng theo JavaDoc của getEnclosingMethod()thủ thuật này, không nên ném một SecurityExceptionlớp vì các lớp bên trong nên được tải bằng cùng một trình nạp lớp. Vì vậy, không cần phải kiểm tra các điều kiện truy cập ngay cả khi có trình quản lý bảo mật.

Nó là cần thiết để sử dụng getEnclosingConstructor()cho các nhà xây dựng. Trong các khối bên ngoài các phương thức (được đặt tên), getEnclosingMethod()trả về null.


9
Điều này sẽ không cung cấp cho bạn phương pháp hiện đang thực hiện. Điều này sẽ cung cấp cho bạn phương thức trong đó một lớp ẩn danh / cục bộ được định nghĩa. - docs.oracle.com/javase/6/docs/api/java/lang/ triệt
shrini1000

7
lớp Địa phương {}; Tên chuỗi = Local. Class.getEnclosesMethod (). GetName ();
alexsmail

21
@ shrini1000 ý tưởng là sử dụng đoạn mã này khi cần thông tin và không đưa nó vào thói quen của thư viện.
Thorbjørn Ravn Andersen

4
Cảm ơn vì những lời khuyên ! Thay vì tạo một đối tượng mới, chỉ cần sử dụng this.getClass (). GetEnclosesMethod (). GetName ();
Lilo

3
@Lilo không chính xác. getEnclosingMethodlấy tên của phương thức trong đó lớp được định nghĩa. this.getClass()sẽ không giúp bạn chút nào @wutzebaer tại sao bạn thậm chí cần phải? Bạn đã truy cập chúng rồi.
Đội quân Hazel

134

Tháng 1 năm 2009:
Một mã đầy đủ sẽ là (để sử dụng với suy nghĩ của @ 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
}

Thêm trong câu hỏi này .

Cập nhật tháng 12 năm 2011:

ý kiến hơi xanh :

Tôi sử dụng JRE 6 và cung cấp cho tôi tên phương thức không chính xác.
Nó hoạt động nếu tôi viếtste[2 + depth].getMethodName().

  • 0getStackTrace(),
  • 1getMethodName(int depth)
  • 2 đang gọi phương thức.

Câu trả lời của virgo47 (được nâng cấp) thực sự tính toán chỉ số đúng để áp dụng để lấy lại tên phương thức.


2
Nó chỉ nói "chính" cho tôi. : - /
Hợp đồng của Giáo sư Falken vi phạm

@Amigable: bạn đã thử in tất cả các StackTraceElementmảng cho mục đích gỡ lỗi và để xem liệu 'chính' có thực sự là phương pháp đúng không?
VonC

7
Tôi sử dụng JRE 6 và cung cấp cho tôi tên phương thức không chính xác. Nó hoạt động nếu tôi viết ste[2 + depth].getMethodName(). 0 là getStackTrace(), 1 là getMethodName(int depth)và 2 là gọi phương thức. Xem thêm câu trả lời của @ virgo47 .
xanh nhạt

2
@bluish: điểm tốt. Tôi đã bao gồm nhận xét của bạn và một tài liệu tham khảo cho câu trả lời của virgo47 trong tôi.
VonC

@VonC Việc thực hiện này có thực sự đúng không? độ sâu ở đây phải là ste.length + 1 để đưa ra phương thức hiện tại. Không nên ste [độ sâu + 1] nếu chúng ta cho phép độ sâu = 0?
mmm

85

Chúng tôi đã sử dụng mã này để giảm thiểu khả năng thay đổi tiềm năng trong chỉ mục theo dõi ngăn xếp - bây giờ chỉ cần gọi phương thứcName tận dụng:

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();
    }
}

Có vẻ bị áp đảo, nhưng chúng tôi đã có một số số cố định cho JDK 1.5 và hơi ngạc nhiên khi nó thay đổi khi chúng tôi chuyển sang JDK 1.6. Bây giờ nó giống với Java 6/7, nhưng bạn không bao giờ biết. Nó không phải là bằng chứng cho những thay đổi trong chỉ mục đó trong thời gian chạy - nhưng hy vọng HotSpot không làm điều đó tồi tệ. :-)


1
Đây vẫn là nhà cung cấp phụ thuộc tinh tế. JVM không bắt buộc phải cung cấp dữ liệu đáng tin cậy cho mã này.
Thorbjørn Ravn Andersen

6
Theo thông số JVM, JVM không bắt buộc phải cung cấp dấu vết ngăn xếp đầy đủ (tối ưu hóa, nội tuyến và tất cả những thứ đó) và bạn đã phát hiện ra rằng heuristic của bạn đã thay đổi giữa Oracle Java 5 và Oracle Java 6. Không có gì đảm bảo rằng bất kỳ JVM nào khác sẽ hành xử như bạn mong đợi trong mã của bạn, vì vậy bạn đang tinh tế dựa vào hành vi cụ thể của nhà cung cấp. Điều này là hoàn toàn tốt, miễn là bạn biết điều đó, nhưng nếu - chẳng hạn - bạn cần triển khai trên IBM JVM (mà chúng ta phải) hoặc trên một cá thể Zing, bạn có thể phải xem lại heuristic của mình.
Thorbjørn Ravn Andersen

1
Điều này có vẻ mạnh mẽ nhất trong tất cả các tùy chọn được trình bày ở đây, phụ thuộc vào mặc dù.
Ian

46
 public class SomeClass {
   public void foo(){
      class Local {};
      String name = Local.class.getEnclosingMethod().getName();
   }
 }

Tên sẽ có giá trị foo.


5
Local.group.getEnclosesMethod () là null. jdk1.6.0_31, chơi 1.2.5
eigil

@eigil điều đó thật thú vị nhưng không có thêm thông tin, thật khó để nói điều gì đã "sai" hoặc khi nào chúng ta nên mong đợinull
Maarten Bodewes

Đây là mẹo tương tự như câu trả lời này . Nó có ưu điểm là nó không tạo ra một thể hiện đối tượng giả, nó có nhược điểm là nó yêu cầu một khai báo lớp không thể được nội tuyến trong câu lệnh (nghĩa là thông thường nó yêu cầu một dòng mã bổ sung).
Maarten Bodewes

@eigil bạn đã định nghĩa lớp trong một lớp (ví dụ someClass) hay trong một phương thức (ví dụ foo)? Tôi thấy rằng việc xác định một lớp con mà không được bọc trong một phương thức - hoặc trong một hàm tạo - sẽ khiến getEnclosesMethod () trả về null.
DN

Khá chắc chắn rằng tôi đã làm chính xác như được mô tả trong câu trả lời này. Tôi nghĩ đó là một cái gì đó kỳ lạ với playframework. Đã thử nghiệm trong java 'bình thường' mà không có bất kỳ vấn đề.
eigil

36

Cả hai tùy chọn này đều hoạt động với tôi với Java:

new Object(){}.getClass().getEnclosingMethod().getName()

Hoặc là:

Thread.currentThread().getStackTrace()[1].getMethodName()

1
đối với các phương thức tĩnh, hãy sử dụng: <Class>. class.getEnclosesMethod (). getName ()
jellobird

hãy cẩn thận với mảng trống theo câu trả lời và chỉ dẫn javadoc của Bombe. Một số JVM có thể không điền vào mảng stacktrace?
el-teedee

34

Cách nhanh nhất tôi tìm thấy là:

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;
        }
    }
}

Nó truy cập trực tiếp vào phương thức gốc getStackTraceEuity (int height). Và lưu trữ Phương thức có thể truy cập trong một biến tĩnh.


3
Nhanh nhất như trong hiệu suất khôn ngoan? Bất kỳ điểm chuẩn vi mô để hỗ trợ yêu cầu?
Ibrahim Arief

10
+1. Sử dụng một vòng lặp thời gian đơn giản trên 1.6, 1.000.000 lần lặp bằng phương pháp này mất 1219ms, trong khi sử dụng new Throwable().getStackTrace()mất 5614ms.
ach

1
m.setAccessible (đúng); nên được bao quanh bởi AccessControll.doPriv đặc biệt. Một cái gì đó để xem xét, không phải là một quy tắc cứng tôi sẽ nói
avanderw

6
Đã thử nghiệm vào năm 2016 và điều này tiếp tục là nhanh nhất. Giống như @ach tôi đã sử dụng các lần lặp 1M. 1.7_79: 1.6s so với 15.2s 1.8_74: 1.8s so với 16.0s. FWIW chiều dài của ste điểm chuẩn của tôi == 23 nhưng phương pháp này vẫn nhanh bất kể độ sâu của ngăn xếp.
Ryan

25

Sử dụng mã sau đây:

    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
    StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
    String methodName = e.getMethodName();
    System.out.println(methodName);

2
Điều này in ra "getStackTrace" cho tôi - Tôi đang sử dụng Java 1.5
Zack Macomber

hãy cẩn thận với mảng trống theo câu trả lời và chỉ dẫn javadoc của Bombe. Một số JVM có thể không điền vào mảng stacktrace?
el-teedee

16
public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
    }

Vâng, cho đến nay, tốt nhất ... biến nó thành một phương thức và lấy khung thứ ba ([2]) (hoặc bất cứ thứ gì nó được gọi) trong dấu vết.
loài gặm nhấm mike

14

Đây là một bản mở rộng về câu trả lời của virgo47 (ở trên).

Nó cung cấp một số phương thức tĩnh để có được các tên lớp / phương thức hiện tại và gọi.

/* 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 + ")";
    }
}

3
Điều này kết hợp với câu trả lời của @ mklemenz là một cách rất nhanh và rõ ràng để truy cập thông tin ngăn xếp.
Octavia Togami

12

Để có được tên của phương thức được gọi là phương thức hiện tại, bạn có thể sử dụng:

new Exception("is not thrown").getStackTrace()[1].getMethodName()

Điều này hoạt động trên MacBook cũng như trên điện thoại Android của tôi

Tôi cũng đã thử:

Thread.currentThread().getStackTrace()[1]

nhưng Android sẽ trả về "getStackTrace" Tôi có thể sửa lỗi này cho Android bằng

Thread.currentThread().getStackTrace()[2]

nhưng sau đó tôi nhận được câu trả lời sai trên MacBook của tôi


Trong thử nghiệm gần đây trên Android, nó hoạt động tốt hơn đối với tôi để sử dụng getStackTrace()[0]hơn là getStackTrace()[1]. YMMV.
mbm29414

lên cho Android làThread.currentThread().getStackTrace()[2]
Ninja

11

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();
}

Một sốClass.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]; làm; e.getClassName();trả lại tên lớp đầy đủ và e.getMethodName()trả lại tên methon.
Đánh dấu

1
getStackTrace()[2]là sai, nó phải được getStackTrace()[3]bởi vì: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] Các chức năng một () gọi này
PhilLab

11

Điều này có thể được thực hiện bằng cách sử dụng StackWalkerJava 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được thiết kế để lười biếng, do đó, nó có khả năng hiệu quả hơn, giả sử, Thread.getStackTraceháo hức tạo ra một mảng cho toàn bộ cửa hàng. Cũng xem JEP để biết thêm thông tin.


5

Một phương thức thay thế là tạo, nhưng không ném, Ngoại lệ và sử dụng đối tượng đó để lấy dữ liệu theo dõi ngăn xếp, vì phương thức kèm theo thường sẽ ở chỉ số 0 - miễn là JVM lưu trữ thông tin đó, như những người khác có đã đề cập ở trên. Đây không phải là phương pháp rẻ nhất, tuy nhiên.

Từ throwable.getStackTrace () (điều này ít nhất giống với Java 5):

Phần tử zeroth của mảng (giả sử độ dài của mảng là khác không) đại diện cho đỉnh của ngăn xếp, đây là lời gọi phương thức cuối cùng trong chuỗi. Thông thường , đây là điểm mà cái ném này được tạo ra và ném.

Đoạn mã dưới đây giả định lớp không tĩnh (vì getClass ()), nhưng đó là một bên.

System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());

4
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);

1
Xem câu trả lời của mvanle virgo47 ở trên và nhận xét về thorbjorn-ravn-andersen. Lặp lại, mã không chính xác và không đáng tin cậy.
alexsmail

@ShivaKomuravelly Có, nhưng dường như không phải trong bất kỳ tình huống nào, vì vậy -1 từ tôi cũng vậy.
Maarten Bodewes

3

Tôi đã có giải pháp sử dụng điều này (Trong 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())}));
    }
}

3

Tôi không biết ý định đằng sau việc lấy tên của phương thức hiện được thực hiện là gì, nhưng nếu đó chỉ nhằm mục đích gỡ lỗi, thì các khung đăng nhập như "logback" có thể giúp ích ở đây. Ví dụ, trong logback, tất cả những gì bạn cần làm là sử dụng mẫu "% M" trong cấu hình ghi nhật ký của bạn . Tuy nhiên, điều này nên được sử dụng một cách thận trọng vì điều này có thể làm giảm hiệu suất.


2

Chỉ trong trường hợp phương thức mà tên bạn muốn biết là phương thức kiểm tra Junit, thì bạn có thể sử dụng quy tắc Testit của Junit: https://stackoverflow.com/a/1426730/3076107


1
@AndreiKonstantinov Tôi không nghĩ rằng đây chỉ là liên kết. Ngay cả khi bạn xóa liên kết, vẫn có ít nhất một số thông tin sẽ tiếp tục.
EJoshuaS - Phục hồi Monica

1

Hầu hết các câu trả lời ở đây có vẻ sai.

    public static String getCurrentMethod() {
            return getCurrentMethod(1);
    }
    public static String getCurrentMethod(int skip) {
            return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
    }

Thí dụ:

    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) );
    }

Đầu ra:

aaa  -> aaa
aaa  -> aaa
main -> main

Cảm ơn câu trả lời hữu ích của bạn.
AmerllicA

Bạn có thể vui lòng làm rõ tại sao hầu hết các câu trả lời có vẻ sai cho bạn? Có rất nhiều câu trả lời và tôi không rành về Java để đọc tất cả chúng và để hiểu sự khác biệt giữa chúng và câu trả lời của bạn. :(
Xobotun

@mmm Xin lỗi, nhưng tôi rất không đồng ý. Tôi đến đây để học và nhiều người khác cũng vậy, tôi tin thế. Tôi chỉ không thể hiểu tại sao bạn nghĩ rằng tôi không xứng đáng để biết thêm về chủ đề này. Tôi muốn ít mắc lỗi hơn trong mã của mình và cảnh báo cho những người khác, không tuân theo một số giáo phái hàng hóa. Ít nhất bạn đã có thể làm rõ phiên bản Java mà mã này phải chính xác. :( Một câu trả lời dưới đây cho biết có sự thay đổi trong stacktrace giữa 1.5 và 1.6. Có lẽ bạn ngụ ý có điều gì đó tương tự trong Java 14 sắp tới, làm sao tôi biết được. Hoặc nhà cung cấp khác có thể có. Xin lỗi nếu tôi hiểu sai câu trả lời của bạn là thô lỗ một.
Xobotun

0

Tôi đã viết lại một chút câu trả lời của 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);
}

-2
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();

11
Vui lòng chỉnh sửa với nhiều thông tin hơn. Các câu trả lời chỉ dành cho mã và "thử cái này" không được khuyến khích, vì chúng không chứa nội dung có thể tìm kiếm và không giải thích lý do tại sao một người nào đó nên "thử cái này".
abarisone

1
Mặc dù mã này có thể giúp giải quyết vấn đề, nhưng nó không giải thích được tại sao và / hoặc cách nó trả lời câu hỏi. Cung cấp bối cảnh bổ sung này sẽ cải thiện đáng kể giá trị giáo dục lâu dài của nó. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích, bao gồm những hạn chế và giả định được áp dụng.
Toby Speight

1
Chỉ dành cho Java 7+, nhưng cách ngắn gọn để có được tên phương thức. Tuy nhiên, vẫn là những cân nhắc về hiệu suất của một cuộc gọi như vậy.
Benj

6
getEnclosingMethod()ném NullPointerExceptioncho tôi trong Java 7.
Markus L

2
Java.lang.Class.getEnclosesMethod () trả về một đối tượng Phương thức đại diện cho phương thức kèm theo ngay lập tức của lớp bên dưới, nếu đối tượng Class này đại diện cho một lớp cục bộ hoặc ẩn danh trong một phương thức, thì khác trả về null.
bếp

-5

Có gì sai với cách tiếp cận này:

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);
    }
}

Và trước khi mọi người phát điên về việc sử dụng System.out.println(...)bạn luôn có thể, và nên, tạo một số phương thức để đầu ra có thể được chuyển hướng, ví dụ:

    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());
        }
    }

4
@Saksham có vẻ như đó thực sự là một nỗ lực để trả lời câu hỏi. Không phải là một nỗ lực lớn, nhưng một nỗ lực không hơn không kém.
ivarni

@ivarni "không phải là một nỗ lực tốt"? có gì sai với nó? bạn có quen thuộc với "nguyên tắc hôn" không?
johnny

@Saksham đó là lời hùng biện.
johnny

5
@johnny Trong codebase tôi có trước mặt tôi có 271 lớp. Ngay cả với (5 ước tính thấp) có 5 phương thức cho mỗi lớp có hơn 1300 phương thức. Và đây thậm chí không phải là một cơ sở mã lớn. Bạn không thấy vấn đề với việc mở rộng cách tiếp cận của bạn? Tôi khá vui khi đồng ý không đồng ý, nhưng đó là lý do tại sao tôi nói đó không phải là một nỗ lực tốt. Nó giới thiệu một lượng lớn chi phí trong bất kỳ cơ sở mã hóa không tầm thường nào.
ivarni

1
@johnny Tôi đoán tôi đã thấy quá nhiều trường hợp tên phương thức không khớp với chuỗi đã gửi cho tôi sai hướng khi gỡ lỗi. Nhưng trong Java tôi vẫn nghĩ đề xuất của bạn là tốt nhất, các lựa chọn thay thế khác "tốn kém" quá nhiều.
Chỉ là một siêu dữ liệu khác
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.