欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JDK9到JDK21中值得掌握的29個(gè)實(shí)用特性分享

 更新時(shí)間:2025年05月22日 15:01:37   作者:風(fēng)象南  
Java的演進(jìn)節(jié)奏從JDK9開(kāi)始顯著加快,每半年一個(gè)新版本的發(fā)布節(jié)奏為Java帶來(lái)了大量的新特性,本文整理了29個(gè)JDK9到JDK21中值得掌握的實(shí)用特性,需要的可以了解下

Java的演進(jìn)節(jié)奏從JDK9開(kāi)始顯著加快,每半年一個(gè)新版本的發(fā)布節(jié)奏為Java帶來(lái)了大量的新特性。

其中包括令人矚目的虛擬線程、記錄類型等"明星特性",也有很多不太引人注意但同樣實(shí)用的小功能。

本文整理了29個(gè)JDK9到JDK21中值得掌握的實(shí)用特性,幫助你編寫(xiě)更簡(jiǎn)潔、高效、安全的Java代碼。

JDK 9 模塊化與API增強(qiáng)

1. 集合工廠方法:一行代碼創(chuàng)建不可變集合

在JDK9之前,創(chuàng)建小型不可變集合相當(dāng)繁瑣,現(xiàn)在只需要一行代碼:

// 舊方式
List<String> list = Collections.unmodifiableList(Arrays.asList("Java", "Kotlin", "Scala"));
Map<String, Integer> map = Collections.unmodifiableMap(new HashMap<String, Integer>() {{
    put("Java", 1995);
    put("Kotlin", 2011);
    put("Scala", 2004);
}});

// JDK9方式
List<String> list = List.of("Java", "Kotlin", "Scala");
Set<String> set = Set.of("Java", "Kotlin", "Scala");
Map<String, Integer> map = Map.of(
    "Java", 1995,
    "Kotlin", 2011,
    "Scala", 2004
);

對(duì)于更多鍵值對(duì),可以使用Map.ofEntries()

Map<String, Integer> largeMap = Map.ofEntries(
    Map.entry("Java", 1995),
    Map.entry("Kotlin", 2011),
    Map.entry("Scala", 2004),
    Map.entry("Groovy", 2003)
    // ...可以有更多entries
);

實(shí)用場(chǎng)景:常量定義、配置集合、測(cè)試數(shù)據(jù)準(zhǔn)備、API返回不可變結(jié)果。

2. 私有接口方法:接口代碼復(fù)用不再尷尬

JDK8引入了接口默認(rèn)方法,JDK9進(jìn)一步允許接口擁有私有方法,便于在接口內(nèi)部復(fù)用代碼:

public interface FileProcessor {
    // 公共抽象方法
    void process(Path path);
    
    // 默認(rèn)方法
    default void processFile(String fileName) {
        validateFileName(fileName); // 復(fù)用私有方法進(jìn)行驗(yàn)證
        process(Path.of(fileName));
        log("Processed file: " + fileName);
    }
    
    default void processDirectory(String dirName) {
        validateFileName(dirName); // 復(fù)用相同的驗(yàn)證邏輯
        try (Stream<Path> paths = Files.list(Path.of(dirName))) {
            paths.forEach(this::process);
        } catch (IOException e) {
            handleException(e); // 復(fù)用私有方法處理異常
        }
        log("Processed directory: " + dirName);
    }
    
    // 私有方法 - 供默認(rèn)方法使用
    private void validateFileName(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            throw new IllegalArgumentException("File name cannot be empty");
        }
    }
    
    // 私有靜態(tài)方法
    private static void log(String message) {
        System.out.println("[" + LocalDateTime.now() + "] " + message);
    }
    
    private void handleException(Exception e) {
        log("Error: " + e.getMessage());
    }
}

實(shí)用場(chǎng)景:API設(shè)計(jì)、接口默認(rèn)方法邏輯復(fù)用、框架開(kāi)發(fā)。

3. Stream API增強(qiáng):流操作更靈活

JDK9為Stream API增加了幾個(gè)實(shí)用方法:

// 1. takeWhile - 從頭開(kāi)始獲取元素,直到條件不滿足
Stream.of(2, 4, 6, 8, 9, 10, 12)
      .takeWhile(n -> n % 2 == 0) // 結(jié)果: [2, 4, 6, 8]
      .forEach(System.out::println);

// 2. dropWhile - 從頭開(kāi)始丟棄元素,直到條件不滿足
Stream.of(2, 4, 6, 8, 9, 10, 12)
      .dropWhile(n -> n % 2 == 0) // 結(jié)果: [9, 10, 12]
      .forEach(System.out::println);

// 3. ofNullable - 安全創(chuàng)建單元素流,處理null值
Stream.ofNullable(null).count(); // 0
Stream.ofNullable("Java").count(); // 1

// 4. iterate方法重載 - 帶終止條件的迭代
// 舊方式需要使用limit或filter來(lái)限制
Stream.iterate(1, n -> n * 2)
      .limit(5)
      .forEach(System.out::println);

// 新方式更直接
Stream.iterate(1, n -> n < 100, n -> n * 2)
      .forEach(System.out::println); // 1, 2, 4, 8, 16, 32, 64

實(shí)用場(chǎng)景:數(shù)據(jù)處理管道、復(fù)雜條件過(guò)濾、有界數(shù)據(jù)生成。

4. InputStream.transferTo():流復(fù)制不再繁瑣

在JDK9之前,在流之間復(fù)制數(shù)據(jù)需要手動(dòng)處理緩沖區(qū),現(xiàn)在只需要一行代碼:

// 舊方式 - 冗長(zhǎng)且易錯(cuò)
try (InputStream is = new FileInputStream("source.txt");
     OutputStream os = new FileOutputStream("target.txt")) {
    byte[] buffer = new byte[8192];
    int length;
    while ((length = is.read(buffer)) > 0) {
        os.write(buffer, 0, length);
    }
}

// JDK9方式 - 簡(jiǎn)潔明了
try (InputStream is = new FileInputStream("source.txt");
     OutputStream os = new FileOutputStream("target.txt")) {
    is.transferTo(os); // 一行代碼搞定
}

實(shí)用場(chǎng)景:文件復(fù)制、網(wǎng)絡(luò)數(shù)據(jù)傳輸、流處理。

5. 改進(jìn)的Process API:管理系統(tǒng)進(jìn)程更容易

