Java 9 का StackWalker स्टैक फ्रेम्स पर शक्तिशाली स्ट्रीम-आधारित फ़िल्टरिंग प्रदान करता है, जिसमें skip(n) और dropWhile(predicate) शामिल हैं जो अप्रासंगिक फ्रेम्स (जैसे लॉगिंग/फ्रेमवर्क कोड) को बायपास करते हैं।
स्ट्रीम ऑपरेशंस के साथ फ़िल्टरिंग
import java.lang.StackWalker;
import java.lang.StackWalker.StackFrame;
import java.util.List;
import java.util.stream.Collectors;
public class StackWalkerSkipDemo {
public static void main(String[] args) {
new StackWalkerSkipDemo().stackWalk();
}
private void stackWalk() {
new StackWalker1().stackWalk1();
}
private class StackWalker1 {
public void stackWalk1() { new StackWalker2().stackWalk2(); }
}
private class StackWalker2 {
public void stackWalk2() { new StackWalker3().stackWalk3(); }
}
private class StackWalker3 {
public void stackWalk3() { new StackWalker4().stackWalk4(); }
}
private class StackWalker4 {
public void stackWalk4() {
// RETAIN_CLASS_REFERENCE के साथ वॉकर प्राप्त करें
List framesAfterSkip = StackWalker.getInstance(
StackWalker.Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s.skip(2).collect(Collectors.toList()));
System.out.println("2 फ्रेम्स छोड़ने के बाद:");
framesAfterSkip.forEach(System.out::println);
}
}
}
आउटपुट
2 फ्रेम्स छोड़ने के बाद: StackWalkerSkipDemo$StackWalker2.stackWalk2(StackWalkerSkipDemo.java:29) StackWalkerSkipDemo$StackWalker1.stackWalk1(StackWalkerSkipDemo.java:24) StackWalkerSkipDemo.stackWalk(StackWalkerSkipDemo.java:19) StackWalkerSkipDemo.main(StackWalkerSkipDemo.java:9)
skip() बनाम dropWhile() बनाम filter()
| ऑपरेशन | व्यवहार | उपयोग केस |
|---|---|---|
skip(n) | पहले n फ्रेम्स छोड़ें | ज्ञात फ्रेमवर्क/लॉगिंग लेयर्स |
dropWhile(pred) | शर्त सत्य रहने तक छोड़ें | डायनामिक फ़िल्टरिंग (पैकेज प्रीफिक्स तक) |
filter(pred) | शर्त से मेल खाने वाले रखें | समावेशी फ़िल्टरिंग |
limit(n) | अधिकतम n फ्रेम्स लें | ट्रंकेट गहरे स्टैक |
व्यावहारिक पैटर्न
1. ज्ञात फ्रेमवर्क फ्रेम्स छोड़ें
// पहले 3 फ्रेम्स छोड़ें (लॉगिंग, AOP, फ्रेमवर्क)
StackWalker.getInstance().walk(s -> s.skip(3).forEach(System.out::println));
2. पैकेज प्रीफिक्स द्वारा ड्रॉप करें
// JDK/लाइब्रेरी फ्रेम्स छोड़ें, पहले ऐप फ्रेम से शुरू करें
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s
.dropWhile(f -> f.getClassName().startsWith("java.")
|| f.getClassName().startsWith("jdk.")
|| f.getClassName().startsWith("org.springframework.")
|| f.getClassName().startsWith("org.apache.logging."))
.forEach(f -> System.out.println(f.getClassName() + "." + f.getMethodName())));
3. पहला ऐप्लिकेशन फ्रेम ढूंढें
public static StackFrame findCaller(Class> loggerClass) {
return StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s
.dropWhile(f -> f.getDeclaringClass() == loggerClass
|| f.getClassName().startsWith("java.util.logging"))
.findFirst()
.orElse(null));
}
4. लॉगिंग के लिए कस्टम फ़िल्टर
public class LogStackWalker {
private static final StackWalker WALKER = StackWalker.getInstance(
Option.RETAIN_CLASS_REFERENCE);
private static final Set EXCLUDED_PREFIXES = Set.of(
"java.", "jdk.", "sun.", "org.apache.logging.",
"org.slf4j.", "ch.qos.logback.", "com.myapp.logging");
public static StackFrame getCallerFrame() {
return WALKER.walk(s -> s
.dropWhile(f -> EXCLUDED_PREFIXES.stream()
.anyMatch(prefix -> f.getClassName().startsWith(prefix)))
.findFirst()
.orElse(null));
}
public static String getCallerInfo() {
StackFrame frame = getCallerFrame();
if (frame == null) return "Unknown";
return String.format("%s.%s:%d",
frame.getClassName(), frame.getMethodName(), frame.getLineNumber());
}
}
पूर्ण उदाहरण: कई फ़िल्टर
import java.lang.StackWalker.*;
import java.util.*;
public class ComprehensiveStackFilter {
public static void main(String[] args) {
demoSkip();
demoDropWhile();
demoFilter();
demoCombined();
}
static void demoSkip() {
System.out.println("=== skip(2) ===");
walkAndPrint(s -> s.skip(2));
}
static void demoDropWhile() {
System.out.println("\n=== dropWhile (java/jdk छोड़ें) ===");
walkAndPrint(s -> s.dropWhile(f ->
f.getClassName().startsWith("java.") ||
f.getClassName().startsWith("jdk.")));
}
static void demoFilter() {
System.out.println("\n=== filter (केवल com.example) ===");
walkAndPrint(s -> s.filter(f ->
f.getClassName().startsWith("com.example.")));
}
static void demoCombined() {
System.out.println("\n=== संयुक्त: dropWhile + limit(5) ===");
walkAndPrint(s -> s
.dropWhile(f -> f.getClassName().startsWith("java.")
|| f.getClassName().startsWith("jdk."))
.limit(5));
}
static void walkAndPrint(java.util.function.Function<
Stream, Stream> processor) {
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(s -> processor.apply(s).collect(Collectors.toList()))
.forEach(f -> System.out.printf(" %s.%s:%d%n",
f.getClassName(), f.getMethodName(), f.getLineNumber()));
}
// कॉल स्टैक उत्पन्न करने के लिए नेस्टेड कॉल्स
static { a(); }
static void a() { b(); }
static void b() { c(); }
static void c() { d(); }
static void d() { e(); }
static void e() { f(); }
static void f() { g(); }
static void g() { /* स्टैक यहाँ कैप्चर किया गया */ }
}
प्रदर्शन लाभ
- लेज़ी मूल्यांकन: स्टैक फ्रेम्स केवल मांग पर कैप्चर किए जाते हैं
skip(100)केवल 100 फ्रेम्स चलता है, पूरे स्टैक को नहींThread.getStackTrace()हमेशा पूर्ण सरणी आवंटित करता हैlimit(10)के साथStackWalkerकेवल 10 फ्रेम्स कैप्चर करता है
सामान्य पैटर्न
// पैटर्न 1: लॉगिंग फ्रेमवर्क के लिए कॉलर ढूंढें
StackFrame caller = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s
.dropWhile(f -> isLoggingFramework(f.getClassName()))
.findFirst()
.orElse(null));
// पैटर्न 2: शीर्ष N ऐप्लिकेशन फ्रेम्स प्राप्त करें
List topFrames = StackWalker.getInstance()
.walk(s -> s
.dropWhile(f -> isSystemFrame(f.getClassName()))
.limit(10)
.collect(Collectors.toList()));
// पैटर्न 3: रिफ्लेक्शन फ्रेम्स के साथ (डिबगिंग)
List withReflection = StackWalker.getInstance(
Option.SHOW_REFLECT_FRAMES, Option.RETAIN_CLASS_REFERENCE)
.walk(s -> s.collect(Collectors.toList()));
सारांश
skip(n)- निश्चित संख्या में फ्रेम्स छोड़ेंdropWhile(pred)- शर्त सत्य रहने तक छोड़ें (डायनामिक)filter(pred)- मेल खाने वाले फ्रेम्स रखेंlimit(n)- परिणामों को काटें- पारंपरिक
Thread.getStackTrace()की तुलना में अधिक कुशल - जटिल फ़िल्टरिंग के लिए स्ट्रीम ऑपरेशंस संयोजित करें