Java 9 ने java.lang.StackWalker पेश किया - स्टैक ट्रेस तक पहुंच के लिए एक कुशल, आलसी (lazy) API। Option.SHOW_REFLECT_FRAMES विकल्प रिफ्लेक्शन के माध्यम से आह्वान किए गए मेथड्स के स्टैक फ्रेम्स को शामिल करने की अनुमति देता है, जो डिबगिंग के लिए उपयोगी है।
StackWalker अवलोकन
| विकल्प | विवरण |
RETAIN_CLASS_REFERENCE | StackFrame.getDeclaringClass() सक्षम करता है |
SHOW_REFLECT_FRAMES | रिफ्लेक्शन फ्रेम्स दिखाएं (Method.invoke, आदि) |
SHOW_HIDDEN_FRAMES | छिपे हुए फ्रेम्स दिखाएं (लैम्ब्डा, प्रॉक्सी, आदि) |
SHOW_REFLECT_FRAMES उदाहरण
import java.lang.StackWalker;
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
public class ReflectionFrameDemo {
public static void main(String[] args)
throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
// रिफ्लेक्शन के माध्यम से मेथड आह्वान करें
Method test1Method = Test1.class.getDeclaredMethod("test1");
test1Method.invoke(null);
}
}
class Test1 {
protected static void test1() {
Test2.test2();
}
}
class Test2 {
protected static void test2() {
// SHOW_REFLECT_FRAMES के साथ स्टैक वॉकर प्राप्त करें
List stack = StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES)
.walk(s -> s.collect(Collectors.toList()));
for (StackFrame frame : stack) {
System.out.printf("%-40s %4d %s%n",
frame.getClassName(),
frame.getLineNumber(),
frame.getMethodName());
}
}
}
आउटपुट
Test2 22 test2
Test1 16 test1
jdk.internal.reflect.NativeMethodAccessorImpl -2 invoke0
jdk.internal.reflect.NativeMethodAccessorImpl 62 invoke
jdk.internal.reflect.DelegatingMethodAccessorImpl 43 invoke
java.lang.reflect.Method 564 invoke
ReflectionFrameDemo 11 main
विकल्प के बिना तुलना
// SHOW_REFLECT_FRAMES के बिना (डिफ़ॉल्ट)
List stack = StackWalker.getInstance()
.walk(s -> s.collect(Collectors.toList()));
Test2 22 test2
Test1 16 test1
ReflectionFrameDemo 11 main
// रिफ्लेक्शन फ्रेम्स छुपे हुए!
StackFrame API
| मेथड | वापसी प्रकार | विवरण |
getClassName() | String | घोषक कक्षा नाम |
getMethodName() | String | मेथड नाम |
getFileName() | String | स्रोत फ़ाइल नाम |
getLineNumber() | int | लाइन नंबर (-1 यदि अनुपलब्ध) |
getDeclaringClass() | Class<?> | कक्षा ऑब्जेक्ट (RETAIN_CLASS_REFERENCE आवश्यक) |
getMethodType() | MethodType | मेथड टाइप (RETAIN_CLASS_REFERENCE आवश्यक) |
isNativeMethod() | boolean | नेटिव मेथड है? |
toString() | String | फॉर्मेटेड स्ट्रिंग |
उन्नत उपयोग: कस्टम स्ट्रीम प्रोसेसिंग
public class AdvancedStackWalker {
public static void main(String[] args) {
// 1. केवल एप्लिकेशन फ्रेम्स (JDK/लाइब्रेरी फ़िल्टर करें)
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s
.filter(f -> f.getClassName().startsWith("com.myapp"))
.forEach(f -> System.out.println(f)));
// 2. पहला गैर-JDK फ्रेम ढूंढें
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s
.filter(f -> !f.getClassName().startsWith("java.")
&& !f.getClassName().startsWith("jdk."))
.findFirst()
.ifPresent(f -> System.out.println("पहला ऐप फ्रेम: " + f)));
// 3. कक्षा रेफरेंस के साथ (रिफ्लेक्शन के लिए)
StackWalker walker = StackWalker.getInstance(
Option.RETAIN_CLASS_REFERENCE, Option.SHOW_REFLECT_FRAMES);
walker.walk(s -> s
.filter(f -> f.getDeclaringClass() != null)
.forEach(f -> {
System.out.println("कक्षा: " + f.getDeclaringClass().getName());
System.out.println("मेथड: " + f.getMethodName());
}));
}
}
पारंपरिक API के साथ तुलना
| API | लेज़ी? | फ़िल्टरिंग | कक्षा रेफरेंस | रिफ्लेक्शन फ्रेम्स |
Thread.getStackTrace() | नहीं (ईगर) | मैन्युअल | नहीं | नहीं |
Throwable.getStackTrace() | नहीं | मैन्युअल | नहीं | नहीं |
StackWalker | हां | स्ट्रीम API | वैकल्पिक | वैकल्पिक |
व्यावहारिक उपयोग केस
1. लॉगिंग फ्रेमवर्क एकीकरण
public class LogUtil {
private static final StackWalker WALKER = StackWalker.getInstance(
Option.RETAIN_CLASS_REFERENCE);
public static String getCallerClassName() {
return WALKER.walk(s -> s
.skip(1) // getCallerClassName को छोड़ें
.filter(f -> !f.getClassName().startsWith("com.myapp.logging"))
.map(StackFrame::getClassName)
.findFirst()
.orElse("Unknown"));
}
}
2. प्रदर्शन प्रोफाइलिंग
public class Profiler {
private static final StackWalker WALKER = StackWalker.getInstance();
public static void profile(Runnable task) {
long start = System.nanoTime();
task.run();
long elapsed = System.nanoTime() - start;
WALKER.walk(s -> s
.limit(10)
.forEach(f -> System.out.printf("%s.%s:%d%n",
f.getClassName(), f.getMethodName(), f.getLineNumber())));
System.out.println("समय: " + elapsed/1_000_000 + "ms");
}
}
3. सुरक्षा ऑडिटिंग
public class SecurityAudit {
public static void checkCallerPermission(String permission) {
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s
.skip(1)
.findFirst()
.ifPresent(frame -> {
Class> caller = frame.getDeclaringClass();
// कॉलर की अनुमतियां जांचें
System.out.println("कॉलर: " + caller.getName() +
" मेथड: " + frame.getMethodName() +
" अनुमति मांग रहा: " + permission);
}));
}
}
सर्वोत्तम अभ्यास
- इंस्टेंस पुनः उपयोग करें:
StackWalker.getInstance() कैश्ड इंस्टेंस लौटाता है
- लेज़ी मूल्यांकन:
walk() केवल आवश्यक फ्रेम्स प्रोसेस करता है
- विकल्प संयोजित करें:
getInstance(Option.RETAIN_CLASS_REFERENCE, Option.SHOW_REFLECT_FRAMES)
- गहरे स्टैक से बचें:
limit(), skip(), dropWhile() का उपयोग करें
- प्रदर्शन: पारंपरिक API से तेज़ जब केवल कुछ फ्रेम्स की आवश्यकता हो
सारांश
StackWalker Java 9+ में स्टैक इंस्पेक्शन के लिए आधुनिक API है
Option.SHOW_REFLECT_FRAMES रिफ्लेक्शन फ्रेम्स (Method.invoke, आदि) को उजागर करता है
- स्ट्रीम-आधारित प्रोसेसिंग शक्तिशाली फ़िल्टरिंग/परिवर्तन सक्षम करती है
RETAIN_CLASS_REFERENCE कक्षा/मेथड रिफ्लेक्शन के लिए Class ऑब्जेक्ट्स सक्षम करता है
- Thread.getStackTrace() और Throwable.getStackTrace() से अधिक कुशल