JDK9大幅增強(qiáng)了Process API,讓Java程序與系統(tǒng)進(jìn)程的交互更加強(qiáng)大:

// 獲取當(dāng)前進(jìn)程
ProcessHandle current = ProcessHandle.current();
System.out.println("Current PID: " + current.pid());

// 獲取進(jìn)程信息
current.info().user().ifPresent(user -> System.out.println("User: " + user));
current.info().commandLine().ifPresent(cmd -> System.out.println("Command: " + cmd));
current.info().startInstant().ifPresent(start -> System.out.println("Start time: " + start));
current.info().totalCpuDuration().ifPresent(cpu -> System.out.println("CPU time: " + cpu));

// 列出所有子進(jìn)程
current.children().forEach(child -> System.out.println("Child PID: " + child.pid()));

// 列出所有進(jìn)程
ProcessHandle.allProcesses()
    .filter(ph -> ph.info().command().isPresent())
    .forEach(ph -> System.out.println(ph.pid() + ": " + ph.info().command().get()));

// 啟動(dòng)并等待進(jìn)程完成
ProcessBuilder pb = new ProcessBuilder("ls", "-l");
Process process = pb.start();
ProcessHandle handle = process.toHandle();
boolean terminated = handle.onExit().thenAccept(p -> 
    System.out.println("Process " + p.pid() + " terminated")
).isDone();

實(shí)用場(chǎng)景:系統(tǒng)管理工具、守護(hù)進(jìn)程、執(zhí)行外部命令、監(jiān)控應(yīng)用。

JDK 10 局部變量推斷

6. 局部變量類型推斷(var):告別冗長(zhǎng)的變量聲明

JDK10引入了局部變量類型推斷,使用var關(guān)鍵字讓編譯器推斷變量類型:

// 舊方式 - 類型重復(fù)且冗長(zhǎng)
HashMap<String, List<Customer>> customersByCity = new HashMap<>();
BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
URLConnection connection = new URL("https://example.com").openConnection();

// JDK10方式 - 簡(jiǎn)潔明了
var customersByCity = new HashMap<String, List<Customer>>();
var reader = new BufferedReader(new FileReader("data.txt"));
var connection = new URL("https://example.com").openConnection();

// 在for循環(huán)中特別有用
for (var entry : customersByCity.entrySet()) {
    var city = entry.getKey();
    var customers = entry.getValue();
    // ...
}

注意事項(xiàng)

  • var只能用于局部變量,不能用于字段、方法參數(shù)或返回類型
  • 聲明時(shí)必須初始化變量
  • 不要過(guò)度使用,當(dāng)類型不明顯時(shí)應(yīng)該明確聲明類型

最佳實(shí)踐

// 好的用法 - 類型明確
var customers = new ArrayList<Customer>();
var entry = Map.entry("key", "value");

// 避免的用法 - 類型不明確
var result = getResult(); // 返回類型不明顯
var x = 1; // 基本類型推薦顯式聲明

實(shí)用場(chǎng)景:復(fù)雜泛型類型、匿名類、lambda表達(dá)式中的變量。

7. 不可修改集合的復(fù)制方法:集合轉(zhuǎn)換更安全

JDK10為集合框架增加了copyOf方法,創(chuàng)建不可修改的集合副本:

// 原始集合
List<String> original = new ArrayList<>(List.of("Java", "Kotlin", "Scala"));
Set<Integer> originalSet = new HashSet<>(Set.of(1, 2, 3));
Map<String, Integer> originalMap = new HashMap<>(Map.of("one", 1, "two", 2));

// 創(chuàng)建不可修改的副本
List<String> copy = List.copyOf(original);
Set<Integer> copiedSet = Set.copyOf(originalSet);
Map<String, Integer> copiedMap = Map.copyOf(originalMap);

// 修改原集合不影響副本
original.add("Groovy");
System.out.println(original); // [Java, Kotlin, Scala, Groovy]
System.out.println(copy);     // [Java, Kotlin, Scala]

// 嘗試修改副本會(huì)拋出異常
try {
    copy.add("Clojure"); // 拋出 UnsupportedOperationException
} catch (UnsupportedOperationException e) {
    System.out.println("Cannot modify immutable copy");
}

Collections.unmodifiableList()不同,List.copyOf()會(huì)創(chuàng)建一個(gè)全新的集合,如果原集合已經(jīng)是不可修改的,則可能直接返回原集合而不是副本。

實(shí)用場(chǎng)景:防御性編程、返回安全的集合副本、創(chuàng)建常量集合。

JDK 11 長(zhǎng)期支持版功能增強(qiáng)

8. String新方法:文本處理得心應(yīng)手

JDK11為String類增加了幾個(gè)實(shí)用方法:

// 1. lines() - 按行分割字符串
String multiline = "Java\nKotlin\nScala";
multiline.lines()
    .map(String::toUpperCase)
    .forEach(System.out::println);

// 2. strip(), stripLeading(), stripTrailing() - 去除空白字符
String text = "  Hello World  ";
System.out.println(">" + text.strip() + "<");          // >Hello World<
System.out.println(">" + text.stripLeading() + "<");   // >Hello World  <
System.out.println(">" + text.stripTrailing() + "<");  // >  Hello World<

// strip()與trim()的區(qū)別: strip()識(shí)別更多的Unicode空白字符
String unicodeWhitespace = "\u2005Hello\u2005";
System.out.println(">" + unicodeWhitespace.trim() + "<");   // >?Hello?<
System.out.println(">" + unicodeWhitespace.strip() + "<");  // >Hello<

// 3. isBlank() - 檢查字符串是否為空白
System.out.println("  ".isBlank());     // true
System.out.println("".isBlank());       // true
System.out.println(" a ".isBlank());    // false

// 4. repeat() - 重復(fù)字符串
String star = "*";
System.out.println(star.repeat(10));    // **********
System.out.println("=".repeat(20));     // ====================

實(shí)用場(chǎng)景:處理用戶輸入、解析文本文件、構(gòu)建格式化輸出。

9. Files新方法:文件讀寫(xiě)一步到位

JDK11為Files類添加了幾個(gè)便捷方法:

// 讀取文件為String
String content = Files.readString(Path.of("config.json"));

// 寫(xiě)入String到文件
Files.writeString(Path.of("output.txt"), "Hello Java 11!");

