Java 11作为第一个LTS版本,带来了革命性的字符串API增强、HTTP客户端标准化和ZGC垃圾回收器等重要特性。本文将深入剖析Java 11的核心新特性,从字符串处理到现代化基础设施,带你体验LTS版本的稳定与创新。
🎯 Java 11变革背景 LTS版本的重要意义 Java 11是Oracle发布周期改革后的第一个长期支持(LTS)版本:
LTS承诺 :8年的免费支持和更新
企业友好 :稳定的生产环境选择
功能平衡 :既保持创新又保证稳定性
生态影响 :影响了整个Java生态的发展方向
现代化与性能的双重追求 现代化方面 :
字符串API的全面增强
HTTP客户端的标准化
文件操作的简化
Unicode 10支持
性能方面 :
ZGC垃圾回收器:可扩展的低延迟GC
Epsilon GC:用于性能测试和内存压力测试
运行时镜像:AOT编译支持
动态类文件常量:提升常量加载性能
🔤 字符串API增强:现代字符串处理 1. 传统字符串处理的局限性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class StringUtilsJava10 { public static boolean isBlank (String str) { if (str == null ) return true ; for (int i = 0 ; i < str.length(); i++) { if (!Character.isWhitespace(str.charAt(i))) { return false ; } } return true ; } public static List<String> lines (String str) { List<String> result = new ArrayList <>(); if (str == null || str.isEmpty()) return result; int start = 0 ; for (int i = 0 ; i < str.length(); i++) { char c = str.charAt(i); if (c == '\n' || c == '\r' ) { if (start < i) { result.add(str.substring(start, i)); } if (c == '\r' && i + 1 < str.length() && str.charAt(i + 1 ) == '\n' ) { i++; } start = i + 1 ; } } if (start < str.length()) { result.add(str.substring(start)); } return result; } public static String strip (String str) { if (str == null ) return null ; return str.trim(); } public static String repeat (String str, int count) { if (str == null ) return null ; if (count <= 0 ) return "" ; if (count == 1 ) return str; StringBuilder sb = new StringBuilder (str.length() * count); for (int i = 0 ; i < count; i++) { sb.append(str); } return sb.toString(); } }
2. Java 11字符串API的优雅解决方案 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 public class StringUtilsJava11 { public static void demonstrateIsBlank () { String empty = "" ; String spaces = " " ; String tabs = "\t\t" ; String content = " hello " ; System.out.println("\"\".isBlank(): " + "" .isBlank()); System.out.println("\" \".isBlank(): " + " " .isBlank()); System.out.println("\"\\t\\t\".isBlank(): " + "\t\t" .isBlank()); System.out.println("\" hello \".isBlank(): " + " hello " .isBlank()); System.out.println("传统isBlank(\" \"): " + isBlankTraditional(" " )); } public static void demonstrateLines () { String multiline = "Hello\nWorld\r\nJava\r11" ; multiline.lines().forEach(line -> { System.out.println("Line: '" + line + "'" ); }); System.out.println("传统lines(): " + linesTraditional(multiline)); } public static void demonstrateStrip () { String text = " \u2000\u2001hello\u2002\u2003 " ; System.out.println("原始字符串长度: " + text.length()); System.out.println("strip()结果: '" + text.strip() + "'" ); System.out.println("strip()后长度: " + text.strip().length()); System.out.println("stripLeading(): '" + text.stripLeading() + "'" ); System.out.println("stripTrailing(): '" + text.stripTrailing() + "'" ); System.out.println("trim()结果: '" + text.trim() + "'" ); System.out.println("trim()后长度: " + text.trim().length()); } public static void demonstrateRepeat () { String pattern = "*-" ; System.out.println("\"*-\".repeat(5): " + pattern.repeat(5 )); System.out.println("\"Hello\".repeat(3): " + "Hello" .repeat(3 )); System.out.println("\"A\".repeat(0): " + "A" .repeat(0 )); System.out.println("\"Test\".repeat(1): " + "Test" .repeat(1 )); String separator = "=" .repeat(50 ); System.out.println(separator); System.out.println("Java 11 String API Demo" ); System.out.println(separator); } private static boolean isBlankTraditional (String str) { return str == null || str.trim().isEmpty(); } private static List<String> linesTraditional (String str) { return Arrays.asList(str.split("\\r?\\n" )); } }
字符串API增强的优势 :
Unicode友好 :正确处理所有Unicode空白字符
性能优化 :内置实现比自定义方法更高效
空安全 :正确处理null值
一致性 :API设计保持一致
🌐 HTTP客户端标准化:现代网络通信 1. Java 10 HTTP客户端的局限性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.net.http.*;import java.net.URI;import java.time.Duration;public class HttpClientJava10 { private static final HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(10 )) .build(); public static String getSync (String url) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("User-Agent" , "Java-10-Client" ) .timeout(Duration.ofSeconds(5 )) .build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); return response.statusCode() == 200 ? response.body() : null ; } public static CompletableFuture<String> getAsync (String url) { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .build(); return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(response -> response.body()); } }
2. Java 11 HTTP客户端的增强 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 import java.net.http.*;import java.net.URI;import java.time.Duration;import java.net.Authenticator;import java.net.PasswordAuthentication;public class HttpClientJava11 { private static final HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(10 )) .followRedirects(HttpClient.Redirect.NORMAL) .authenticator(new Authenticator () { @Override protected PasswordAuthentication getPasswordAuthentication () { return new PasswordAuthentication ("user" , "password" .toCharArray()); } }) .build(); public static HttpResponse<String> getSync (String url) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("User-Agent" , "Java-11-Client" ) .header("Accept" , "application/json" ) .timeout(Duration.ofSeconds(5 )) .build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); switch (response.statusCode()) { case 200 : return response; case 404 : throw new RuntimeException ("Resource not found: " + url); case 500 : throw new RuntimeException ("Server error: " + url); default : throw new RuntimeException ("HTTP error: " + response.statusCode()); } } public static HttpResponse<String> postJson (String url, String jsonData) throws Exception { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Content-Type" , "application/json" ) .header("Authorization" , "Bearer " + getAuthToken()) .POST(HttpRequest.BodyPublishers.ofString(jsonData)) .build(); return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } public static CompletableFuture<String> getAsyncChain (String url) { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .build(); return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenApply(String::toUpperCase) .thenApply(body -> "Processed: " + body) .exceptionally(throwable -> { System.err.println("Async request failed: " + throwable.getMessage()); return "Error occurred" ; }); } public static void webSocketExample () { WebSocket webSocket = httpClient.newWebSocketBuilder() .buildAsync(URI.create("wss://echo.websocket.org" ), new WebSocket .Listener() { @Override public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) { System.out.println("Received: " + data); if (last) { webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "Client closing" ); } return null ; } @Override public void onError (WebSocket webSocket, Throwable error) { System.err.println("WebSocket error: " + error.getMessage()); } }).join(); webSocket.sendText("Hello from Java 11!" , true ); try { Thread.sleep(2000 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public static void fileUploadDownload () throws Exception { Path filePath = Paths.get("data.txt" ); HttpRequest uploadRequest = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/upload" )) .POST(HttpRequest.BodyPublishers.ofFile(filePath)) .build(); HttpResponse<String> uploadResponse = httpClient.send(uploadRequest, HttpResponse.BodyHandlers.ofString()); HttpRequest downloadRequest = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/download/file.txt" )) .build(); HttpResponse<Path> downloadResponse = httpClient.send(downloadRequest, HttpResponse.BodyHandlers.ofFile(Paths.get("downloaded.txt" ))); System.out.println("File downloaded to: " + downloadResponse.body()); } private static String getAuthToken () { return "your-jwt-token-here" ; } }
HTTP客户端增强 :
标准化API :成为Java标准库的一部分
更好的认证支持 :内置认证机制
增强的异步支持 :更流畅的异步链式调用
文件操作支持 :直接上传下载文件
WebSocket改进 :更好的WebSocket支持
📁 文件方法增强:简化的文件操作 1. Java 10文件操作的复杂性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.io.*;import java.nio.file.*;import java.util.stream.Stream;public class FileUtilsJava10 { public static String readAllText (String filePath) throws IOException { byte [] bytes = Files.readAllBytes(Paths.get(filePath)); return new String (bytes, StandardCharsets.UTF_8); } public static void writeAllText (String filePath, String content) throws IOException { Files.write(Paths.get(filePath), content.getBytes(StandardCharsets.UTF_8)); } public static List<String> readAllLines (String filePath) throws IOException { return Files.readAllLines(Paths.get(filePath), StandardCharsets.UTF_8); } public static void writeAllLines (String filePath, List<String> lines) throws IOException { Files.write(Paths.get(filePath), lines, StandardCharsets.UTF_8); } }
2. Java 11文件方法的简化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 import java.io.IOException;import java.nio.file.*;import java.nio.charset.StandardCharsets;import java.util.List;import java.util.stream.Stream;public class FileUtilsJava11 { public static String readStringSimple (String filePath) throws IOException { Path path = Paths.get(filePath); return Files.readString(path); } public static String readStringWithCharset (String filePath) throws IOException { Path path = Paths.get(filePath); return Files.readString(path, StandardCharsets.UTF_16); } public static void writeStringSimple (String filePath, String content) throws IOException { Path path = Paths.get(filePath); Files.writeString(path, content); } public static void writeStringAdvanced (String filePath, String content) throws IOException { Path path = Paths.get(filePath); Files.writeString(path, content, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); } public static void appendString (String filePath, String content) throws IOException { Path path = Paths.get(filePath); Files.writeString(path, content, StandardOpenOption.CREATE, StandardOpenOption.APPEND); } public static byte [] readAllBytes(String filePath) throws IOException { return Files.readAllBytes(Paths.get(filePath)); } public static void writeBytes (String filePath, byte [] data) throws IOException { Files.write(Paths.get(filePath), data); } public static void demonstrateFileOperations () throws IOException { String configPath = "config.properties" ; String logPath = "app.log" ; if (Files.exists(Paths.get(configPath))) { String config = Files.readString(Paths.get(configPath)); System.out.println("Config content: " + config); } else { String defaultConfig = """ app.name=MyApp app.version=1.0 app.debug=true """ ; Files.writeString(Paths.get(configPath), defaultConfig); System.out.println("Default config created" ); } String logEntry = String.format("[%s] Application started%n" , java.time.LocalDateTime.now()); appendString(logPath, logEntry); if (Files.exists(Paths.get(logPath))) { List<String> lines = Files.readAllLines(Paths.get(logPath)); int startIndex = Math.max(0 , lines.size() - 5 ); lines.subList(startIndex, lines.size()).forEach(System.out::println); } } public static void streamFileProcessing (String inputPath, String outputPath) throws IOException { Path input = Paths.get(inputPath); Path output = Paths.get(outputPath); Stream<String> lines = Files.lines(input); String processedContent = lines .map(String::toUpperCase) .map(line -> line.replaceAll("\\s+" , " " )) .filter(line -> !line.trim().isEmpty()) .collect(java.util.stream.Collectors.joining("\n" )); Files.writeString(output, processedContent); } public static void temporaryFileOperations () throws IOException { Path tempFile = Files.createTempFile("temp" , ".txt" ); Files.writeString(tempFile, "Temporary content" ); String content = Files.readString(tempFile); System.out.println("Temp file content: " + content); Files.delete(tempFile); System.out.println("Temp file deleted: " + Files.notExists(tempFile)); } }
文件方法增强的优势 :
简化API :readString()和writeString()简化操作
编码友好 :默认UTF-8,支持自定义编码
选项丰富 :支持追加、创建、覆盖等多种操作
性能优化 :针对字符串操作优化
🗂️ 集合API增强:更实用的集合操作 1. Java 10集合操作的局限性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CollectionUtilsJava10 { public static void demonstrateToArray () { List<String> names = Arrays.asList("Alice" , "Bob" , "Charlie" ); Object[] objectArray = names.toArray(); System.out.println("Object array: " + Arrays.toString(objectArray)); String[] stringArray = names.toArray(new String [0 ]); System.out.println("String array: " + Arrays.toString(stringArray)); String[] sizedArray = names.toArray(new String [names.size()]); System.out.println("Sized array: " + Arrays.toString(sizedArray)); } }
2. Java 11集合API的改进 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 import java.util.*;import java.util.stream.Collectors;public class CollectionUtilsJava11 { public static void demonstrateToArray () { List<String> names = Arrays.asList("Alice" , "Bob" , "Charlie" , "Diana" ); String[] stringArray = names.toArray(String[]::new ); System.out.println("String array: " + Arrays.toString(stringArray)); String[] oldWay = names.toArray(new String [0 ]); System.out.println("Old way: " + Arrays.toString(oldWay)); Set<Integer> numbers = Set.of(1 , 2 , 3 , 4 , 5 ); Integer[] numberArray = numbers.toArray(Integer[]::new ); System.out.println("Number array: " + Arrays.toString(numberArray)); } public static void streamAndCollection () { List<String> names = Arrays.asList("alice" , "bob" , "charlie" , "diana" ); String[] filteredNames = names.stream() .filter(name -> name.length() > 3 ) .map(String::toUpperCase) .toArray(String[]::new ); System.out.println("Filtered names: " + Arrays.toString(filteredNames)); Map<Integer, List<String>> groupedByLength = names.stream() .collect(Collectors.groupingBy(String::length)); for (Map.Entry<Integer, List<String>> entry : groupedByLength.entrySet()) { String[] groupArray = entry.getValue().toArray(String[]::new ); System.out.println("Length " + entry.getKey() + ": " + Arrays.toString(groupArray)); } } public static void realWorldExamples () { List<User> users = getUsersFromDatabase(); User[] userArray = users.toArray(User[]::new ); List<Order> orders = getOrdersFromAPI(); String[] orderIds = orders.stream() .map(Order::getId) .toArray(String[]::new ); List<Path> files = getFilesFromDirectory(); String[] fileNames = files.stream() .map(Path::getFileName) .map(Path::toString) .toArray(String[]::new ); System.out.println("Users: " + Arrays.toString(userArray)); System.out.println("Order IDs: " + Arrays.toString(orderIds)); System.out.println("File names: " + Arrays.toString(fileNames)); } static class User { private final String name; User(String name) { this .name = name; } @Override public String toString () { return name; } } static class Order { private final String id; Order(String id) { this .id = id; } public String getId () { return id; } @Override public String toString () { return "Order:" + id; } } private static List<User> getUsersFromDatabase () { return Arrays.asList(new User ("Alice" ), new User ("Bob" )); } private static List<Order> getOrdersFromAPI () { return Arrays.asList(new Order ("001" ), new Order ("002" )); } private static List<Path> getFilesFromDirectory () { return Arrays.asList( java.nio.file.Paths.get("file1.txt" ), java.nio.file.Paths.get("file2.txt" ) ); } }
集合API增强的优势 :
类型安全 :toArray(String[]::new)确保类型正确
简洁明了 :减少样板代码
性能优化 :避免不必要的数组复制
灵活性 :支持所有集合类型
🎭 Optional增强:更优雅的空值处理 1. Java 10 Optional的不足 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class OptionalExampleJava10 { public static void demonstrateOptional () { Optional<String> optional = Optional.ofNullable(getValue()); if (!optional.isPresent()) { System.out.println("Value is empty" ); } if (optional.isPresent()) { System.out.println("Value: " + optional.get()); } else { System.out.println("Value is empty" ); } if (optional.isPresent() && optional.get().length() > 5 ) { System.out.println("Long value: " + optional.get()); } } private static String getValue () { return Math.random() > 0.5 ? "Hello World" : null ; } }
2. Java 11 Optional的改进 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 public class OptionalExampleJava11 { public static void demonstrateIsEmpty () { Optional<String> optional = Optional.ofNullable(getValue()); if (optional.isEmpty()) { System.out.println("Value is empty" ); } else { System.out.println("Value: " + optional.get()); } if (!optional.isPresent()) { System.out.println("Value is empty (old way)" ); } } public static void advancedOptionalUsage () { List<Optional<String>> optionals = Arrays.asList( Optional.of("Hello" ), Optional.empty(), Optional.of("World" ), Optional.empty() ); List<String> nonEmptyValues = optionals.stream() .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); List<String> nonEmptyValuesNew = optionals.stream() .filter(optional -> !optional.isEmpty()) .map(Optional::get) .collect(Collectors.toList()); System.out.println("Non-empty values: " + nonEmptyValues); System.out.println("Non-empty values (new): " + nonEmptyValuesNew); long emptyCount = optionals.stream().filter(Optional::isEmpty).count(); long presentCount = optionals.stream().filter(Optional::isPresent).count(); System.out.println("Empty optionals: " + emptyCount); System.out.println("Present optionals: " + presentCount); } public static void realWorldOptional () { User user = findUserById("123" ); Optional<String> userName = Optional.ofNullable(user) .map(User::getName); if (userName.isEmpty()) { System.out.println("User not found or has no name" ); } else { System.out.println("User name: " + userName.get()); } userName.ifPresentOrElse( name -> System.out.println("Found user: " + name), () -> System.out.println("User not found" ) ); Optional<String> configValue = readConfig("app.timeout" ); int timeout = configValue .filter(value -> !value.trim().isEmpty()) .map(Integer::parseInt) .orElse(30 ); System.out.println("Timeout: " + timeout + " seconds" ); } public static void chainOptimization () { Optional<String> result = getData() .filter(data -> data.length() > 10 ) .map(String::toUpperCase); if (result.isEmpty()) { System.out.println("No valid data found" ); } else { String processedData = result.get(); System.out.println("Processed data: " + processedData); } String finalResult = result.orElse("DEFAULT_VALUE" ); System.out.println("Final result: " + finalResult); } private static String getValue () { return Math.random() > 0.5 ? "Hello Java 11" : null ; } private static User findUserById (String id) { return "123" .equals(id) ? new User ("Alice" ) : null ; } private static String readConfig (String key) { return "app.timeout" .equals(key) ? "60" : null ; } static class User { private final String name; User(String name) { this .name = name; } public String getName () { return name; } } private static Optional<String> getData () { return Optional.ofNullable(Math.random() > 0.3 ? "Short" : "This is a long data string" ); } }
Optional增强的优势 :
更直观 :isEmpty()比!isPresent()更清晰
代码一致性 :与其他集合类的API保持一致
可读性提升 :减少否定逻辑,代码更易理解
现代化 :符合现代编程语言的设计理念
⚡ Lambda参数的var语法 1. Java 10 Lambda参数的限制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.function.Function;public class LambdaVarJava10 { public static void main (String[] args) { Function<String, Integer> lengthFunc = s -> s.length(); Function<String, Integer> lengthFunc2 = (String s) -> s.length(); } }
2. Java 11 Lambda参数的var语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 import java.util.function.*;import java.util.List;import java.util.stream.Collectors;public class LambdaVarJava11 { public static void demonstrateBasicVar () { Function<String, Integer> lengthFunc = (var s) -> s.length(); BiFunction<String, String, String> concatFunc = (var s1, var s2) -> s1 + s2; System.out.println("Length: " + lengthFunc.apply("Hello" )); System.out.println("Concat: " + concatFunc.apply("Hello" , " World" )); } public static void demonstrateVarWithAnnotations () { Function<String, Integer> annotatedFunc = (@SuppressWarnings("unused") var s) -> s.length(); BiFunction<String, String, Boolean> compareFunc = ( (@NonNull var s1), (@NonNull var s2) ) -> s1.length() > s2.length(); System.out.println("Compare result: " + compareFunc.apply("Hello" , "Hi" )); } public static void demonstrateStreamUsage () { List<String> names = List.of("Alice" , "Bob" , "Charlie" , "Diana" ); List<String> upperNames = names.stream() .map((var name) -> name.toUpperCase()) .collect(Collectors.toList()); Map<Integer, List<String>> groupedByLength = names.stream() .collect(Collectors.groupingBy((var name) -> name.length())); System.out.println("Upper names: " + upperNames); System.out.println("Grouped by length: " + groupedByLength); } public static void realWorldUsage () { List<User> users = getUsers(); List<String> validNames = users.stream() .filter((var user) -> user.getName() != null && !user.getName().isBlank()) .map((var user) -> user.getName().strip().toUpperCase()) .filter((var name) -> name.length() >= 3 ) .collect(Collectors.toList()); CompletableFuture<List<String>> future = CompletableFuture.supplyAsync(() -> { return users.stream() .map((var user) -> "User: " + user.getName()) .collect(Collectors.toList()); }); System.out.println("Valid names: " + validNames); future.thenAccept(result -> System.out.println("Async result: " + result)); } @interface NonNull {} @SuppressWarnings("unused") public static void annotationExample () { Predicate<String> validator = (@NonNull var input) -> input != null && !input.isEmpty(); System.out.println("Validation result: " + validator.test("test" )); } static class User { private final String name; User(String name) { this .name = name; } public String getName () { return name; } } private static List<User> getUsers () { return List.of( new User ("Alice" ), new User ("Bob" ), new User (null ), new User (" Charlie " ), new User ("Diana" ) ); } }
Lambda var语法的优势 :
一致性 :与方法参数的var语法保持一致
注解支持 :可以在Lambda参数上使用注解
可读性 :在复杂类型推断时更清晰
现代化 :符合现代Java的语法风格
🗑️ 垃圾回收器革新:ZGC和Epsilon 1. ZGC:可扩展的低延迟垃圾回收器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 java -XX:+UseZGC \ -Xmx16g \ -Xms16g \ -XX:ZCollectionInterval=5 \ -XX:ZAllocationSpikeTolerance=2.0 \ com.example.App
2. Epsilon GC:用于性能测试 1 2 3 4 5 6 7 8 9 10 11 12 java -XX:+UseEpsilonGC \ -Xmx1g \ -XX:+PrintGCDetails \ com.example.App
📊 性能测试和对比 1. 字符串API性能对比 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class StringPerformanceTest { private static final String TEST_DATA = " \u2000Hello\u2001World\u2002 \nLine1\r\nLine2\rLine3 " ; private static final int ITERATIONS = 100000 ; public static void main (String[] args) { long startTime = System.nanoTime(); for (int i = 0 ; i < ITERATIONS; i++) { boolean result = TEST_DATA.isBlank(); } long endTime = System.nanoTime(); System.out.println("isBlank() time: " + (endTime - startTime) / 1_000_000 + "ms" ); startTime = System.nanoTime(); for (int i = 0 ; i < ITERATIONS; i++) { String result = TEST_DATA.strip(); } endTime = System.nanoTime(); System.out.println("strip() time: " + (endTime - startTime) / 1_000_000 + "ms" ); startTime = System.nanoTime(); for (int i = 0 ; i < ITERATIONS; i++) { long count = TEST_DATA.lines().count(); } endTime = System.nanoTime(); System.out.println("lines() time: " + (endTime - startTime) / 1_000_000 + "ms" ); } }
2. HTTP客户端性能测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public class HttpClientPerformanceTest { private static final HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .build(); public static void testHttpPerformance () throws Exception { String url = "https://httpbin.org/get" ; int requests = 100 ; long startTime = System.nanoTime(); List<CompletableFuture<HttpResponse<String>>> futures = new ArrayList <>(); for (int i = 0 ; i < requests; i++) { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .build(); CompletableFuture<HttpResponse<String>> future = httpClient .sendAsync(request, HttpResponse.BodyHandlers.ofString()); futures.add(future); } CompletableFuture.allOf(futures.toArray(new CompletableFuture [0 ])).join(); long endTime = System.nanoTime(); long totalTime = (endTime - startTime) / 1_000_000 ; System.out.println("Total time for " + requests + " requests: " + totalTime + "ms" ); System.out.println("Average time per request: " + (totalTime * 1.0 / requests) + "ms" ); System.out.println("Requests per second: " + (requests * 1000.0 / totalTime)); } }
🎯 Java 11变革总结 核心变革内容对比
特性
Java 10及之前
Java 11
改进程度
字符串API
基础操作
isBlank/lines/strip/repeat
📈 显著增强
HTTP客户端
预览版
正式标准化
✅ 稳定可用
文件操作
readAllBytes
readString/writeString
📝 大幅简化
集合API
基础toArray
泛型toArray方法
🔧 语法简化
Optional
基础方法
isEmpty()方法
🛡️ 更直观
Lambda参数
无var支持
var语法支持
🎯 语法一致
GC选择
G1为主
ZGC/Epsilon可选
⚡ 更多选择
为什么需要这些变革? 1. LTS版本的稳定性保证 :
8年支持周期,需要经过充分测试的功能
平衡创新与稳定的最佳选择
企业用户的首选版本
2. 开发者体验的持续提升 :
字符串处理是最常见的操作,需要更好支持
HTTP客户端需要标准化,成为核心API
文件操作需要简化,减少样板代码
3. 现代应用的需求 :
大堆内存应用需要ZGC
性能测试需要Epsilon GC
异步编程需要更好的HTTP支持
4. 生态系统的完善 :
移除过时的Java EE模块
统一JDK仓库
Unicode 10支持
相对于Java 10的优势 1. 字符串处理的革命 :
isBlank()、lines()、strip()、repeat()等实用方法
Unicode空白字符正确支持
性能优化和内存效率提升
2. 网络编程的标准化 :
HTTP客户端成为正式API
更好的异步支持和错误处理
WebSocket和文件操作支持
3. API设计的完善 :
Optional.isEmpty()更直观
集合toArray()方法简化
Lambda var语法一致性
4. 垃圾回收的选择丰富 :
ZGC满足大堆内存需求
Epsilon GC支持性能测试
运行时镜像优化启动速度
🚀 最佳实践指南 1. 字符串API的最佳实践 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class StringBestPractices { public static void modernStringProcessing () { String input = " \u2000Hello\u2001World\u2002 \nLine1\r\nLine2 " ; if (input.isBlank()) { System.out.println("Input is blank" ); return ; } String cleanInput = input.strip(); cleanInput.lines() .filter(line -> !line.isBlank()) .map(String::toUpperCase) .forEach(System.out::println); String separator = "=" .repeat(30 ); System.out.println(separator); } public static void legacyStringProcessing () { String input = " Hello World " ; if (input == null || input.trim().isEmpty()) { return ; } String[] lines = input.split("\\r?\\n" ); } }
2. HTTP客户端的最佳实践 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public class HttpClientBestPractices { private static final HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(10 )) .followRedirects(HttpClient.Redirect.NORMAL) .build(); public static HttpResponse<String> getWithRetry (String url, int maxRetries) { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("User-Agent" , "Java-11-App" ) .timeout(Duration.ofSeconds(5 )) .build(); for (int i = 0 ; i < maxRetries; i++) { try { HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 200 ) { return response; } if (i < maxRetries - 1 ) { Thread.sleep(1000 * (int ) Math.pow(2 , i)); } } catch (Exception e) { if (i == maxRetries - 1 ) { throw new RuntimeException ("HTTP request failed after " + maxRetries + " retries" , e); } } } throw new RuntimeException ("HTTP request failed" ); } public static CompletableFuture<String> asyncDataProcessing (String apiUrl, String fileUrl) { CompletableFuture<String> apiFuture = httpClient.sendAsync( HttpRequest.newBuilder().uri(URI.create(apiUrl)).build(), HttpResponse.BodyHandlers.ofString() ).thenApply(HttpResponse::body); CompletableFuture<String> fileFuture = httpClient.sendAsync( HttpRequest.newBuilder().uri(URI.create(fileUrl)).build(), HttpResponse.BodyHandlers.ofString() ).thenApply(HttpResponse::body); return apiFuture.thenCombine(fileFuture, (apiData, fileData) -> { return "API: " + apiData.length() + " chars, File: " + fileData.length() + " chars" ; }); } }
3. 文件操作的最佳实践 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public class FileOperationsBestPractices { public static void modernFileOperations () throws IOException { Path configPath = Paths.get("config.properties" ); Path logPath = Paths.get("app.log" ); if (Files.exists(configPath)) { String config = Files.readString(configPath, StandardCharsets.UTF_8); System.out.println("Config loaded: " + config.length() + " chars" ); } else { Map<String, String> defaultConfig = Map.of( "app.name" , "MyApp" , "app.version" , "1.0" , "app.debug" , "false" ); String configContent = defaultConfig.entrySet().stream() .map(entry -> entry.getKey() + "=" + entry.getValue()) .collect(Collectors.joining("\n" )); Files.writeString(configPath, configContent, StandardCharsets.UTF_8); } String logEntry = String.format("[%s] Operation completed%n" , LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); Files.writeString(logPath, logEntry, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND); } public static void temporaryFileHandling () throws IOException { Path tempDir = Files.createTempDirectory("myapp" ); try { Path tempFile = Files.createTempFile(tempDir, "data" , ".tmp" ); Files.writeString(tempFile, "Temporary data" ); String content = Files.readString(tempFile); System.out.println("Temp file content: " + content); Files.delete(tempFile); } finally { try (Stream<Path> paths = Files.walk(tempDir)) { paths.sorted(Comparator.reverseOrder()) .forEach(path -> { try { Files.delete(path); } catch (IOException e) { System.err.println("Failed to delete: " + path); } }); } } } }
4. Optional增强的使用建议 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public class OptionalEnhancementBestPractices { public static void modernOptionalUsage () { Optional<String> result = getUserInput(); if (result.isEmpty()) { System.out.println("No input provided" ); } else { System.out.println("Input: " + result.get()); } String processed = result .filter(input -> !input.isBlank()) .map(String::strip) .map(String::toLowerCase) .orElse("default" ); System.out.println("Processed: " + processed); } public static void stringOptionalCombination () { List<Optional<String>> inputs = Arrays.asList( Optional.of(" Hello " ), Optional.empty(), Optional.of("" ), Optional.of(" World " ) ); List<String> validInputs = inputs.stream() .filter(Optional::isPresent) .map(Optional::get) .filter(input -> !input.isBlank()) .map(String::strip) .map(String::toUpperCase) .collect(Collectors.toList()); System.out.println("Valid inputs: " + validInputs); } public static void errorHandlingBestPractices () { Optional<String> configValue = readConfig("timeout" ); int timeout = configValue .filter(value -> !value.isBlank()) .map(String::strip) .filter(value -> value.matches("\\d+" )) .map(Integer::parseInt) .filter(timeout -> timeout > 0 && timeout <= 300 ) .orElse(30 ); System.out.println("Timeout: " + timeout + " seconds" ); } private static Optional<String> getUserInput () { return Math.random() > 0.5 ? Optional.of(" Hello World " ) : Optional.empty(); } private static Optional<String> readConfig (String key) { return "timeout" .equals(key) ? Optional.of("60" ) : Optional.empty(); } }
🎉 结语 Java 11作为Oracle发布周期改革后的第一个LTS版本,成功地找到了功能创新与平台稳定的完美平衡。通过字符串API的全面增强、HTTP客户端的标准化、文件操作的简化以及ZGC等重要特性,Java 11不仅提升了开发者的编程体验,更为现代Java应用的开发和部署奠定了坚实的基础。
字符串API的革命性改进 :isBlank()、lines()、strip()、repeat()等方法让字符串处理变得更加简单和高效。
HTTP客户端的标准化 :成为Java标准库的一部分,提供了现代化的网络通信能力,支持HTTP/2、异步处理和WebSocket。
文件操作的简化 :readString()和writeString()方法大幅减少了文件处理的样板代码。
Optional的增强 :isEmpty()方法让空值处理更加直观和一致。
Java 11的发布,不仅是技术上的进步,更是Oracle对Java生态系统长期承诺的体现。作为LTS版本,Java 11将在未来8年内为企业级应用提供稳定的支持,同时为后续版本的现代化改进提供了宝贵的经验。
在学习和使用Java 11的过程中,建议大家重点关注以下几个方面 :
字符串API :掌握isBlank、lines、strip、repeat等方法的正确使用
HTTP客户端 :学习异步编程和错误处理的最佳实践
文件操作 :利用readString和writeString简化文件处理
Optional增强 :使用isEmpty()提高代码可读性
ZGC调优 :根据应用特点优化垃圾回收性能
Java 11的学习虽然需要适应一些新的API和概念,但它带来的收益是值得的。掌握了这些新特性,你将能够编写出更加现代化、高效和可维护的Java代码!
Happy Coding with Java 11! 🎊