รับชื่อของวิธีการดำเนินการในปัจจุบัน


คำตอบ:


177

Thread.currentThread().getStackTrace()มักจะมีวิธีการที่คุณเรียกใช้ แต่มีข้อผิดพลาด (ดูJavadoc ):

เครื่องเสมือนบางเครื่องอาจไม่รวมกรอบสแต็กหนึ่งเฟรมขึ้นไปจากการติดตามสแต็ก ในกรณีที่รุนแรงเครื่องเสมือนที่ไม่มีข้อมูลการติดตามสแต็กที่เกี่ยวข้องกับเธรดนี้ได้รับอนุญาตให้ส่งกลับอาร์เรย์ที่มีความยาวเป็นศูนย์จากวิธีนี้


7
ข้อผิดพลาดนี้เป็นจริงสำหรับการติดตามสแต็กในข้อยกเว้นหรือไม่
Nate Parsons

8
ใช่แล้ว. เอกสารประกอบสำหรับThrowable [getStackTrace ()] ( download.oracle.com/javase/1.5.0/docs/api/java/lang/…มีย่อหน้าเดียวกันที่แน่นอน
Bombe

4
สิ่งที่สำคัญคือ JVM ไม่จำเป็นต้องให้สแต็คสแตร็ก แต่งานจำนวนมากได้ทำให้ HotSpot เชื่อถือได้มาก อย่างไรก็ตามคุณจำเป็นต้องรู้ในกรณีที่คุณต้องการให้โค้ดของคุณไม่ขึ้นอยู่กับพฤติกรรมของ JVM ที่เฉพาะเจาะจง
Thorbjørn Ravn Andersen

เวอร์ชันของ Alexsmail ด้านล่างไม่ได้สร้างการติดตามสแต็กและให้คุณเข้าถึงวัตถุวิธีการที่แท้จริงไม่ใช่แค่ชื่อ (เพื่อให้คุณสามารถหาประเภทผลตอบแทนได้เช่นกัน) ฉันไม่ได้ทำเครื่องหมายบนโต๊ะ แต่ฉันสงสัยว่าวิธีการของเขานั้นเร็วกว่ามากเช่นกันเนื่องจากร่องรอยสแต็คมีแนวโน้มที่จะมีราคาแพง
กัส

คำตอบของ Devin ดูเหมือนจะให้คำตอบสั้น ๆ สำหรับคำถามนี้
risingTide

310

ในทางเทคนิคจะใช้งานได้ ...

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

อย่างไรก็ตามคลาสภายในที่ไม่ระบุชื่อใหม่จะถูกสร้างขึ้นในช่วงเวลารวบรวม (เช่นYourClass$1.class) ดังนั้นสิ่งนี้จะสร้าง.classไฟล์สำหรับแต่ละวิธีที่ปรับใช้เคล็ดลับนี้ นอกจากนี้ยังมีการสร้างอินสแตนซ์วัตถุที่ไม่ได้ใช้เป็นอย่างอื่นในแต่ละการเรียกใช้ระหว่างรันไทม์ ดังนั้นนี่อาจเป็นเคล็ดลับการดีบักที่ยอมรับได้ แต่มันมาพร้อมค่าใช้จ่ายที่สำคัญ

ข้อดีของเคล็ดลับนี้คือการgetEncosingMethod()ส่งคืนjava.lang.reflect.Methodซึ่งสามารถใช้เพื่อดึงข้อมูลอื่น ๆ ทั้งหมดของวิธีการรวมถึงคำอธิบายประกอบและชื่อพารามิเตอร์ สิ่งนี้ทำให้สามารถแยกความแตกต่างระหว่างเมธอดที่ระบุด้วยชื่อเดียวกัน (เมธอดโอเวอร์โหลด)

โปรดทราบว่าตาม JavaDoc ของgetEnclosingMethod()เคล็ดลับนี้ไม่ควรโยนSecurityExceptionเป็นคลาสภายในควรโหลดโดยใช้ตัวโหลดคลาสเดียวกัน ดังนั้นจึงไม่จำเป็นต้องตรวจสอบเงื่อนไขการเข้าถึงแม้ว่าจะมีผู้จัดการความปลอดภัยอยู่ก็ตาม

มันจะต้องใช้getEnclosingConstructor()สำหรับการก่อสร้าง ในระหว่างการบล็อกนอก (ชื่อ) วิธีการรับผลตอบแทนgetEnclosingMethod()null


9
วิธีนี้จะไม่ให้วิธีการดำเนินการแก่คุณในขณะนี้ นี่จะให้วิธีการที่กำหนดคลาสแบบไม่ระบุชื่อ / โลคัล - docs.oracle.com/javase/6/docs/api/java/lang/…
shrini1000

7
ระดับท้องถิ่น {}; ชื่อสตริง = Local.class.getEnclosingMethod (). getName ();
alexsmail

21
@ shrini1000 แนวคิดนี้คือการใช้ตัวอย่างข้อมูลนี้ในที่ที่ต้องการข้อมูลและไม่นำไปไว้ในรูทีนไลบรารี
Thorbjørn Ravn Andersen

4
ขอบคุณสำหรับเคล็ดลับ! แทนที่จะสร้างวัตถุใหม่ให้ใช้ this.getClass (). getEnclosingMethod (). getName ();
Lilo

3
@Lilo ไม่ถูกต้อง getEnclosingMethodรับชื่อของวิธีการที่คลาสที่ถูกกำหนด this.getClass()จะไม่ช่วยคุณเลย @wutzebaer ทำไมคุณถึงต้องทำด้วย? คุณสามารถเข้าถึงได้แล้ว
Hazel Troost

134

มกราคม 2009:
รหัสเต็มจะเป็น (เพื่อใช้กับข้อแม้ของ @ 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
}

เพิ่มเติมในคำถามนี้

อัปเดตธันวาคม 2554:

ความคิดเห็นสีน้ำเงิน :

ฉันใช้ JRE 6 และทำให้ชื่อวิธีไม่ถูกต้อง
มันทำงานได้ถ้าฉันเขียนste[2 + depth].getMethodName().

  • 0คือgetStackTrace(),
  • 1เป็นgetMethodName(int depth)และ
  • 2 เป็นวิธีการเรียก

คำตอบของvirgo47 (upvoted) คำนวณดัชนีที่ถูกต้องเพื่อนำไปใช้เพื่อเรียกชื่อเมธอดกลับคืน


2
มันบอกว่า "หลัก" สำหรับฉันเท่านั้น : - /
ศ. Falken ผิดสัญญา

@Amigable: คุณพยายามพิมพ์StackTraceElementอาเรย์ทั้งหมดเพื่อจุดประสงค์ในการดีบั๊กหรือไม่และดูว่า 'main' เป็นวิธีที่ถูกต้องหรือไม่?
VonC

7
ฉันใช้ JRE 6 และทำให้ชื่อวิธีไม่ถูกต้อง ste[2 + depth].getMethodName()มันทำงานได้ถ้าผมเขียน 0 คือgetStackTrace()1 getMethodName(int depth)และ 2 คือวิธีการเรียกใช้ ดูเพิ่มเติม@ คำตอบของ
สีน้ำเงิน

2
@ สีน้ำเงิน: จุดดี ฉันได้รวมความคิดเห็นของคุณและการอ้างอิงถึงคำตอบของ virgo47 ในของฉัน
VonC

@VonC การใช้งานนี้ถูกต้องจริงเหรอ? ความลึกที่นี่ต้องเป็น ste.length + 1 เพื่อให้วิธีการปัจจุบัน ไม่ควรที่จะเลือก [ความลึก + 1] ถ้าเราอนุญาตให้มีความลึก = 0
mmm

85

เราใช้รหัสนี้เพื่อลดความแปรปรวนที่อาจเกิดขึ้นในดัชนีการติดตามสแต็กตอนนี้เพียงแค่เรียก 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();
    }
}