// 使用指定編碼
String content = Files.readString(Path.of("data.txt"), StandardCharsets.UTF_8);
Files.writeString(Path.of("log.txt"), "Logged at: " + LocalDateTime.now(), 
                 StandardCharsets.UTF_8);

// 寫(xiě)入字符串集合
List<String> lines = List.of("Line 1", "Line 2", "Line 3");
Files.write(Path.of("lines.txt"), lines);

實(shí)用場(chǎng)景:讀取配置文件、生成報(bào)告、日志記錄、快速文件I/O。

10. 標(biāo)準(zhǔn)HTTP客戶端:現(xiàn)代化網(wǎng)絡(luò)請(qǐng)求

JDK11將HTTP Client從孵化模塊升級(jí)為標(biāo)準(zhǔn)API,提供了現(xiàn)代化的HTTP客戶端:

// 創(chuàng)建HTTP客戶端
HttpClient client = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(10))
    .build();

// 構(gòu)建GET請(qǐng)求
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.github.com/users/octocat"))
    .header("User-Agent", "Java 11 HttpClient")
    .GET()
    .build();

// 同步發(fā)送請(qǐng)求,接收J(rèn)SON響應(yīng)
HttpResponse<String> response = client.send(request, 
    HttpResponse.BodyHandlers.ofString());

System.out.println("Status code: " + response.statusCode());
System.out.println("Body: " + response.body());

// POST請(qǐng)求示例
HttpRequest postRequest = HttpRequest.newBuilder()
    .uri(URI.create("https://httpbin.org/post"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{"name": "Java"}"))
    .build();

// 異步發(fā)送請(qǐng)求
client.sendAsync(postRequest, HttpResponse.BodyHandlers.ofString())
    .thenApply(HttpResponse::body)
    .thenAccept(System.out::println)
    .join();

// 處理JSON響應(yīng)(需要JSON庫(kù))
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
    .thenApply(HttpResponse::body)
    .thenApply(body -> {
        // 使用Jackson或Gson解析JSON
        return body;
    })
    .thenAccept(System.out::println)
    .join();

實(shí)用場(chǎng)景:RESTful API調(diào)用、微服務(wù)通信、網(wǎng)絡(luò)爬蟲(chóng)、數(shù)據(jù)集成。

JDK 12 語(yǔ)言和庫(kù)的改進(jìn)

11. String.transform():鏈?zhǔn)阶址幚?/h3>

JDK12為String類添加了transform方法,支持鏈?zhǔn)胶瘮?shù)轉(zhuǎn)換:

// 傳統(tǒng)方式
String original = "hello, world!";
String result = original.toUpperCase();
result = result.substring(0, 5);
result = result + "...";

// 使用transform方式
String result = "hello, world!"
    .transform(String::toUpperCase)
    .transform(s -> s.substring(0, 5))
    .transform(s -> s + "...");
System.out.println(result); // HELLO...

// 復(fù)雜轉(zhuǎn)換
String parsed = "{ "name": "John", "age": 30 }"
    .transform(json -> {
        // 解析JSON
        // 此處簡(jiǎn)化,實(shí)際應(yīng)使用Jackson等
        return json.substring(json.indexOf("name") + 7, json.indexOf("age") - 3);
    })
    .transform(String::trim)
    .transform(String::toUpperCase);

System.out.println(parsed); // JOHN

對(duì)于多步轉(zhuǎn)換特別有用,提高了代碼可讀性。

實(shí)用場(chǎng)景:數(shù)據(jù)轉(zhuǎn)換鏈、復(fù)雜字符串處理、函數(shù)式數(shù)據(jù)處理管道。

12. Compact Number Formatting:數(shù)字的可讀性表示

JDK12引入了緊湊數(shù)字格式化功能,可以將大數(shù)字格式化為更易讀的形式:

// 創(chuàng)建簡(jiǎn)短格式的格式化器
NumberFormat shortFormatter = NumberFormat.getCompactNumberInstance(
    Locale.US, NumberFormat.Style.SHORT);

// 格式化數(shù)字
System.out.println(shortFormatter.format(1000));       // 1K
System.out.println(shortFormatter.format(1500));       // 2K (四舍五入)
System.out.println(shortFormatter.format(1000000));    // 1M
System.out.println(shortFormatter.format(1000000000)); // 1B

// 長(zhǎng)格式
NumberFormat longFormatter = NumberFormat.getCompactNumberInstance(
    Locale.US, NumberFormat.Style.LONG);
System.out.println(longFormatter.format(1000));        // 1 thousand
System.out.println(longFormatter.format(1000000));     // 1 million

// 其他語(yǔ)言的格式化
NumberFormat germanFormatter = NumberFormat.getCompactNumberInstance(
    Locale.GERMANY, NumberFormat.Style.SHORT);
System.out.println(germanFormatter.format(1000));      // 1.000

NumberFormat chineseFormatter = NumberFormat.getCompactNumberInstance(
    Locale.CHINA, NumberFormat.Style.SHORT);
System.out.println(chineseFormatter.format(1000));     // 1千
System.out.println(chineseFormatter.format(1000000));  // 100萬(wàn)

// 自定義精度
shortFormatter.setMaximumFractionDigits(1);
System.out.println(shortFormatter.format(1234));       // 1.2K
System.out.println(shortFormatter.format(1500));       // 1.5K

實(shí)用場(chǎng)景:用戶界面顯示、儀表盤(pán)開(kāi)發(fā)、數(shù)據(jù)可視化、國(guó)際化應(yīng)用。

JDK 14 友好錯(cuò)誤信息與語(yǔ)言改進(jìn)

13. 友好的NullPointerException:告別空指針調(diào)試噩夢(mèng)

JDK14增強(qiáng)了NullPointerException,異常消息中會(huì)準(zhǔn)確指出哪個(gè)變量是null:

// 假設(shè)有這樣的代碼
User user = null;
String city = user.getAddress().getCity();

在JDK14之前,你會(huì)得到一個(gè)簡(jiǎn)單的消息:

Exception in thread "main" java.lang.NullPointerException
    at Main.main(Main.java:5)

在JDK14及之后,異常消息變得非常具體:

Exception in thread "main" java.lang.NullPointerException: 
  Cannot invoke "User.getAddress()" because "user" is null
    at Main.main(Main.java:5)

對(duì)于更復(fù)雜的表達(dá)式:

map.get("key").process().getNestedValue();

