工作中積累的「小而美」技巧,往往能瞬間解決棘手問題。本文持續更新,記錄集合統一遍歷、反射操作數組、Properties 批量加載、Ant 路徑通配符等高頻實用技巧。
<c:forEach> 統一遍歷 Map、List、Array、SetJSTL 核心標簽庫 `
<%-- 1. List/Set/Array --%>
<c:forEach var="item" items="${listOrArray}">
${item} <br/>
</c:forEach>
<%-- 2. Map (varStatus 可獲取索引) --%>
<c:forEach var="entry" items="${map}" varStatus="status">
Key: ${entry.key}, Value: ${entry.value}, Index: ${status.index} <br/>
</c:forEach>
<%-- 3. 固定次數循環 --%>
<c:forEach var="i" begin="1" end="10" step="2">
${i} <br/>
</c:forEach>
注意:Map 遍歷時 `${entry}` 是 `Map.Entry` 對象,用 `${entry.key}` / `${entry.value}` 取值。
場景:方法參數為 `Object`,實際可能是 `String[]`、`int[]`、`Object[]`、`List` 轉數組等。使用 `java.lang.reflect.Array` 統一獲取長度、讀取元素、設置元素,**完全屏蔽基本類型/引用類型數組差異**。
import java.lang.reflect.Array;
public static void processArray(Object arrayObj) {
// 1. 校驗是否為數組
if (arrayObj == null || !arrayObj.getClass().isArray()) {
throw new IllegalArgumentException("參數必須是數組");
}
// 2. 獲取長度 (統一 API)
int length = Array.getLength(arrayObj);
System.out.println("數組長度: " + length);
// 3. 遍歷讀取元素 (統一返回 Object,基本類型自動裝箱)
for (int i = 0; i < length; i++) {
Object element = Array.get(arrayObj, i);
System.out.println("Index " + i + ": " + element);
}
// 4. 設置元素 (需類型匹配,否則 ArrayStoreException)
// Array.set(arrayObj, 0, "newValue");
}
// 測試
String[] strs = {"a", "b"};
int[] nums = {1, 2, 3};
processArray(strs); // 正常
processArray(nums); // 正常,自動裝箱為 Integer
processArray(new ArrayList<>()); // 拋異常
核心 API:Array.getLength(Object)、Array.get(Object, int)、Array.set(Object, int, Object)、Array.newInstance(Class, int) (動態創建數組)。
PropertiesLoaderUtils.loadAllProperties() 批量加載屬性文件場景:項目中有多個 `*.properties` 文件 (如 `config.properties`, `db.properties`, `redis.properties`),需合併加載到單一 `Properties` 對象,支持 classpath 下多文件匹配、覆蓋策略。
import org.springframework.core.io.support.PropertiesLoaderUtils;
import java.io.IOException;
import java.util.Properties;
public Properties loadAllConfigs() throws IOException {
// 加載 classpath 下所有以 config- 開頭的 .properties 文件
// 返回合併後的 Properties,後加載的覆蓋先加載的同名鍵
Properties props = PropertiesLoaderUtils.loadAllProperties("config-*.properties");
// 也可指定具體文件列表
// Properties props = PropertiesLoaderUtils.loadProperties(new ClassPathResource("db.properties"));
return props;
}
// 用法
String dbUrl = props.getProperty("jdbc.url");
優勢:自動處理資源流關閉、編碼 (默認 ISO-8859-1,建議文件存為 UTF-8 並配合 `new EncodedResource(resource, "UTF-8")`)、多文件合併邏輯。
Ant 風格路徑匹配是 Spring 生態標準,三大通配符:
| 符號 | 含義 | 匹配示例 | 不匹配示例 |
|---|---|---|---|
? | 匹配單個字符 (不含路徑分隔符) | `file?.txt` → `file1.txt` | `file12.txt`, `dir/file.txt` |
* | 匹配任意字符 (不含路徑分隔符 `/` `\`) | `*.properties` → `a.properties` | `dir/a.properties` (跨目錄) |
** | 匹配任意字符含路徑分隔符 (遞歸匹配多級目錄) | `**/mapper/*.xml` → `com/dao/UserMapper.xml` | 無 (最強通配) |
// 1. 掃描所有子包下的 Mapper XML (MyBatis mapper-locations)
classpath*:mapper/**/*.xml
classpath*:com/**/mapper/*.xml
// 2. 加載多環境配置文件 (Spring @PropertySource)
classpath:config/application-${spring.profiles.active}.properties
// 3. Logback 掃描配置變更
// 非 Ant 路徑
// 4. Spring @Value 注入文件內容
@Value("classpath:templates/email/*.ftl")
private Resource[] emailTemplates; // 注入數組
public static boolean isEmpty(Object obj) {
if (obj == null) return true;
if (obj instanceof CharSequence) return ((CharSequence) obj).length() == 0;
if (obj.getClass().isArray()) return Array.getLength(obj) == 0;
if (obj instanceof Collection) return ((Collection>) obj).isEmpty();
if (obj instanceof Map) return ((Map, ?>) obj).isEmpty();
return false; // 其他對象視為非空
}
Mapcounts = new HashMap<>(); // merge: key 存在則應用函數合併值,不存在則插入值 counts.merge("apple", 1, (oldVal, newVal) -> oldVal + newVal); // 計數器神器 // computeIfAbsent: 緩存模式 (線程安全需 ConcurrentHashMap) Map > cache = new ConcurrentHashMap<>(); List list = cache.computeIfAbsent("key", k -> new ArrayList<>()); list.add("value"); // computeIfPresent: 值存在時重新計算 counts.computeIfPresent("apple", (k, v) -> v + 1);
歡迎在評論區分享你的「壓箱底」小技巧,我將整合進後續版本。關注不迷路,下期預告:Stream 流式編程避坑指南、CompletableFuture 異步編排實戰、Arthas 線上診斷命令速查表。