ดูเหมือนว่า overengineered แต่เรามีหมายเลขคงที่สำหรับ JDK 1.5 และรู้สึกประหลาดใจเล็กน้อยที่มันเปลี่ยนไปเมื่อเราย้ายไปที่ JDK 1.6 ตอนนี้มันเหมือนกันใน Java 6/7 แต่คุณไม่มีทางรู้ มันไม่ได้เป็นข้อพิสูจน์ถึงการเปลี่ยนแปลงในดัชนีนั้นในระหว่างรันไทม์ - แต่หวังว่า HotSpot จะไม่ทำสิ่งนั้นไม่ดี :-)


1
นี่ยังขึ้นอยู่กับผู้ขายอย่างละเอียด JVM ไม่จำเป็นต้องใช้ในการส่งข้อมูลที่เชื่อถือได้สำหรับรหัสนี้
Thorbjørn Ravn Andersen

6
ตามข้อกำหนด JVM JVM ไม่จำเป็นต้องจัดเตรียมการติดตามสแต็กเต็มรูปแบบ (การเพิ่มประสิทธิภาพการอินไลน์และสิ่งอื่น ๆ ) และคุณได้ค้นพบแล้วว่าฮิวริสติกของคุณเปลี่ยนไประหว่าง Oracle Java 5 และ Oracle Java 6 ไม่มีอะไรรับประกันได้ว่า JVM อื่น ๆ ประพฤติตามที่คุณคาดหวังในรหัสของคุณดังนั้นคุณจึงต้องพึ่งพาพฤติกรรมของผู้ขายอย่างละเอียด สิ่งใดที่สมบูรณ์แบบที่สุดตราบใดที่คุณตระหนักถึงสิ่งนั้น แต่ถ้า - คุณต้องปรับใช้บน IBM JVM (ซึ่งเราต้อง) และ Zing instance คุณอาจต้องทบทวนฮิวริสติกของคุณอีกครั้ง
Thorbjørn Ravn Andersen