增強(qiáng)的NPE消息會(huì)明確指出哪一部分是null:

Exception in thread "main" java.lang.NullPointerException: 
  Cannot invoke "Result.getNestedValue()" because the return value of 
  "ProcessedData.process()" is null

實(shí)用場(chǎng)景:調(diào)試復(fù)雜對(duì)象鏈、排查第三方庫(kù)錯(cuò)誤、縮短問(wèn)題定位時(shí)間。

14. Switch表達(dá)式:更簡(jiǎn)潔的分支處理

JDK14正式發(fā)布了switch表達(dá)式(最初在JDK12引入為預(yù)覽特性):

// 傳統(tǒng)switch語(yǔ)句
String result;
DayOfWeek day = LocalDate.now().getDayOfWeek();

switch (day) {
    case MONDAY:
    case TUESDAY:
    case WEDNESDAY:
    case THURSDAY:
    case FRIDAY:
        result = "Weekday";
        break;
    case SATURDAY:
    case SUNDAY:
        result = "Weekend";
        break;
    default:
        result = "Invalid day";
        break;
}

// 新的switch表達(dá)式
String result = switch (day) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
    case SATURDAY, SUNDAY -> "Weekend";
    default -> "Invalid day";
};

// 復(fù)雜表達(dá)式,帶代碼塊
int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> {
        System.out.println("Six letters day");
        yield 6;
    }
    case TUESDAY -> {
        System.out.println("Seven letters day");
        yield 7;
    }
    case THURSDAY, SATURDAY -> {
        System.out.println("Eight letters day");
        yield 8;
    }
    case WEDNESDAY -> {
        System.out.println("Nine letters day");
        yield 9;
    }
    default -> {
        throw new IllegalStateException("Invalid day: " + day);
    }
};

主要優(yōu)點(diǎn)

  • 可以作為表達(dá)式返回值
  • 箭頭語(yǔ)法更簡(jiǎn)潔
  • 使用逗號(hào)可以合并多個(gè)case
  • 不需要break語(yǔ)句,消除了常見(jiàn)的錯(cuò)誤源
  • 窮盡性檢查,確保所有情況都被處理

實(shí)用場(chǎng)景:狀態(tài)機(jī)實(shí)現(xiàn)、命令處理、配置解析、業(yè)務(wù)邏輯分派。

15. 記錄類(Records):數(shù)據(jù)類不再冗長(zhǎng)

JDK14引入了Records作為預(yù)覽特性,在JDK16正式發(fā)布,為不可變數(shù)據(jù)類提供了簡(jiǎn)潔的語(yǔ)法:

// 傳統(tǒng)POJO類
public final class Employee {
    private final String name;
    private final int id;
    private final Department department;
    
    public Employee(String name, int id, Department department) {
        this.name = name;
        this.id = id;
        this.department = department;
    }
    
