Java 平台蘊藏著許多鮮為人知但極其實用的工具類,如同廚房抽屜裡的「小線頭」,關鍵時刻能解決大問題。本文介紹 StAX、ServiceLoader、Scanner、Timer、JavaSound 五大隱藏寶石。
SAX 太底層、DOM 太佔記憶體,StAX(Streaming API for XML)提供「拉取式」解析:將文檔建模為可逐個提取的節點流,一次處理一個,用完即丟棄。JDK 內建於 javax.xml.stream。
XMLEventReader reader = XMLInputFactory.newInstance()
.createXMLEventReader(new FileReader("build.xml"));
while (reader.hasNext()) {
XMLEvent evt = reader.nextEvent();
if (evt.getEventType() == XMLEvent.START_ELEMENT) {
StartElement se = evt.asStartElement();
if ("target".equals(se.getName().getLocalPart())) {
System.out.println(se.getAttributeByName(new QName("name")).getValue());
}
}
}
適用場景:大型 XML、無需完整樹結構、記憶體敏感環境。另提供 XMLStreamReader 低階 API 及 XMLEventWriter/XMLStreamWriter 輸出支援。
標準化的「介面與實現分離」方案,輕於 Spring。讀取 JAR 中 META-INF/services/全限定介面名 文件,自動發現並實例化實現類。
IPersonalServant 含 can(String)、process(File)Jeeves implements IPersonalServantMETA-INF/services/IPersonalServant 內容為 JeevesAnt 1.7+ <service> 標籤可自動生成服務文件。ServiceLoader.load(介面.class) 返回可迭代的實現列表,支援動態擴展。
介於 String.split() 過弱與完整解析器框架過重之間。支援按分隔符、正則、類型安全讀取(nextInt()、nextDouble() 等)。
Scanner scanner = new Scanner(commandFile);
while (scanner.hasNext()) {
String verb = scanner.next();
if ("fetch".equals(verb)) {
int num = scanner.nextInt();
String type = scanner.next();
fetch(num, type);
} else if ("attach".equals(verb)) { ... }
}
適合 CSV、日誌、簡易 DSL、配置文件解析,API 簡潔直觀。
java.util.Timer + TimerTask 提供一次性/週期性延遲執行,比手寫 Thread 簡單,比 ScheduledExecutorService 輕量。
Timer t = new Timer("TimerThread");
t.schedule(new TimerTask() {
public void run() { System.out.println("This is later"); }
}, 1000); // 1秒後執行
注意:預設建立非守護線程,長期運行程式建議用 new Timer(true) 建立守護線程,避免阻止 JVM 退出。
javax.sound.* 支援 MIDI 與音頻(WAV 等)。播放片段核心流程:
AudioSystem.getAudioInputStream() 獲取音頻流AudioSystem.getLine() 獲取 ClipLineListener 處理 STOP 事件(修復 JDK 5 短片段無聲 Bug)clip.open() → clip.start() → clip.drain() → clip.close()適用場景:監控告警聲、桌面應用交互反饋、測試輔助提示。服務端慎用。
這五個工具類無需額外依賴,即開即用。下次遇到 XML 處理、模組發現、文本解析、定時任務、聲音播放需求時,先看看 JDK 自帶能否解決,往往事半功倍。