1
ดูเหมือนว่าจะมีประสิทธิภาพมากที่สุดของตัวเลือกทั้งหมดที่นำเสนอที่นี่พึ่งพาถึงแม้ว่า
Ian

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

ชื่อจะมีค่า foo


5
Local.class.getEnclosingMethod () เป็นโมฆะ jdk1.6.0_31 เล่น 1.2.5
eigil

@ eigil ที่น่าสนใจ แต่ไม่มีข้อมูลเพิ่มเติมมันยากที่จะบอกว่าเกิดอะไรขึ้น "ผิด" หรือเมื่อเราควรคาดหวังnull
Maarten Bodewes

นี่เป็นเคล็ดลับเดียวกับคำตอบนี้ มันมีข้อได้เปรียบที่มันไม่ได้สร้างอินสแตนซ์ของวัตถุปลอมมันมีข้อเสียที่ต้องมีการประกาศคลาสซึ่งไม่สามารถ inlined ในคำสั่ง (เช่นปกติมันต้องมีบรรทัดของรหัสเพิ่มเติม)
Maarten Bodewes

@eigil คุณกำหนดคลาสภายในคลาส (ตัวอย่าง SomeClass) หรือภายในเมธอด (ตัวอย่าง foo) ฉันพบว่าการกำหนดคลาสย่อยโดยไม่มีการห่อในเมธอด - หรือในตัวสร้าง - จะทำให้ getEnclosingMethod () เพื่อส่งคืนค่าว่าง
DN

ค่อนข้างแน่ใจว่าฉันทำตามที่อธิบายไว้ในคำตอบนี้ ฉันคิดว่ามันเป็นสิ่งที่แปลกด้วย playframework ทดสอบในจาวา 'ปกติ' โดยไม่มีปัญหาใด ๆ
eigil

36

ตัวเลือกทั้งสองนี้ใช้ได้สำหรับฉันกับ Java:

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

หรือ:

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

1
สำหรับวิธีการคงที่ใช้: <Class> .class.getEnclosingMethod (). getName ()
jellobird

ระวังอาร์เรย์ว่างเปล่าตามคำตอบของ Bombe และตัวบ่งชี้ javadoc JVM บางตัวอาจไม่เติมอาเรย์สแต็คแบบเต็ม?
el-teedee

34

วิธีที่เร็วที่สุดที่ฉันพบคือ:

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

มันเข้าถึงเมธอดดั้งเดิม getStackTraceElement (ความลึก int) โดยตรง และเก็บวิธีการเข้าถึงในตัวแปรแบบคงที่