    public String getName() { return name; }
    public int getId() { return id; }
    public Department getDepartment() { return department; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return id == employee.id && 
               Objects.equals(name, employee.name) && 
               Objects.equals(department, employee.department);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, id, department);
    }
    
    @Override
    public String toString() {
        return "Employee{" +
               "name='" + name + ''' +
               ", id=" + id +
               ", department=" + department +
               '}';
    }
}

// 使用Record
public record Employee(String name, int id, Department department) { }

Records自動(dòng)生成構(gòu)造器、訪問(wèn)器、equals/hashCode和toString方法。

你也可以向Record添加額外的構(gòu)造器、方法和靜態(tài)成員:

public record Point(int x, int y) {
    // 自定義緊湊構(gòu)造器
    public Point {
        if (x < 0 || y < 0) {
            throw new IllegalArgumentException("Coordinates cannot be negative");
        }
    }
    
    // 重載構(gòu)造器
    public Point() {
        this(0, 0);
    }
    
    // 實(shí)例方法
    public double distance(Point other) {
        return Math.sqrt(Math.pow(this.x - other.x, 2) + 
                          Math.pow(this.y - other.y, 2));
    }
    
    // 靜態(tài)成員
    public static final Point ORIGIN = new Point(0, 0);
    
    // 靜態(tài)方法
    public static Point of(int x, int y) {
        return new Point(x, y);
    }
}

實(shí)用場(chǎng)景:DTO對(duì)象、API響應(yīng)模型、消息體、不可變數(shù)據(jù)容器、值對(duì)象。

JDK 15-16 文本和類型檢查優(yōu)化

16. 文本塊:多行字符串不再痛苦

JDK15正式發(fā)布了文本塊功能(在JDK13首次預(yù)覽),讓多行字符串變得簡(jiǎn)單優(yōu)雅:

// 傳統(tǒng)多行字符串
String json = "{\n" +
              "  "name": "John Doe",\n" +
              "  "age": 30,\n" +
              "  "address": {\n" +
              "    "street": "123 Main St",\n" +
              "    "city": "Anytown"\n" +
              "  }\n" +
              "}";

// 使用文本塊
String json = """
              {
                "name": "John Doe",
                "age": 30,
                "address": {
                  "street": "123 Main St",
                  "city": "Anytown"
                }
              }
              """;

// HTML示例
String html = """
              <html>
                <body>
                  <h1>Hello, World!</h1>
                </body>
              </html>
              """;

// SQL查詢
String query = """
               SELECT id, first_name, last_name
               FROM employees
               WHERE department_id = ?
               ORDER BY last_name, first_name
               """;

文本塊還支持字符串插值和格式控制:

// 使用\避免行尾換行
String compact = """
                 <html>\
                 <body>\
                 <p>Hello</p>\
                 </body>\
                 </html>\
                 """;

// 與String::formatted配合使用
String template = """
                  Dear %s,
                  
                  Your order #%d has been shipped on %s.
                  
                  Thank you,
                  Customer Service
                  """;
                  
String message = template.formatted("John", 12345, "2023-05-15");

實(shí)用場(chǎng)景:SQL查詢、HTML/JSON/XML模板、代碼生成、多行文本配置。

17. instanceof模式匹配:類型檢查與轉(zhuǎn)換合二為一

JDK16正式發(fā)布的instanceof模式匹配簡(jiǎn)化了類型檢查和轉(zhuǎn)換:

// 傳統(tǒng)方式
if (obj instanceof String) {
    String s = (String) obj;
    if (s.length() > 5) {
        System.out.println(s.toUpperCase());
    }
}

// 使用模式匹配
if (obj instanceof String s && s.length() > 5) {
    System.out.println(s.toUpperCase());
}

// 在復(fù)雜條件中使用
if (obj instanceof String s && s.length() > 10 
    || obj instanceof List<?> list && list.size() > 5) {
    // 使用s或list
}

// 與switch配合使用(JDK17預(yù)覽特性)
Object value = getValue();
switch (value) {
    case String s when s.length() > 5 -> System.out.println("Long string: " + s);
    case String s -> System.out.println("Short string: " + s);
    case List<?> l -> System.out.println("List with " + l.size() + " elements");
    default -> System.out.println("Unknown type");
}

實(shí)用場(chǎng)景:多態(tài)對(duì)象處理、類型安全轉(zhuǎn)換、空檢查簡(jiǎn)化。

18. 外部?jī)?nèi)存訪問(wèn)API (Foreign Memory Access):安全高效的本地內(nèi)存操作

JDK16引入了Foreign Memory Access API(孵化器階段),為Java提供了安全高效的本地內(nèi)存訪問(wèn)能力:

// 分配堆外內(nèi)存
try (Arena arena = Arena.ofConfined()) {
    // 分配100字節(jié)的本地內(nèi)存
    MemorySegment segment = arena.allocate(100);
    
    // 寫(xiě)入數(shù)據(jù)
    MemorySegment.copy(new byte[] {1, 2, 3, 4, 5}, 0, segment, 0, 5);
    
    // 讀取數(shù)據(jù)
    byte value = segment.get(ValueLayout.JAVA_BYTE, 2); // 讀取索引2的值
    System.out.println("Value at index 2: " + value);   // 輸出 3
    
    // 填充內(nèi)存段
    MemorySegment.fill(segment, (byte) 10);
    
    // 使用VarHandle操作內(nèi)存
    VarHandle intHandle = ValueLayout.JAVA_INT.varHandle();
    intHandle.set(segment, 0, 42);
    int result = (int) intHandle.get(segment, 0);
    System.out.println("Integer value: " + result);     // 輸出 42
    
    // 內(nèi)存地址操作
    long address = segment.address().toRawLongValue();
    System.out.println("Memory address: 0x" + Long.toHexString(address));
}

這個(gè)API在JDK17中得到了改進(jìn),在JDK21中正式發(fā)布。它為需要處理大量數(shù)據(jù)的應(yīng)用程序提供了比ByteBuffer更強(qiáng)大的替代方案。

實(shí)用場(chǎng)景:高性能計(jì)算、大數(shù)據(jù)處理、網(wǎng)絡(luò)應(yīng)用、與本地庫(kù)集成。

JDK 17 長(zhǎng)期支持版的強(qiáng)大特性

19. 密封類(Sealed Classes):精確控制繼承關(guān)系

JDK17正式發(fā)布的密封類允許更精確地控制哪些類可以繼承一個(gè)類:

// 聲明一個(gè)密封接口,只允許特定的類實(shí)現(xiàn)它
public sealed interface Shape 
    permits Circle, Rectangle, Triangle {
    double area();
}

// 最終實(shí)現(xiàn)類,不允許進(jìn)一步繼承
public final class Circle implements Shape {
    private final double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

// 允許進(jìn)一步繼承的類
public non-sealed class Rectangle implements Shape {
    private final double width;
    private final double height;
    
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    
    @Override
    public double area() {
        return width * height;
    }
}

// 限制繼承的類
public sealed class Triangle implements Shape 
    permits EquilateralTriangle, RightTriangle {
    // ...實(shí)現(xiàn)...
}

// 允許的子類
public final class EquilateralTriangle extends Triangle {
    // ...實(shí)現(xiàn)...
}

public final class RightTriangle extends Triangle {
    // ...實(shí)現(xiàn)...
}

密封類與switch模式匹配和記錄類結(jié)合使用時(shí)特別強(qiáng)大,編譯器可以進(jìn)行窮盡性檢查:

double calculateArea(Shape shape) {
    return switch (shape) {
        case Circle c -> Math.PI * c.radius() * c.radius();
        case Rectangle r -> r.width() * r.height();
        case Triangle t -> t.base() * t.height() / 2;
        // 不需要default分支,因?yàn)榫幾g器知道這些是Shape的所有可能實(shí)現(xiàn)
    };
}

實(shí)用場(chǎng)景:領(lǐng)域模型設(shè)計(jì)、類型安全的API、狀態(tài)機(jī)實(shí)現(xiàn)、編譯器檢查增強(qiáng)。

20. 增強(qiáng)的偽隨機(jī)數(shù)生成器:更靈活、可預(yù)測(cè)的隨機(jī)數(shù)

JDK17引入了增強(qiáng)的偽隨機(jī)數(shù)生成器(PRNG)框架,提供了更多算法和更好的接口:

// 獲取默認(rèn)的隨機(jī)數(shù)生成器
RandomGenerator random = RandomGenerator.getDefault();
System.out.println(random.nextInt(100)); // 0-99之間的隨機(jī)數(shù)

// 使用特定算法的生成器
RandomGenerator xoroshiro = RandomGenerator.of("Xoroshiro128PlusPlus");
System.out.println(xoroshiro.nextLong());

// 使用L32X64MixRandom - 平衡了速度和質(zhì)量的算法
RandomGenerator fastRandom = RandomGenerator.of("L32X64MixRandom");
for (int i = 0; i < 5; i++) {
    System.out.println(fastRandom.nextInt(1000));
}

// 創(chuàng)建可復(fù)現(xiàn)的隨機(jī)數(shù)序列 (使用相同的種子)
RandomGenerator seeded = RandomGenerator.of("Xoshiro256PlusPlus");
((SplittableRandomGenerator) seeded).setSeed(42);
for (int i = 0; i < 5; i++) {
    System.out.println(seeded.nextInt(100));
}

// 生成隨機(jī)流
DoubleStream randomDoubles = RandomGenerator.getDefault().doubles(1000);
randomDoubles.forEach(System.out::println);

// 查看所有可用的算法
RandomGenerator.all()
    .map(provider -> provider.name() + ": " + provider.group())
    .sorted()
    .forEach(System.out::println);

實(shí)用場(chǎng)景:科學(xué)計(jì)算、模擬、游戲開(kāi)發(fā)、測(cè)試數(shù)據(jù)生成、加密應(yīng)用。

21. 向量API (Incubator):性能密集型計(jì)算

JDK17引入了孵化器階段的向量API,支持SIMD(單指令多數(shù)據(jù))風(fēng)格的操作,顯著加速特定類型的計(jì)算:

// 使用IntVector加速數(shù)組求和
static int sumArrayVectorized(int[] a) {
    var species = IntVector.SPECIES_PREFERRED;
    var sum = IntVector.zero(species);
    var i = 0;
    
    // 處理可以向量化的部分
    for (; i <= a.length - species.length(); i += species.length()) {
        var v = IntVector.fromArray(species, a, i);
        sum = sum.add(v);
    }
    
    // 處理剩余元素
    var result = sum.reduceLanes(VectorOperators.ADD);
    for (; i < a.length; i++) {
        result += a[i];
    }
    
    return result;
}

// 向量化矩陣乘法
static void multiplyMatricesVectorized(float[] a, float[] b, float[] c, int n) {
    var species = FloatVector.SPECIES_PREFERRED;
    int limit = species.length();
    
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            var sum = FloatVector.zero(species);
            int k = 0;
            
            // 使用向量計(jì)算
            for (; k <= n - limit; k += limit) {
                var va = FloatVector.fromArray(species, a, i * n + k);
                var vb = FloatVector.fromArray(species, b, k * n + j);
                sum = sum.add(va.mul(vb));
            }
            
            // 累加向量結(jié)果
            float dotProduct = sum.reduceLanes(VectorOperators.ADD);
            
            // 處理剩余元素
            for (; k < n; k++) {
                dotProduct += a[i * n + k] * b[k * n + j];
            }
            
            c[i * n + j] = dotProduct;
        }
    }
}

JDK19和JDK21繼續(xù)改進(jìn)了向量API,但截至JDK21仍處于孵化器階段。

實(shí)用場(chǎng)景:科學(xué)計(jì)算、圖像處理、機(jī)器學(xué)習(xí)、信號(hào)處理、金融模擬。

JDK 18-19 工具鏈和API增強(qiáng)

22. 簡(jiǎn)單Web服務(wù)器:快速啟動(dòng)靜態(tài)文件服務(wù)

JDK18引入了一個(gè)簡(jiǎn)單的命令行HTTP服務(wù)器,可以快速啟動(dòng)靜態(tài)文件服務(wù):

// 命令行用法
// jwebserver -p 8000 -d /path/to/directory

// 在代碼中使用:
import com.sun.net.httpserver.*;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Path;

public class SimpleFileServer {
    public static void main(String[] args) throws IOException {
        var server = SimpleFileServer.createFileServer(
            new InetSocketAddress(8000), 
            Path.of("/path/to/directory"), 
            SimpleFileServer.OutputLevel.VERBOSE
        );
        server.start();
        System.out.println("Server started at http://localhost:8000");
    }
}

這個(gè)功能特別適合開(kāi)發(fā)和測(cè)試環(huán)境,比如快速預(yù)覽靜態(tài)網(wǎng)站或測(cè)試API調(diào)用。

實(shí)用場(chǎng)景:前端開(kāi)發(fā)、靜態(tài)網(wǎng)站預(yù)覽、本地測(cè)試環(huán)境、原型開(kāi)發(fā)。

23. 代碼片段in JavaDoc:更好的API文檔

JDK18引入了@snippet標(biāo)簽,允許在JavaDoc中添加帶有語(yǔ)法高亮的代碼示例:

/**
 * This class provides utility methods for string operations.
 *
 * <p>Example usage:</p>
 * {@snippet :
 *   String result = StringUtils.capitalize("hello");  // Returns "Hello"
 *   boolean isEmpty = StringUtils.isBlank(" ");       // Returns true
 * }
 */
public class StringUtils {
    // 類實(shí)現(xiàn)省略
}

增強(qiáng)的文檔還支持高亮、區(qū)域標(biāo)記和錯(cuò)誤標(biāo)記:

/**
 * Example of snippet with highlighting:
 * {@snippet :
 *   // @highlight region="important"
 *   String encoded = Base64.getEncoder().encodeToString(data);
 *   // @end
 *   
 *   // @highlight regex="data" type="bold"
 *   byte[] decoded = Base64.getDecoder().decode(encoded);
 *   
 *   // @replace regex="badPractice()" replacement="goodPractice()" type="error"
 *   result = badPractice();
 * }
 */

實(shí)用場(chǎng)景:API文檔、開(kāi)源項(xiàng)目、技術(shù)指南、教程編寫(xiě)。

24. 外部函數(shù)接口 (Foreign Function & Memory API)

JDK19改進(jìn)了孵化器中的外部函數(shù)接口(在JDK21中正式發(fā)布),讓Java與本地代碼交互更加簡(jiǎn)單:

// 定義C庫(kù)函數(shù)的接口
import java.lang.foreign.*;
import static java.lang.foreign.ValueLayout.*;

public class LibCDemo {
    public static void main(String[] args) {
        // 獲取C標(biāo)準(zhǔn)庫(kù)的鏈接器
        Linker linker = Linker.nativeLinker();
        
        // 查找printf函數(shù)
        SymbolLookup stdlib = linker.defaultLookup();
        MethodHandle printf = stdlib.find("printf")
            .map(addr -> linker.downcallHandle(
                addr,
                FunctionDescriptor.of(JAVA_INT, ADDRESS),
                Linker.Option.firstVariadicArg(1)
            ))
            .orElseThrow();
        
        // 準(zhǔn)備字符串參數(shù)
        try (Arena arena = Arena.ofConfined()) {
            MemorySegment cString = arena.allocateUtf8String("Hello from Java! Count: %d\n");
            
            // 調(diào)用printf
            try {
                printf.invoke(cString, 42);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }
}

這個(gè)API消除了JNI的大部分復(fù)雜性,提供了更安全、更簡(jiǎn)潔的方式來(lái)調(diào)用本地代碼。

實(shí)用場(chǎng)景:與C/C++庫(kù)集成、系統(tǒng)編程、性能關(guān)鍵應(yīng)用、多語(yǔ)言項(xiàng)目。

JDK 20-21 現(xiàn)代并發(fā)和語(yǔ)言增強(qiáng)

25. 虛擬線程(Virtual Threads):并發(fā)革命

JDK21正式發(fā)布了虛擬線程,這是Java并發(fā)編程的重大變革:

// 創(chuàng)建和啟動(dòng)單個(gè)虛擬線程
Thread.startVirtualThread(() -> {
    System.out.println("Running in virtual thread");
});

// 使用虛擬線程運(yùn)行多個(gè)任務(wù)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    // 提交1000個(gè)任務(wù),每個(gè)在獨(dú)立的虛擬線程中運(yùn)行
    for (int i = 0; i < 1000; i++) {
        int taskId = i;
        executor.submit(() -> {
            System.out.println("Task " + taskId + " running on " + Thread.currentThread());
            // 模擬IO操作
            try {
                Thread.sleep(Duration.ofMillis(100));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return taskId;
        });
    }
} // 自動(dòng)關(guān)閉executor

// 以構(gòu)建器方式創(chuàng)建虛擬線程
ThreadFactory factory = Thread.ofVirtual().name("worker-", 0).factory();
Thread worker = factory.newThread(() -> {
    // 任務(wù)代碼
});
worker.start();

// 使用虛擬線程改寫(xiě)傳統(tǒng)的阻塞式IO代碼
void processFile(Path file) throws IOException {
    // 這段代碼在虛擬線程中運(yùn)行時(shí)不會(huì)阻塞平臺(tái)線程
    try (var reader = Files.newBufferedReader(file)) {
        String line;
        while ((line = reader.readLine()) != null) {
            processLine(line);
        }
    }
}

虛擬線程的主要優(yōu)勢(shì)是可以創(chuàng)建數(shù)百萬(wàn)個(gè)輕量級(jí)線程,而不會(huì)耗盡系統(tǒng)資源。它們特別適合IO密集型應(yīng)用,使同步代碼可以獲得與異步代碼相當(dāng)?shù)臄U(kuò)展性。

實(shí)用場(chǎng)景:高并發(fā)Web服務(wù)器、微服務(wù)、數(shù)據(jù)處理管道、爬蟲(chóng)程序。

26. 結(jié)構(gòu)化并發(fā)(Structured Concurrency)

可以管理異步任務(wù)的生命周期

JDK21引入了結(jié)構(gòu)化并發(fā)API(預(yù)覽特性),簡(jiǎn)化了多線程代碼的錯(cuò)誤處理和資源管理:

// 并行獲取用戶及其訂單
record User(int id, String name) {}
record Order(int id, double amount) {}
record UserWithOrders(User user, List<Order> orders) {}

UserWithOrders getUserWithOrders(int userId) {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        // 并行執(zhí)行兩個(gè)子任務(wù)
        Future<User> userFuture = scope.fork(() -> fetchUser(userId));
        Future<List<Order>> ordersFuture = scope.fork(() -> fetchOrders(userId));
        
        // 等待所有任務(wù)完成
        scope.join();
        // 檢查子任務(wù)是否有異常
        scope.throwIfFailed(e -> new RuntimeException("Failed to fetch data", e));
        
        // 獲取結(jié)果
        return new UserWithOrders(userFuture.resultNow(), ordersFuture.resultNow());
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

// 使用結(jié)構(gòu)化并發(fā)處理多個(gè)API調(diào)用
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    var weatherFuture = scope.fork(() -> callWeatherAPI());
    var trafficFuture = scope.fork(() -> callTrafficAPI());
    var newsFuture = scope.fork(() -> callNewsAPI());
    
    try {
        scope.join();
        scope.throwIfFailed();
        
        // 所有API調(diào)用成功,處理結(jié)果
        var dashboard = createDashboard(
            weatherFuture.resultNow(),
            trafficFuture.resultNow(),
            newsFuture.resultNow()
        );
        return dashboard;
    } catch (Exception e) {
        // 有一個(gè)API調(diào)用失敗,所有任務(wù)都被取消
        return createFallbackDashboard();
    }
}

結(jié)構(gòu)化并發(fā)確保所有子任務(wù)在父任務(wù)退出前要么完成,要么被取消,避免了資源泄漏和"遺忘"的后臺(tái)任務(wù)。

實(shí)用場(chǎng)景:API聚合、微服務(wù)通信、并行數(shù)據(jù)處理、復(fù)雜異步工作流。

27. Record模式(Record Patterns):解構(gòu)數(shù)據(jù)更簡(jiǎn)單

JDK21正式發(fā)布的Record模式允許在模式匹配中解構(gòu)記錄:

// 定義一些記錄
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}
record Circle(Point center, int radius) {}

// 使用傳統(tǒng)方式處理記錄
Object shape = new Rectangle(new Point(1, 2), new Point(5, 6));
if (shape instanceof Rectangle) {
    Rectangle r = (Rectangle) shape;
    Point topLeft = r.topLeft();
    Point bottomRight = r.bottomRight();
    int width = bottomRight.x() - topLeft.x();
    int height = bottomRight.y() - topLeft.y();
    System.out.println("Rectangle with width " + width + " and height " + height);
}

// 使用Record模式解構(gòu)
if (shape instanceof Rectangle(Point(var x1, var y1), Point(var x2, var y2))) {
    int width = x2 - x1;
    int height = y2 - y1;
    System.out.println("Rectangle with width " + width + " and height " + height);
}

// 結(jié)合switch使用
String getDescription(Object shape) {
    return switch (shape) {
        case Rectangle(Point(var x1, var y1), Point(var x2, var y2)) ->
            "Rectangle from (%d,%d) to (%d,%d)".formatted(x1, y1, x2, y2);
        
        case Circle(Point(var x, var y), var r) ->
            "Circle at (%d,%d) with radius %d".formatted(x, y, r);
        
        default -> "Unknown shape";
    };
}

Record模式與嵌套模式結(jié)合使用時(shí)特別強(qiáng)大,可以輕松處理復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。

實(shí)用場(chǎng)景:數(shù)據(jù)轉(zhuǎn)換、JSON/XML解析結(jié)果處理、領(lǐng)域模型操作、事件處理。

28. 字符串模板(String Templates):安全高效的字符串插值

JDK21引入了字符串模板作為預(yù)覽特性,提供比字符串連接更簡(jiǎn)潔、更安全的方式:

// 傳統(tǒng)方式
String name = "Alice";
int age = 30;
String message = "Hello, " + name + "! Next year, you'll be " + (age + 1) + ".";

// 使用字符串模板
String message = STR."Hello, {name}! Next year, you'll be {age + 1}.";

// 帶表達(dá)式的模板
String status = "active";
String message = STR."User status: {status.toUpperCase()} (set {LocalDate.now()})";

// 格式化數(shù)字
double value = 1234.56789;
String formatted = STR."The value is {value%.2f}";  // "The value is 1234.57"

// 多行JSON
String json = STR."""
    {
      "name": "{name}",
      "age": {age},
      "isAdult": {age >= 18},
      "contacts": [
        {generateContactsJson()}
      ]
    }
    """;

字符串模板不僅語(yǔ)法簡(jiǎn)潔,還提供了類型安全和對(duì)表達(dá)式的編譯時(shí)檢查。

實(shí)用場(chǎng)景:生成JSON/XML/HTML、日志記錄、消息格式化、SQL語(yǔ)句構(gòu)建。

29. 序列集合 (Sequenced Collections):統(tǒng)一的集合操作

JDK21引入了SequencedCollection、SequencedSetSequencedMap接口,為Java集合框架添加了方向性和順序性操作:

// 序列化集合基本用法
SequencedCollection<String> names = new ArrayList<>(List.of("Alice", "Bob", "Charlie"));

// 獲取第一個(gè)和最后一個(gè)元素
String first = names.getFirst();  // "Alice"
String last = names.getLast();    // "Charlie"

// 添加元素到兩端
names.addFirst("Zoe");
names.addLast("David");
System.out.println(names);  // [Zoe, Alice, Bob, Charlie, David]

// 創(chuàng)建反向視圖
SequencedCollection<String> reversed = names.reversed();
System.out.println(reversed);  // [David, Charlie, Bob, Alice, Zoe]

// 序列化Map
SequencedMap<String, Integer> scores = new LinkedHashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 85);
scores.put("Charlie", 90);

// 獲取第一個(gè)和最后一個(gè)條目
Map.Entry<String, Integer> firstEntry = scores.firstEntry();  // Alice=95
Map.Entry<String, Integer> lastEntry = scores.lastEntry();    // Charlie=90

// 添加條目到兩端
scores.putFirst("Zoe", 100);
scores.putLast("David", 80);

// 獲取鍵或值的序列化視圖
SequencedCollection<String> keys = scores.sequencedKeySet();
SequencedCollection<Integer> values = scores.sequencedValues();

這些接口統(tǒng)一了Java集合框架中的順序操作,使API更加一致。現(xiàn)有的有序集合類如ArrayList、LinkedHashSetLinkedHashMap都實(shí)現(xiàn)了這些新接口。

實(shí)用場(chǎng)景:維持插入順序的集合、FIFO/LIFO隊(duì)列操作、雙向迭代、有序數(shù)據(jù)處理。

總結(jié)

Java語(yǔ)言在保持向后兼容性的同時(shí),不斷引入新特性以提高開(kāi)發(fā)效率和代碼質(zhì)量。掌握這些新特性不僅能提高開(kāi)發(fā)效率,還能編寫(xiě)出更加簡(jiǎn)潔、健壯的代碼。

到此這篇關(guān)于JDK9到JDK21中值得掌握的29個(gè)實(shí)用特性分享的文章就介紹到這了,更多相關(guān)JDK實(shí)用特性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java基礎(chǔ)之Math和Random類知識(shí)總結(jié)

    Java基礎(chǔ)之Math和Random類知識(shí)總結(jié)

    今天帶大家來(lái)學(xué)習(xí)java的Math和Random類,文中有非常詳細(xì)的代碼示例及介紹,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們很有幫助喲,需要的朋友可以參考下
    2021-05-05
  • Java對(duì)象的復(fù)制三種方式(小結(jié))

    Java對(duì)象的復(fù)制三種方式(小結(jié))

    這篇文章主要介紹了Java對(duì)象的復(fù)制三種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java實(shí)現(xiàn)文件或文件夾的復(fù)制到指定目錄實(shí)例

    Java實(shí)現(xiàn)文件或文件夾的復(fù)制到指定目錄實(shí)例

    本篇文章主要介紹了Java實(shí)現(xiàn)文件或文件夾的復(fù)制到指定目錄實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Spring boot集成Kafka+Storm的示例代碼

    Spring boot集成Kafka+Storm的示例代碼

    這篇文章主要介紹了Spring boot集成Kafka+Storm的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • IDEA 集成 Docker 插件一鍵部署 SpringBoot 應(yīng)用小結(jié)

    IDEA 集成 Docker 插件一鍵部署 SpringBoot 應(yīng)用

    通過(guò)本文介紹的方法,我們期望能幫助開(kāi)發(fā)者更輕松地在IDEA中實(shí)現(xiàn)Spring Boot應(yīng)用的Docker化部署,為現(xiàn)代軟件開(kāi)發(fā)提供更便捷的解決方案,感興趣的朋友一起看看吧
    2023-11-11
  • springboot整合freemarker詳解

    springboot整合freemarker詳解

    本篇文章主要介紹了springboot整合freemarker詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • SpringBoot讀取Resource下文件的4種方法

    SpringBoot讀取Resource下文件的4種方法

    這篇文章主要介紹了SpringBoot讀取Resource下文件的4種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot項(xiàng)目創(chuàng)建使用+配置文件+日志文件詳解

    SpringBoot項(xiàng)目創(chuàng)建使用+配置文件+日志文件詳解

    Spring的出現(xiàn)是為了簡(jiǎn)化 Java 程序開(kāi)發(fā),而 SpringBoot 的出現(xiàn)是為了簡(jiǎn)化 Spring 程序開(kāi)發(fā),這篇文章主要介紹了SpringBoot項(xiàng)目創(chuàng)建使用+配置文件+日志文件,需要的朋友可以參考下
    2023-02-02
  • SpringBoot整合jasypt實(shí)現(xiàn)重要數(shù)據(jù)加密

    SpringBoot整合jasypt實(shí)現(xiàn)重要數(shù)據(jù)加密

    Jasypt是一個(gè)專注于簡(jiǎn)化Java加密操作的開(kāi)源工具,這篇文章主要為大家介紹了詳細(xì)介紹了如何使用jasypt實(shí)現(xiàn)重要數(shù)據(jù)加密,感興趣的小伙伴可以了解下
    2025-03-03
  • 如何獲得spring上下文的方法總結(jié)

    如何獲得spring上下文的方法總結(jié)

    這篇文章主要介紹了如何獲得spring上下文的方法總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04

最新評(píng)論