✦ 112 个现代模式 · Java 8 → Java 25

Java 已进化。
您的代码也可以。

现代 Java 代码片段集合。每个旧 Java 模式与其简洁的现代替代方案并排展示。

✕ 旧版
public class Point {
    private final int x, y;
    public Point(int x, int y) { ... }
    public int getX() { return x; }
    public int getY() { return y; }
    // equals, hashCode, toString
}
✓ 现代
public record Point(int x, int y) {}
分享 𝕏 🦋 in
🤖
使用 GitHub Copilot 现代化您的 Java 代码库。 让 Copilot 帮您自动将遗留模式迁移到现代 Java。

所有对比

112 个代码片段
显示:
Language

紧凑规范构造函数

旧版 public record Person(String name, List<String> pets) { // Full canonical constructor public Person(String name, List<String> pets) { Objects.requireNonNull(name); this.name = name; this.pets = List.copyOf(pets); } }
现代 public record Person(String name, List<String> pets) { // Compact constructor public Person { Objects.requireNonNull(name); pets = List.copyOf(pets); } }
悬停查看现代版 →
Language

紧凑源文件

旧版 public class HelloWorld { public static void main(String[] args) { System.out.println( "Hello, World!"); } }
现代 void main() { IO.println("Hello, World!"); }
悬停查看现代版 →
Language

接口默认方法

旧版 // Need abstract class to share behavior public abstract class AbstractLogger { public void log(String msg) { System.out.println( timestamp() + ": " + msg); } abstract String timestamp(); } // Single inheritance only public class FileLogger extends AbstractLogger { ... }
现代 public interface Logger { default void log(String msg) { IO.println( timestamp() + ": " + msg); } String timestamp(); } // Multiple interfaces allowed public class FileLogger implements Logger, Closeable { ... }
悬停查看现代版 →
Language

匿名类的菱形运算符

旧版 Map<String, List<String>> map = new HashMap<String, List<String>>(); // anonymous class: no diamond Predicate<String> p = new Predicate<String>() { public boolean test(String s) {..} };
现代 Map<String, List<String>> map = new HashMap<>(); // Java 9: diamond with anonymous classes Predicate<String> p = new Predicate<>() { public boolean test(String s) {..} };
悬停查看现代版 →
Language

无 default 的穷举 switch

旧版 // Must add default even though // all cases are covered double area(Shape s) { if (s instanceof Circle c) return Math.PI * c.r() * c.r(); else if (s instanceof Rect r) return r.w() * r.h(); else throw new IAE(); }
现代 // sealed Shape permits Circle, Rect double area(Shape s) { return switch (s) { case Circle c -> Math.PI * c.r() * c.r(); case Rect r -> r.w() * r.h(); }; // no default needed! }
悬停查看现代版 →
Language

灵活的构造函数体

旧版 class Square extends Shape { Square(double side) { super(side, side); // can't validate BEFORE super! if (side <= 0) throw new IAE("bad"); } }
现代 class Square extends Shape { Square(double side) { if (side <= 0) throw new IAE("bad"); super(side, side); } }
悬停查看现代版 →
Language

带 when 的守卫模式

旧版 if (shape instanceof Circle c) { if (c.radius() > 10) { return "large circle"; } else { return "small circle"; } } else { return "not a circle"; }
现代 return switch (shape) { case Circle c when c.radius() > 10 -> "large circle"; case Circle c -> "small circle"; default -> "not a circle"; };
悬停查看现代版 →
Language

Javadoc 注释中的 Markdown

旧版 /** * Returns the {@code User} with * the given ID. * * <p>Example: * <pre>{@code * var user = findUser(123); * }</pre> * * @param id the user ID * @return the user */ public User findUser(int id) { ... }
现代 /// Returns the `User` with /// the given ID. /// /// Example: /// ```java /// var user = findUser(123); /// ``` /// /// @param id the user ID /// @return the user public User findUser(int id) { ... }
悬停查看现代版 →
Language

模块导入声明

旧版 import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path;
现代 import module java.base; // All of java.util, java.io, java.nio // etc. available in one line
悬停查看现代版 →
Language

instanceof 的模式匹配

旧版 if (obj instanceof String) { String s = (String) obj; System.out.println(s.length()); }
现代 if (obj instanceof String s) { IO.println(s.length()); }
悬停查看现代版 →
Language

switch 中的模式匹配

旧版 String format(Object obj) { if (obj instanceof Integer i) return "int: " + i; else if (obj instanceof Double d) return "double: " + d; else if (obj instanceof String s) return "str: " + s; return "unknown"; }
现代 String format(Object obj) { return switch (obj) { case Integer i -> "int: " + i; case Double d -> "double: " + d; case String s -> "str: " + s; default -> "unknown"; }; }
悬停查看现代版 →
Language

模式中的原始类型

旧版 String classify(int code) { if (code >= 200 && code < 300) return "success"; else if (code >= 400 && code < 500) return "client error"; else return "other"; }
现代 String classify(int code) { return switch (code) { case int c when c >= 200 && c < 300 -> "success"; case int c when c >= 400 && c < 500 -> "client error"; default -> "other"; }; }
悬停查看现代版 →
Language

接口私有方法

旧版 interface Logger { default void logInfo(String msg) { System.out.println( "[INFO] " + timestamp() + msg); } default void logWarn(String msg) { System.out.println( "[WARN] " + timestamp() + msg); } }
现代 interface Logger { private String format(String lvl, String msg) { return "[" + lvl + "] " + timestamp() + msg; } default void logInfo(String msg) { IO.println(format("INFO", msg)); } default void logWarn(String msg) { IO.println(format("WARN", msg)); } }
悬停查看现代版 →
Language

record 模式(解构)

旧版 if (obj instanceof Point) { Point p = (Point) obj; int x = p.getX(); int y = p.getY(); System.out.println(x + y); }
现代 if (obj instanceof Point(int x, int y)) { IO.println(x + y); }
悬停查看现代版 →
Language

用 record 定义数据类

旧版 public class Point { private final int x, y; public Point(int x, int y) { ... } public int getX() { return x; } public int getY() { return y; } // equals, hashCode, toString }
现代 public record Point(int x, int y) {}
悬停查看现代版 →
Language

用密封类定义类型层次

旧版 // Anyone can extend Shape public abstract class Shape { } public class Circle extends Shape { } public class Rect extends Shape { } // unknown subclasses possible
现代 public sealed interface Shape permits Circle, Rect {} public record Circle(double r) implements Shape {} public record Rect(double w, double h) implements Shape {}
悬停查看现代版 →
Language

内部类中的静态成员

旧版 class Library { // Must be static nested class static class Book { static int globalBookCount; Book() { globalBookCount++; } } } // Usage var book = new Library.Book();
现代 class Library { // Can be inner class with statics class Book { static int globalBookCount; Book() { Book.globalBookCount++; } } } // Usage var lib = new Library(); var book = lib.new Book();
悬停查看现代版 →
Language

接口中的静态方法

旧版 // Separate utility class needed public class ValidatorUtils { public static boolean isBlank( String s) { return s == null || s.trim().isEmpty(); } } // Usage if (ValidatorUtils.isBlank(input)) { ... }
现代 public interface Validator { boolean validate(String s); static boolean isBlank(String s) { return s == null || s.trim().isEmpty(); } } // Usage if (Validator.isBlank(input)) { ... }
悬停查看现代版 →
Language

switch 表达式

旧版 String msg; switch (day) { case MONDAY: msg = "Start"; break; case FRIDAY: msg = "End"; break; default: msg = "Mid"; }
现代 String msg = switch (day) { case MONDAY -> "Start"; case FRIDAY -> "End"; default -> "Mid"; };
悬停查看现代版 →
Language

多行字符串文本块

旧版 String json = "{\n" + " \"name\": \"Duke\",\n" + " \"age\": 30\n" + "}";
现代 String json = """ { "name": "Duke", "age": 30 }""";
悬停查看现代版 →
Language

使用 var 进行类型推断

旧版 Map<String, List<Integer>> map = new HashMap<String, List<Integer>>(); for (Map.Entry<String, List<Integer>> e : map.entrySet()) { // verbose type noise }
现代 var map = new HashMap<String, List<Integer>>(); for (var entry : map.entrySet()) { // clean and readable }
悬停查看现代版 →
Language

用 _ 表示未命名变量

旧版 try { parse(input); } catch (Exception ignored) { log("parse failed"); } map.forEach((key, value) -> { process(value); // key unused });
现代 try { parse(input); } catch (Exception _) { log("parse failed"); } map.forEach((_, value) -> { process(value); });
悬停查看现代版 →
Collections

Collectors.teeing()

旧版 long count = items.stream().count(); double sum = items.stream() .mapToDouble(Item::price) .sum(); var result = new Stats(count, sum);
现代 var result = items.stream().collect( Collectors.teeing( Collectors.counting(), Collectors.summingDouble(Item::price), Stats::new ) );
悬停查看现代版 →
Collections

不可变地复制集合

旧版 List<String> copy = Collections.unmodifiableList( new ArrayList<>(original) );
现代 List<String> copy = List.copyOf(original);
悬停查看现代版 →
Collections

创建不可变列表

旧版 List<String> list = Collections.unmodifiableList( new ArrayList<>( Arrays.asList("a", "b", "c") ) );
现代 List<String> list = List.of("a", "b", "c");
悬停查看现代版 →
Collections

创建不可变 Map

旧版 Map<String, Integer> map = new HashMap<>(); map.put("a", 1); map.put("b", 2); map.put("c", 3); map = Collections.unmodifiableMap(map);
现代 Map<String, Integer> map = Map.of("a", 1, "b", 2, "c", 3);
悬停查看现代版 →
Collections

创建不可变 Set

旧版 Set<String> set = Collections.unmodifiableSet( new HashSet<>( Arrays.asList("a", "b", "c") ) );
现代 Set<String> set = Set.of("a", "b", "c");
悬停查看现代版 →
Collections

Map.entry() 工厂方法

旧版 Map.Entry<String, Integer> e = new AbstractMap.SimpleEntry<>( "key", 42 );
现代 var e = Map.entry("key", 42);
悬停查看现代版 →
Collections

反向列表迭代

旧版 for (ListIterator<String> it = list.listIterator(list.size()); it.hasPrevious(); ) { String element = it.previous(); System.out.println(element); }
现代 for (String element : list.reversed()) { IO.println(element); }
悬停查看现代版 →
Collections

有序集合

旧版 // Get last element var last = list.get(list.size() - 1); // Get first var first = list.get(0); // Reverse iteration: manual
现代 var last = list.getLast(); var first = list.getFirst(); var reversed = list.reversed();
悬停查看现代版 →
Collections

类型化流 toArray

旧版 List<String> list = getNames(); String[] arr = new String[list.size()]; for (int i = 0; i < list.size(); i++) { arr[i] = list.get(i); }
现代 String[] arr = getNames().stream() .filter(n -> n.length() > 3) .toArray(String[]::new);
悬停查看现代版 →
Collections

不可修改收集器

旧版 List<String> list = stream.collect( Collectors.collectingAndThen( Collectors.toList(), Collections::unmodifiableList ) );
现代 List<String> list = stream.toList();
悬停查看现代版 →
Strings

字符串字符流

旧版 for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (Character.isDigit(c)) { process(c); } }
现代 str.chars() .filter(Character::isDigit) .forEach(c -> process((char) c));
悬停查看现代版 →
Strings

String.formatted()

旧版 String msg = String.format( "Hello %s, you are %d", name, age );
现代 String msg = "Hello %s, you are %d" .formatted(name, age);
悬停查看现代版 →
Strings

String.indent() 和 transform()

旧版 String[] lines = text.split("\n"); StringBuilder sb = new StringBuilder(); for (String line : lines) { sb.append(" ").append(line) .append("\n"); } String indented = sb.toString();
现代 String indented = text.indent(4); String result = text .transform(String::strip) .transform(s -> s.replace(" ", "-"));
悬停查看现代版 →
Strings

String.isBlank()

旧版 boolean blank = str.trim().isEmpty(); // or: str.trim().length() == 0
现代 boolean blank = str.isBlank(); // handles Unicode whitespace too
悬停查看现代版 →
Strings

用 String.lines() 分割行

旧版 String text = "one\ntwo\nthree"; String[] lines = text.split("\n"); for (String line : lines) { System.out.println(line); }
现代 String text = "one\ntwo\nthree"; text.lines().forEach(IO::println);
悬停查看现代版 →
Strings

String.repeat()

旧版 StringBuilder sb = new StringBuilder(); for (int i = 0; i < 3; i++) { sb.append("abc"); } String result = sb.toString();
现代 String result = "abc".repeat(3); // "abcabcabc"
悬停查看现代版 →
Strings

String.strip() 与 trim()

旧版 // trim() only removes ASCII whitespace // (chars <= U+0020) String clean = str.trim();
现代 // strip() removes all Unicode whitespace String clean = str.strip(); String left = str.stripLeading(); String right = str.stripTrailing();
悬停查看现代版 →
Streams

Collectors.flatMapping()

旧版 // Flatten within a grouping collector // Required complex custom collector Map<String, Set<String>> tagsByDept = // no clean way in Java 8
现代 var tagsByDept = employees.stream() .collect(groupingBy( Emp::dept, flatMapping( e -> e.tags().stream(), toSet() ) ));
悬停查看现代版 →
Streams

Optional.ifPresentOrElse()

旧版 Optional<User> user = findUser(id); if (user.isPresent()) { greet(user.get()); } else { handleMissing(); }
现代 findUser(id).ifPresentOrElse( this::greet, this::handleMissing );
悬停查看现代版 →
Streams

Optional.or() 回退

旧版 Optional<Config> cfg = primary(); if (!cfg.isPresent()) { cfg = secondary(); } if (!cfg.isPresent()) { cfg = defaults(); }
现代 Optional<Config> cfg = primary() .or(this::secondary) .or(this::defaults);
悬停查看现代版 →
Streams

用 Predicate.not() 进行否定

旧版 List<String> nonEmpty = list.stream() .filter(s -> !s.isBlank()) .collect(Collectors.toList());
现代 List<String> nonEmpty = list.stream() .filter(Predicate.not(String::isBlank)) .toList();
悬停查看现代版 →
Streams

流 Gatherer

旧版 // Sliding window: manual implementation List<List<T>> windows = new ArrayList<>(); for (int i = 0; i <= list.size()-3; i++) { windows.add( list.subList(i, i + 3)); }
现代 var windows = stream .gather( Gatherers.windowSliding(3) ) .toList();
悬停查看现代版 →
Streams

带谓词的 Stream.iterate()

旧版 Stream.iterate(1, n -> n * 2) .limit(10) .forEach(System.out::println); // can't stop at a condition
现代 Stream.iterate( 1, n -> n < 1000, n -> n * 2 ).forEach(IO::println); // stops when n >= 1000
悬停查看现代版 →
Streams

Stream.mapMulti()

旧版 stream.flatMap(order -> order.items().stream() .map(item -> new OrderItem( order.id(), item) ) );
现代 stream.<OrderItem>mapMulti( (order, downstream) -> { for (var item : order.items()) downstream.accept( new OrderItem(order.id(), item)); } );
悬停查看现代版 →
Streams

Stream.ofNullable()

旧版 Stream<String> s = val != null ? Stream.of(val) : Stream.empty();
现代 Stream<String> s = Stream.ofNullable(val);
悬停查看现代版 →
Streams

流的 takeWhile / dropWhile

旧版 List<Integer> result = new ArrayList<>(); for (int n : sorted) { if (n >= 100) break; result.add(n); } // no stream equivalent in Java 8
现代 var result = sorted.stream() .takeWhile(n -> n < 100) .toList(); // or: .dropWhile(n -> n < 10)
悬停查看现代版 →
Streams

Stream.toList()

旧版 List<String> result = stream .filter(s -> s.length() > 3) .collect(Collectors.toList());
现代 List<String> result = stream .filter(s -> s.length() > 3) .toList();
悬停查看现代版 →
Streams

虚拟线程执行器

旧版 ExecutorService exec = Executors.newFixedThreadPool(10); try { futures = tasks.stream() .map(t -> exec.submit(t)) .toList(); } finally { exec.shutdown(); }
现代 try (var exec = Executors .newVirtualThreadPerTaskExecutor()) { var futures = tasks.stream() .map(exec::submit) .toList(); }
悬停查看现代版 →
Concurrency

CompletableFuture 链式调用

旧版 Future<String> future = executor.submit(this::fetchData); String data = future.get(); // blocks String result = transform(data);
现代 CompletableFuture.supplyAsync( this::fetchData ) .thenApply(this::transform) .thenAccept(IO::println);
悬停查看现代版 →
Concurrency

使用虚拟线程进行并发 HTTP 请求

旧版 ExecutorService pool = Executors.newFixedThreadPool(10); List<Future<String>> futures = urls.stream() .map(u -> pool.submit( () -> fetchUrl(u))) .toList(); // manual shutdown, blocking get()
现代 try (var exec = Executors .newVirtualThreadPerTaskExecutor()) { var results = urls.stream() .map(u -> exec.submit( () -> client.send(req(u), ofString()).body())) .toList().stream() .map(Future::join).toList(); }
悬停查看现代版 →
Concurrency

ExecutorService 自动关闭

旧版 ExecutorService exec = Executors.newCachedThreadPool(); try { exec.submit(task); } finally { exec.shutdown(); exec.awaitTermination( 1, TimeUnit.MINUTES); }
现代 try (var exec = Executors.newCachedThreadPool()) { exec.submit(task); } // auto shutdown + await on close
悬停查看现代版 →
Concurrency

无锁延迟初始化

旧版 class Config { private static volatile Config inst; static Config get() { if (inst == null) { synchronized (Config.class) { if (inst == null) inst = load(); } } return inst; } }
现代 class Config { private static final StableValue<Config> INST = StableValue.of(Config::load); static Config get() { return INST.get(); } }
悬停查看现代版 →
Concurrency

现代 Process API

旧版 Process p = Runtime.getRuntime() .exec("ls -la"); int code = p.waitFor(); // no way to get PID // no easy process info
现代 ProcessHandle ph = ProcessHandle.current(); long pid = ph.pid(); ph.info().command() .ifPresent(IO::println); ph.children().forEach( c -> IO.println(c.pid()));
悬停查看现代版 →
Concurrency

作用域值

旧版 static final ThreadLocal<User> CURRENT = new ThreadLocal<>(); void handle(Request req) { CURRENT.set(authenticate(req)); try { process(); } finally { CURRENT.remove(); } }
现代 static final ScopedValue<User> CURRENT = ScopedValue.newInstance(); void handle(Request req) { ScopedValue.where(CURRENT, authenticate(req) ).run(this::process); }
悬停查看现代版 →
Concurrency

稳定值

旧版 private volatile Logger logger; Logger getLogger() { if (logger == null) { synchronized (this) { if (logger == null) logger = createLogger(); } } return logger; }
现代 private final StableValue<Logger> logger = StableValue.of(this::createLogger); Logger getLogger() { return logger.get(); }
悬停查看现代版 →
Concurrency

结构化并发

旧版 ExecutorService exec = Executors.newFixedThreadPool(2); Future<User> u = exec.submit(this::fetchUser); Future<Order> o = exec.submit(this::fetchOrder); try { return combine(u.get(), o.get()); } finally { exec.shutdown(); }
现代 try (var scope = new StructuredTaskScope .ShutdownOnFailure()) { var u = scope.fork(this::fetchUser); var o = scope.fork(this::fetchOrder); scope.join().throwIfFailed(); return combine(u.get(), o.get()); }
悬停查看现代版 →
Concurrency

使用 Duration 的 Thread.sleep

旧版 // What unit is 5000? ms? us? Thread.sleep(5000); // 2.5 seconds: math required Thread.sleep(2500);
现代 Thread.sleep( Duration.ofSeconds(5) ); Thread.sleep( Duration.ofMillis(2500) );
悬停查看现代版 →
Concurrency

虚拟线程

旧版 Thread thread = new Thread(() -> { System.out.println("hello"); }); thread.start(); thread.join();
现代 Thread.startVirtualThread(() -> { IO.println("hello"); }).join();
悬停查看现代版 →
I/O

反序列化过滤器

旧版 // Dangerous: accepts any class ObjectInputStream ois = new ObjectInputStream(input); Object obj = ois.readObject(); // deserialization attacks possible!
现代 ObjectInputFilter filter = ObjectInputFilter.Config .createFilter( "com.myapp.*;!*" ); ois.setObjectInputFilter(filter); Object obj = ois.readObject();
悬停查看现代版 →
I/O

文件内存映射

旧版 try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE)) { MappedByteBuffer buffer = channel.map( FileChannel.MapMode.READ_WRITE, 0, (int) channel.size()); // Limited to 2GB // Freed by GC, no control }
现代 FileChannel channel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE); try (Arena arena = Arena.ofShared()) { MemorySegment segment = channel.map( FileChannel.MapMode.READ_WRITE, 0, channel.size(), arena); // No size limit // ... } // Deterministic cleanup
悬停查看现代版 →
I/O

Files.mismatch()

旧版 // Compare two files byte by byte byte[] f1 = Files.readAllBytes(path1); byte[] f2 = Files.readAllBytes(path2); boolean equal = Arrays.equals(f1, f2); // loads both files entirely into memory
现代 long pos = Files.mismatch(path1, path2); // -1 if identical // otherwise: position of first difference
悬停查看现代版 →
I/O

现代 HTTP 客户端

旧版 URL url = new URL("https://api.com/data"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); // read lines, close streams...
现代 var client = HttpClient.newHttpClient(); var request = HttpRequest.newBuilder() .uri(URI.create("https://api.com/data")) .build(); var response = client.send( request, BodyHandlers.ofString()); String body = response.body();
悬停查看现代版 →
I/O

InputStream.transferTo()

旧版 byte[] buf = new byte[8192]; int n; while ((n = input.read(buf)) != -1) { output.write(buf, 0, n); }
现代 input.transferTo(output);
悬停查看现代版 →
I/O

用于控制台 I/O 的 IO 类

旧版 import java.util.Scanner; Scanner sc = new Scanner(System.in); System.out.print("Name: "); String name = sc.nextLine(); System.out.println("Hello, " + name); sc.close();
现代 String name = IO.readln("Name: "); IO.println("Hello, " + name);
悬停查看现代版 →
I/O

Path.of() 工厂方法

旧版 Path path = Paths.get("src", "main", "java", "App.java");
现代 var path = Path.of("src", "main", "java", "App.java");
悬停查看现代版 →
I/O

读取文件

旧版 StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader( new FileReader("data.txt"))) { String line; while ((line = br.readLine()) != null) sb.append(line).append("\n"); } String content = sb.toString();
现代 String content = Files.readString(Path.of("data.txt"));
悬停查看现代版 →
I/O

try-with-resources 改进

旧版 Connection conn = getConnection(); // Must re-declare in try try (Connection c = conn) { use(c); }
现代 Connection conn = getConnection(); // Use existing variable directly try (conn) { use(conn); }
悬停查看现代版 →
I/O

写入文件

旧版 try (FileWriter fw = new FileWriter("out.txt"); BufferedWriter bw = new BufferedWriter(fw)) { bw.write(content); }
现代 Files.writeString( Path.of("out.txt"), content );
悬停查看现代版 →
Errors

有帮助的 NullPointerException

旧版 // Old NPE message: // "NullPointerException" // at MyApp.main(MyApp.java:42) // Which variable was null?!
现代 // Modern NPE message: // Cannot invoke "String.length()" // because "user.address().city()" // is null // Exact variable identified!
悬停查看现代版 →
Errors

多异常捕获

旧版 try { process(); } catch (IOException e) { log(e); } catch (SQLException e) { log(e); } catch (ParseException e) { log(e); }
现代 try { process(); } catch (IOException | SQLException | ParseException e) { log(e); }
悬停查看现代版 →
Errors

switch 中的 null case

旧版 // Must check before switch if (status == null) { return "unknown"; } return switch (status) { case ACTIVE -> "active"; case PAUSED -> "paused"; default -> "other"; };
现代 return switch (status) { case null -> "unknown"; case ACTIVE -> "active"; case PAUSED -> "paused"; default -> "other"; };
悬停查看现代版 →
Errors

Optional 链式调用

旧版 String city = null; if (user != null) { Address addr = user.getAddress(); if (addr != null) { city = addr.getCity(); } } if (city == null) city = "Unknown";
现代 String city = Optional.ofNullable(user) .map(User::address) .map(Address::city) .orElse("Unknown");
悬停查看现代版 →
Errors

无 supplier 的 Optional.orElseThrow()

旧版 // Risky: get() throws if empty, no clear intent String value = optional.get(); // Verbose: supplier just for NoSuchElementException String value = optional .orElseThrow(NoSuchElementException::new);
现代 // Clear intent: throws NoSuchElementException if empty String value = optional.orElseThrow();
悬停查看现代版 →
Errors

基于 record 的错误响应

旧版 // Verbose error class public class ErrorResponse { private final int code; private final String message; // constructor, getters, equals, // hashCode, toString... }
现代 public record ApiError( int code, String message, Instant timestamp ) { public ApiError(int code, String msg) { this(code, msg, Instant.now()); } }
悬停查看现代版 →
Errors

Objects.requireNonNullElse()

旧版 String name = input != null ? input : "default"; // easy to get the order wrong
现代 String name = Objects .requireNonNullElse( input, "default" );
悬停查看现代版 →
Date/Time

日期格式化

旧版 // Not thread-safe! SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String formatted = sdf.format(date); // Must synchronize for concurrent use
现代 DateTimeFormatter fmt = DateTimeFormatter.ofPattern( "uuuu-MM-dd"); String formatted = LocalDate.now().format(fmt); // Thread-safe, immutable
悬停查看现代版 →
Date/Time

Duration 和 Period

旧版 // How many days between two dates? long diff = date2.getTime() - date1.getTime(); long days = diff / (1000 * 60 * 60 * 24); // ignores DST, leap seconds
现代 long days = ChronoUnit.DAYS .between(date1, date2); Period period = Period.between( date1, date2); Duration elapsed = Duration.between( time1, time2);
悬停查看现代版 →
Date/Time

HexFormat

旧版 // Pad to 2 digits, uppercase String hex = String.format( "%02X", byteValue); // Parse hex string int val = Integer.parseInt( "FF", 16);
现代 var hex = HexFormat.of() .withUpperCase(); String s = hex.toHexDigits( byteValue); byte[] bytes = hex.parseHex("48656C6C6F");
悬停查看现代版 →
Date/Time

纳秒精度的 Instant

旧版 // Millisecond precision only long millis = System.currentTimeMillis(); // 1708012345678
现代 // Microsecond/nanosecond precision Instant now = Instant.now(); // 2025-02-15T20:12:25.678901234Z long nanos = now.getNano();
悬停查看现代版 →
Date/Time

java.time API 基础

旧版 // Mutable, confusing, zero-indexed months Calendar cal = Calendar.getInstance(); cal.set(2025, 0, 15); // January = 0! Date date = cal.getTime(); // not thread-safe
现代 LocalDate date = LocalDate.of( 2025, Month.JANUARY, 15); LocalTime time = LocalTime.of(14, 30); Instant now = Instant.now(); // immutable, thread-safe
悬停查看现代版 →
Date/Time

Math.clamp()

旧版 // Clamp value between min and max int clamped = Math.min(Math.max(value, 0), 100); // or: min and max order confusion
现代 int clamped = Math.clamp(value, 0, 100); // value constrained to [0, 100]
悬停查看现代版 →
Security

密钥派生函数

旧版 SecretKeyFactory factory = SecretKeyFactory.getInstance( "PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec( password, salt, 10000, 256); SecretKey key = factory.generateSecret(spec);
现代 var kdf = KDF.getInstance("HKDF-SHA256"); SecretKey key = kdf.deriveKey( "AES", KDF.HKDFParameterSpec .ofExtract() .addIKM(inputKey) .addSalt(salt) .thenExpand(info, 32) .build() );
悬停查看现代版 →
Security

PEM 编码/解码

旧版 String pem = "-----BEGIN CERTIFICATE-----\n" + Base64.getMimeEncoder() .encodeToString( cert.getEncoded()) + "\n-----END CERTIFICATE-----";
现代 // Encode to PEM String pem = PEMEncoder.of() .encodeToString(cert); // Decode from PEM var cert = PEMDecoder.of() .decode(pemString);
悬停查看现代版 →
Security

RandomGenerator 接口

旧版 // Hard-coded to one algorithm Random rng = new Random(); int value = rng.nextInt(100); // Or thread-local, but still locked in int value = ThreadLocalRandom.current() .nextInt(100);
现代 // Algorithm-agnostic via factory var rng = RandomGenerator.of("L64X128MixRandom"); int value = rng.nextInt(100); // Or get a splittable generator var rng = RandomGeneratorFactory .of("L64X128MixRandom").create();
悬停查看现代版 →
Security

强随机数生成

旧版 // Default algorithm — may not be // the strongest available SecureRandom random = new SecureRandom(); byte[] bytes = new byte[32]; random.nextBytes(bytes);
现代 // Platform's strongest algorithm SecureRandom random = SecureRandom.getInstanceStrong(); byte[] bytes = new byte[32]; random.nextBytes(bytes);
悬停查看现代版 →
Security

默认 TLS 1.3

旧版 SSLContext ctx = SSLContext.getInstance("TLSv1.2"); ctx.init(null, trustManagers, null); SSLSocketFactory factory = ctx.getSocketFactory(); // Must specify protocol version
现代 // TLS 1.3 is the default! var client = HttpClient.newBuilder() .sslContext(SSLContext.getDefault()) .build(); // Already using TLS 1.3
悬停查看现代版 →
Tooling

AOT 类预加载

旧版 // Every startup: // - Load 10,000+ classes // - Verify bytecode // - JIT compile hot paths // Startup: 2-5 seconds
现代 // Training run: $ java -XX:AOTCacheOutput=app.aot \ -cp app.jar com.App // Production: $ java -XX:AOTCache=app.aot \ -cp app.jar com.App
悬停查看现代版 →
Tooling

内置 HTTP 服务器

旧版 // Install and configure a web server // (Apache, Nginx, or embedded Jetty) // Or write boilerplate with com.sun.net.httpserver HttpServer server = HttpServer.create( new InetSocketAddress(8080), 0); server.createContext("/", exchange -> { ... }); server.start();
现代 // Terminal: serve current directory $ jwebserver // Or use the API (JDK 18+) var server = SimpleFileServer.createFileServer( new InetSocketAddress(8080), Path.of("."), OutputLevel.VERBOSE); server.start();
悬停查看现代版 →
Tooling

紧凑对象头

旧版 // Default: 128-bit object header // = 16 bytes overhead per object // A boolean field object = 32 bytes! // Mark word (64) + Klass pointer (64)
现代 // -XX:+UseCompactObjectHeaders // 64-bit object header // = 8 bytes overhead per object // 50% less header memory // More objects fit in cache
悬停查看现代版 →
Tooling

用 JFR 进行性能分析

旧版 // Install VisualVM / YourKit / JProfiler // Attach to running process // Configure sampling // Export and analyze // External tool required
现代 // Start with profiling enabled $ java -XX:StartFlightRecording= filename=rec.jfr MyApp // Or attach to running app: $ jcmd <pid> JFR.start
悬停查看现代版 →
Tooling

用 JShell 进行原型开发

旧版 // 1. Create Test.java // 2. javac Test.java // 3. java Test // Just to test one expression!
现代 $ jshell jshell> "hello".chars().count() $1 ==> 5 jshell> List.of(1,2,3).reversed() $2 ==> [3, 2, 1]
悬停查看现代版 →
Tooling

使用 JSpecify null 安全的 JUnit 6

旧版 import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; class UserServiceTest { // JUnit 5: no null contracts on the API // Can assertEquals() accept null? Check source... // Does fail(String) allow null message? Unknown. @Test void findUser_found() { // Is result nullable? API doesn't say User result = service.findById("u1"); assertNotNull(result); assertEquals("Alice", result.name()); } @Test void findUser_notFound() { // Hope this returns null, not throws... assertNull(service.findById("missing")); } }
现代 import org.junit.jupiter.api.Test; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import static org.junit.jupiter.api.Assertions.*; @NullMarked // all refs non-null unless @Nullable class UserServiceTest { // JUnit 6 API is @NullMarked: // assertNull(@Nullable Object actual) // assertEquals(@Nullable Object, @Nullable Object) // fail(@Nullable String message) @Test void findUser_found() { // IDE warns: findById returns @Nullable User @Nullable User result = service.findById("u1"); assertNotNull(result); // narrows type to non-null assertEquals("Alice", result.name()); // safe } @Test void findUser_notFound() { @Nullable User result = service.findById("missing"); assertNull(result); // IDE confirms null expectation } }
悬停查看现代版 →
Tooling

多文件源代码启动器

旧版 $ javac *.java $ java Main // Must compile all files first // Need a build tool for dependencies
现代 $ java Main.java // Automatically finds and compiles // other source files referenced // by Main.java
悬停查看现代版 →
Tooling

单文件执行

旧版 $ javac HelloWorld.java $ java HelloWorld // Two steps every time
现代 $ java HelloWorld.java // Compiles and runs in one step // Also works with shebangs: #!/usr/bin/java --source 25
悬停查看现代版 →
Enterprise

EJB Timer 与 Jakarta 调度器

旧版 @Stateless public class ReportGenerator { @Resource TimerService timerService; @PostConstruct public void init() { timerService.createCalendarTimer( new ScheduleExpression() .hour("2").minute("0")); } @Timeout public void generateReport(Timer timer) { // runs every day at 02:00 buildDailyReport(); } }
现代 @ApplicationScoped public class ReportGenerator { @Resource ManagedScheduledExecutorService scheduler; @PostConstruct public void init() { scheduler.scheduleAtFixedRate( this::generateReport, 0, 24, TimeUnit.HOURS); } public void generateReport() { buildDailyReport(); } }
悬停查看现代版 →
Enterprise

EJB 与 CDI

旧版 @Stateless public class OrderEJB { @EJB private InventoryEJB inventory; public void placeOrder(Order order) { // container-managed transaction inventory.reserve(order.getItem()); } }
现代 @ApplicationScoped public class OrderService { @Inject private InventoryService inventory; @Transactional public void placeOrder(Order order) { inventory.reserve(order.getItem()); } }
悬停查看现代版 →
Enterprise

JDBC ResultSet 映射与 JPA Criteria API

旧版 String sql = "SELECT * FROM users" + " WHERE status = ? AND age > ?"; try (Connection con = ds.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { ps.setString(1, status); ps.setInt(2, minAge); ResultSet rs = ps.executeQuery(); List<User> users = new ArrayList<>(); while (rs.next()) { User u = new User(); u.setId(rs.getLong("id")); u.setName(rs.getString("name")); u.setAge(rs.getInt("age")); users.add(u); } }
现代 @PersistenceContext EntityManager em; public List<User> findActiveAboveAge( String status, int minAge) { var cb = em.getCriteriaBuilder(); var cq = cb.createQuery(User.class); var root = cq.from(User.class); cq.select(root).where( cb.equal(root.get("status"), status), cb.greaterThan(root.get("age"), minAge)); return em.createQuery(cq).getResultList(); }
悬停查看现代版 →
Enterprise

JDBC 与 jOOQ

旧版 String sql = "SELECT id, name, email FROM users " + "WHERE department = ? AND salary > ?"; try (Connection con = ds.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { ps.setString(1, department); ps.setBigDecimal(2, minSalary); ResultSet rs = ps.executeQuery(); List<User> result = new ArrayList<>(); while (rs.next()) { result.add(new User( rs.getLong("id"), rs.getString("name"), rs.getString("email"))); } return result; }
现代 DSLContext dsl = DSL.using(ds, SQLDialect.POSTGRES); return dsl .select(USERS.ID, USERS.NAME, USERS.EMAIL) .from(USERS) .where(USERS.DEPARTMENT.eq(department) .and(USERS.SALARY.gt(minSalary))) .fetchInto(User.class);
悬停查看现代版 →
Enterprise

JDBC 与 JPA

旧版 String sql = "SELECT * FROM users WHERE id = ?"; try (Connection con = dataSource.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { ps.setLong(1, id); ResultSet rs = ps.executeQuery(); if (rs.next()) { User u = new User(); u.setId(rs.getLong("id")); u.setName(rs.getString("name")); } }
现代 @PersistenceContext EntityManager em; public User findUser(Long id) { return em.find(User.class, id); } public List<User> findByName(String name) { return em.createQuery( "SELECT u FROM User u WHERE u.name = :name", User.class) .setParameter("name", name) .getResultList(); }
悬停查看现代版 →
Enterprise

JNDI 查找与 CDI 注入

旧版 public class OrderService { private DataSource ds; public void init() throws NamingException { InitialContext ctx = new InitialContext(); ds = (DataSource) ctx.lookup( "java:comp/env/jdbc/OrderDB"); } public List<Order> findAll() throws SQLException { try (Connection con = ds.getConnection()) { // query orders } } }
现代 @ApplicationScoped public class OrderService { @Inject @Resource(name = "jdbc/OrderDB") DataSource ds; public List<Order> findAll() throws SQLException { try (Connection con = ds.getConnection()) { // query orders } } }
悬停查看现代版 →
Enterprise

JPA 与 Jakarta Data

旧版 @PersistenceContext EntityManager em; public User findById(Long id) { return em.find(User.class, id); } public List<User> findByName(String name) { return em.createQuery( "SELECT u FROM User u WHERE u.name = :name", User.class) .setParameter("name", name) .getResultList(); } public void save(User user) { em.persist(user); }
现代 @Repository public interface Users extends CrudRepository<User, Long> { List<User> findByName(String name); }
悬停查看现代版 →
Enterprise

JSF Managed Bean 与 CDI Named Bean

旧版 @ManagedBean @SessionScoped public class UserBean implements Serializable { @ManagedProperty("#{userService}") private UserService userService; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void setUserService(UserService svc) { this.userService = svc; } }
现代 @Named @SessionScoped public class UserBean implements Serializable { @Inject private UserService userService; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
悬停查看现代版 →
Enterprise

手动 JPA 事务与声明式 @Transactional

旧版 @PersistenceContext EntityManager em; public void transferFunds(Long from, Long to, BigDecimal amount) { EntityTransaction tx = em.getTransaction(); tx.begin(); try { Account src = em.find(Account.class, from); Account dst = em.find(Account.class, to); src.debit(amount); dst.credit(amount); tx.commit(); } catch (Exception e) { tx.rollback(); throw e; } }
现代 @ApplicationScoped public class AccountService { @PersistenceContext EntityManager em; @Transactional public void transferFunds(Long from, Long to, BigDecimal amount) { var src = em.find(Account.class, from); var dst = em.find(Account.class, to); src.debit(amount); dst.credit(amount); } }
悬停查看现代版 →
Enterprise

Message-Driven Bean 与 Reactive Messaging

旧版 @MessageDriven(activationConfig = { @ActivationConfigProperty( propertyName = "destinationType", propertyValue = "jakarta.jms.Queue"), @ActivationConfigProperty( propertyName = "destination", propertyValue = "java:/jms/OrderQueue") }) public class OrderMDB implements MessageListener { @Override public void onMessage(Message message) { TextMessage txt = (TextMessage) message; processOrder(txt.getText()); } }
现代 @ApplicationScoped public class OrderProcessor { @Incoming("orders") public void process(Order order) { // automatically deserialized from // the "orders" channel fulfillOrder(order); } }
悬停查看现代版 →
Enterprise

Servlet 与 JAX-RS

旧版 @WebServlet("/users") public class UserServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String id = req.getParameter("id"); res.setContentType("application/json"); res.getWriter().write("{\"id\":\"" + id + "\"}"); } }
现代 @Path("/users") public class UserResource { @GET @Produces(MediaType.APPLICATION_JSON) public Response getUser( @QueryParam("id") String id) { return Response.ok(new User(id)).build(); } }
悬停查看现代版 →
Enterprise

Singleton EJB 与 CDI @ApplicationScoped

旧版 @Singleton @Startup @ConcurrencyManagement( ConcurrencyManagementType.CONTAINER) public class ConfigCache { private Map<String, String> cache; @PostConstruct public void load() { cache = loadFromDatabase(); } @Lock(LockType.READ) public String get(String key) { return cache.get(key); } @Lock(LockType.WRITE) public void refresh() { cache = loadFromDatabase(); } }
现代 @ApplicationScoped public class ConfigCache { private volatile Map<String, String> cache; @PostConstruct public void load() { cache = loadFromDatabase(); } public String get(String key) { return cache.get(key); } public void refresh() { cache = loadFromDatabase(); } }
悬停查看现代版 →
Enterprise

SOAP Web Services 与 Jakarta REST

旧版 @WebService public class UserWebService { @WebMethod public UserResponse getUser( @WebParam(name = "id") String id) { User user = findUser(id); UserResponse res = new UserResponse(); res.setId(user.getId()); res.setName(user.getName()); return res; } }
现代 @Path("/users") @Produces(MediaType.APPLICATION_JSON) public class UserResource { @Inject UserService userService; @GET @Path("/{id}") public User getUser(@PathParam("id") String id) { return userService.findById(id); } }
悬停查看现代版 →
Enterprise

Spring Framework 7 API 版本控制

旧版 // Version 1 controller @RestController @RequestMapping("/api/v1/products") public class ProductControllerV1 { @GetMapping("/{id}") public ProductDtoV1 getProduct( @PathVariable Long id) { return service.getV1(id); } } // Version 2 — duplicated structure @RestController @RequestMapping("/api/v2/products") public class ProductControllerV2 { @GetMapping("/{id}") public ProductDtoV2 getProduct( @PathVariable Long id) { return service.getV2(id); } }
现代 // Configure versioning once @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureApiVersioning( ApiVersionConfigurer config) { config.useRequestHeader("X-API-Version"); } } // Single controller, version per method @RestController @RequestMapping("/api/products") public class ProductController { @GetMapping(value = "/{id}", version = "1") public ProductDtoV1 getV1(@PathVariable Long id) { return service.getV1(id); } @GetMapping(value = "/{id}", version = "2") public ProductDtoV2 getV2(@PathVariable Long id) { return service.getV2(id); } }
悬停查看现代版 →
Enterprise

Spring Null 安全与 JSpecify

旧版 import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; public class UserService { @Nullable public User findById(@NonNull String id) { return repository.findById(id).orElse(null); } @NonNull public List<User> findAll() { return repository.findAll(); } @NonNull public User save(@NonNull User user) { return repository.save(user); } }
现代 import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @NullMarked public class UserService { public @Nullable User findById(String id) { return repository.findById(id).orElse(null); } public List<User> findAll() { return repository.findAll(); } public User save(User user) { return repository.save(user); } }
悬停查看现代版 →
Enterprise

Spring XML Bean 配置与注解驱动

旧版 <!-- applicationContext.xml --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userRepository" class="com.example.UserRepository"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="userService" class="com.example.UserService"> <property name="repository" ref="userRepository"/> </bean> </beans>
现代 @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } @Repository public class UserRepository { private final JdbcTemplate jdbc; public UserRepository(JdbcTemplate jdbc) { this.jdbc = jdbc; } } @Service public class UserService { private final UserRepository repository; public UserService(UserRepository repository) { this.repository = repository; } }
悬停查看现代版 →
112
现代模式
17
覆盖的 JDK 版本
10
分类
0
所需 Python 代码行数
ESC