3
เร็วที่สุดในด้านประสิทธิภาพ เกณฑ์มาตรฐานขนาดเล็กใด ๆ ที่สนับสนุนการเรียกร้อง?
Ibrahim Arief

10
+1 ใช้การวนรอบแบบง่ายบน 1.6, 1,000,000 iterations โดยใช้วิธีนี้ใช้เวลา 1219ms ในขณะที่ใช้new Throwable().getStackTrace()เอา 5614ms
ACH

1
m.setAccessible (จริง); ควรล้อมรอบด้วย AccessController.doPrivileged สิ่งที่ต้องพิจารณาไม่ใช่กฎที่ยากที่ฉันจะพูดได้
avanderw

6
ทดสอบในปี 2559 และสิ่งนี้ยังคงเป็นวิธีที่เร็วที่สุด เช่นเดียวกับ @ach ฉันใช้การซ้ำ 1M 1.7_79: 1.6s เทียบกับ 15.2s 1.8_74: 1.8s กับ 16.0s FWIW ความยาวมาตรฐานของอาร์เรย์ ste == 23 แต่วิธีนี้ยังคงรวดเร็วโดยไม่คำนึงถึงความลึกของสแต็ก
Ryan

25

ใช้รหัสต่อไปนี้:

    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
พิมพ์ออกมา "getStackTrace" สำหรับฉัน - ฉันใช้ Java 1.5
Zack Macomber

ระวังอาร์เรย์ว่างเปล่าตามคำตอบของ Bombe และตัวบ่งชี้ javadoc JVM บางตัวอาจไม่เติมอาเรย์สแต็คแบบเต็ม?
el-teedee

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

ใช่แล้วสิ่งที่ดีที่สุด ... เปลี่ยนเป็นวิธีและรับเฟรมที่สาม ([2]) (หรืออะไรก็ตามที่เรียกว่า) ในการติดตาม
ไมค์สัตว์ฟันแทะ

14

นี่คือการขยายคำตอบของ virgo47 (ด้านบน)

มันมีวิธีการแบบคงที่บางอย่างที่จะได้รับในปัจจุบันและเรียกชื่อคลาส / วิธีการ

/* 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
การใช้ร่วมกับคำตอบของ @ mklemenz เป็นวิธีที่รวดเร็วและสะอาดในการเข้าถึงข้อมูลสแต็ก
Octavia Togami

12

ในการรับชื่อของเมธอดที่เรียกว่าเมธอดปัจจุบันคุณสามารถใช้:

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

สิ่งนี้ใช้ได้กับ MacBook และโทรศัพท์ Android ของฉัน

ฉันก็ลอง:

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

แต่ Android จะคืนค่า "getStackTrace" ฉันสามารถแก้ไขได้สำหรับ Android ด้วย

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

แต่ฉันจะได้คำตอบที่ผิดบน MacBook


ในการทดสอบล่าสุดบน Android มันทำงานได้ดีสำหรับผมที่จะใช้มากกว่าgetStackTrace()[0] getStackTrace()[1]YMMV
mbm29414

ค่าสำหรับ android คือ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();
}

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]; ทำงาน; e.getClassName();ส่งคืนชื่อคลาสแบบเต็มและe.getMethodName()ส่งคืนชื่อเม็ต
เครื่องหมาย

1
getStackTrace()[2]มันเป็นสิ่งที่ผิดgetStackTrace()[3]เพราะ: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] ฟังก์ชัน a () เรียกสิ่งนี้
PhilLab

11

สิ่งนี้สามารถทำได้โดยใช้ 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ถูกออกแบบมาให้ขี้เกียจดังนั้นจึงน่าจะมีประสิทธิภาพมากกว่าพูดThread.getStackTraceซึ่งสร้างอาเรย์สำหรับโทรสแต็คทั้งหมดอย่างกระตือรือร้น โปรดดู JEP สำหรับข้อมูลเพิ่มเติม


5

อีกวิธีหนึ่งคือการสร้าง แต่ไม่โยนข้อยกเว้นและใช้วัตถุนั้นเพื่อรับข้อมูลการติดตามสแต็กเนื่องจากวิธีการปิดล้อมจะโดยทั่วไปจะอยู่ที่ดัชนี 0 - ตราบใดที่ JVM เก็บข้อมูลนั้นไว้ ดังกล่าวข้างต้น อย่างไรก็ตามนี่ไม่ใช่วิธีที่ถูกที่สุด

จากThrowable.getStackTrace () (เหมือนกันตั้งแต่ Java 5 เป็นอย่างน้อย):

องค์ประกอบศูนย์ของอาร์เรย์ (สมมติว่าความยาวของอาร์เรย์ไม่เป็นศูนย์) หมายถึงส่วนบนสุดของสแต็กซึ่งเป็นการเรียกใช้วิธีสุดท้ายในลำดับ โดยทั่วไปนี่คือจุดที่สร้างและโยนได้นี้

ตัวอย่างด้านล่างถือว่าคลาสนั้นไม่ใช่แบบคงที่ (เพราะ getClass ()) แต่นั่นคือสิ่งที่กัน

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
ดูคำตอบของ mvanle virgo47 ด้านบนและความคิดเห็นของ thorbjorn-ravn-andersen การทำซ้ำรหัสไม่ถูกต้องและไม่น่าเชื่อถือ
alexsmail

@ ShivaKomuravelly ใช่ แต่ไม่ใช่ในสถานการณ์ใด ๆ ที่ดูเหมือนดังนั้น -1 จากฉันเช่นกัน
Maarten Bodewes

3

ฉันมีวิธีแก้ปัญหาการใช้สิ่งนี้ (ใน 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

ฉันไม่รู้ว่าเจตนาที่จะได้รับชื่อของวิธีการที่ดำเนินการอยู่ในปัจจุบันคืออะไร แต่ถ้านั่นเป็นเพียงจุดประสงค์ในการดีบั๊กการบันทึกเฟรมเวิร์กเช่น "logback" สามารถช่วยได้ที่นี่ ยกตัวอย่างเช่นใน logback ทั้งหมดที่คุณต้องทำคือการใช้รูปแบบ "M%" ในการกำหนดค่าการเข้าสู่ระบบของคุณ อย่างไรก็ตามควรใช้ด้วยความระมัดระวังเนื่องจากอาจทำให้ประสิทธิภาพลดลง


2

ในกรณีที่วิธีที่ชื่อที่คุณต้องการทราบนั้นเป็นวิธีทดสอบ junit จากนั้นคุณสามารถใช้กฎ Junit TestName: https://stackoverflow.com/a/1426730/3076107


1
@AndreiKonstantinov ฉันไม่คิดว่านี่เป็นลิงก์เท่านั้น แม้ว่าคุณจะลบลิงก์ออกไป แต่ก็ยังมีข้อมูลบางอย่างที่ต้องดำเนินการ
EJoshuaS - คืนสถานะโมนิก้า

1

คำตอบส่วนใหญ่ที่นี่ดูเหมือนผิด

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

ตัวอย่าง:

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

ขาออก:

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

ขอบคุณสำหรับคำตอบที่มีประโยชน์ของคุณ
AmerllicA

คุณช่วยอธิบายได้ไหมว่าทำไมคำตอบส่วนใหญ่จึงดูผิดสำหรับคุณ มีคำตอบมากมายและฉันไม่เก่งใน Java ที่จะอ่านทั้งหมดและเข้าใจว่าอะไรคือความแตกต่างระหว่างพวกเขาและคำตอบของคุณ :(
Xobotun

@mmm ขออภัย แต่ฉันไม่เห็นด้วยอย่างยิ่ง ฉันมาที่นี่เพื่อเรียนรู้และทำสิ่งอื่น ๆ อีกมากมายฉันเชื่อ ฉันแค่ไม่เข้าใจว่าทำไมคุณคิดว่าฉันไม่สมควรที่จะรู้เพิ่มเติมเกี่ยวกับเรื่องนี้ ฉันต้องการที่จะทำผิดพลาดน้อยในรหัสของฉันและเตือนผู้อื่นไม่ปฏิบัติตามสินค้าบางอย่าง อย่างน้อยคุณสามารถอธิบายได้อย่างชัดเจนว่าควรแก้ไขโค้ด Java เวอร์ชันใด :( คำตอบด้านล่างบอกว่ามีการเปลี่ยนแปลงใน stacktrace ระหว่าง 1.5 และ 1.6 บางทีคุณอาจบอกเป็นนัย ๆ ว่าใน Java 14 ที่กำลังจะมาถึงฉันจะรู้ได้อย่างไรหรือผู้ขายรายอื่นอาจมีขออภัยด้วยถ้าฉันตีความคำตอบของคุณอย่างสุภาพ หนึ่ง
Xobotun

0

ฉันเขียนคำตอบของ 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
โปรดแก้ไขด้วยข้อมูลเพิ่มเติม รหัสเท่านั้นและคำตอบ "ลองนี้" จะหมดกำลังใจเพราะพวกเขาไม่มีเนื้อหาที่ค้นหาได้และไม่อธิบายว่าทำไมคนควร "ลองนี้"
abarisone

1
แม้ว่ารหัสนี้อาจช่วยในการแก้ปัญหา แต่ก็ไม่ได้อธิบายว่าทำไมและ / หรือวิธีการตอบคำถาม การให้บริบทเพิ่มเติมนี้จะช่วยเพิ่มมูลค่าทางการศึกษาในระยะยาวอย่างมีนัยสำคัญ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายรวมถึงข้อ จำกัด และข้อสมมติฐานที่ใช้
Toby Speight

1
เฉพาะ Java 7 ขึ้นไป แต่มีวิธีรัดกุมในการรับชื่อเมธอด ยังคงมีข้อควรพิจารณาเกี่ยวกับประสิทธิภาพของการโทรดังกล่าว
Benj

6
getEnclosingMethod()โยนNullPointerExceptionสำหรับฉันใน Java 7
Markus L

2
java.lang.Class.getEnclosingMethod () ส่งคืนวัตถุเมธอดที่แสดงถึงวิธีการปิดล้อมทันทีของคลาสพื้นฐานหากวัตถุคลาสนี้แสดงถึงคลาสโลคัลหรือไม่ระบุชื่อภายในเมธอดมิฉะนั้นจะส่งคืน null
เตา

-5

มีอะไรผิดปกติกับวิธีนี้:

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

และก่อนที่คนจะคลั่งไคล้การใช้งาน System.out.println(...)คุณสามารถทำได้ตลอดเวลาและควรสร้างวิธีการบางอย่างเพื่อให้สามารถเปลี่ยนเส้นทางผลลัพธ์เช่น:

    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 มันดูเหมือนว่าฉันจริง ๆ แล้วมันเป็นความพยายามที่จะตอบคำถาม ไม่ใช่ความพยายามที่ยิ่งใหญ่ แต่เป็นความพยายามที่น้อยกว่า
ivarni

@ivarni "ไม่ใช่ความพยายามที่ดี"? มีอะไรผิดปกติกับมัน? คุณคุ้นเคยกับ "หลักการจูบ" หรือไม่?
johnny

@ Saksham มันเป็นโวหาร
johnny

5
@ Johnny ใน codebase ที่ฉันมีต่อหน้าฉันตอนนี้มี 271 คลาส แม้จะมี (ประมาณต่ำ) og 5 วิธีต่อคลาสที่มากกว่า 1300 วิธี และนี่ไม่ใช่แม้แต่ฐานข้อมูลขนาดใหญ่ คุณไม่เห็นปัญหาในการขยายแนวทางของคุณใช่ไหม ฉันมีความสุขมากที่เห็นด้วยที่จะไม่เห็นด้วย แต่นั่นเป็นเหตุผลที่ฉันบอกว่ามันไม่ได้เป็นความพยายามที่ดี มันแนะนำค่าใช้จ่ายจำนวนมากใน codebase ใด ๆ ที่ไม่สำคัญ
ivarni

1
@ จอห์นนี่ฉันเดาว่าฉันเคยเห็นหลาย ๆ กรณีที่ชื่อเมธอดไม่ตรงกับสตริงที่ส่งฉันไปผิดทิศทางเมื่อทำการดีบั๊ก แต่ใน Java ฉันยังคิดว่าข้อเสนอแนะของคุณดีที่สุดตัวเลือกอื่น ๆ "ราคา" มากเกินไป
อื่นอีก
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.