許多開發者從 .NET (C#/VB.NET) 轉向 Java 時,會面臨語法範式、運行時機制、生態工具鏈的多重適應挑戰。本文針對核心語法差異提供對照表、轉換模式與最佳實踐,幫助你快速建立 Java 思維模型。
// C#
public enum Direction { Down = 1, DownLeft, Left, UpLeft, Up, UpRight, Right, DownRight }
// VB.NET
Public Enum Direction
Right = 1
DownRight
Down
' ...
End Enum
public enum Direction {
// 實例宣告:帶構造參數
DOWN(1), DOWN_LEFT(2), LEFT(3), UP_LEFT(4),
UP(5), UP_RIGHT(6), RIGHT(7), DOWN_RIGHT(8);
private final int code; // 實例欄位
Direction(int code) { this.code = code; }
public int getCode() { return code; }
// 靜態工廠:由 code 反查枚舉
private static final Map<Integer, Direction> LOOKUP =
Arrays.stream(values()).collect(Collectors.toMap(Direction::getCode, d -> d));
public static Direction fromCode(int code) {
return LOOKUP.getOrDefault(code, DOWN); // 或拋異常
}
// 實作介面實現多態行為
public Vector2 getVector() { /* 根據方向返回單位向量 */ }
}
| 特性 | .NET Enum | Java Enum |
|---|---|---|
| 本質 | 整數別名 | 單例類實例 |
| 可攜帶欄位/方法 | 否 | 是 |
| 可實作介面 | 否 | 是 |
| Switch 表達式支援 | C# 8.0+ | Java 12+ (switch expression) |
| 序列化 | 按名稱/值 | 保證單例反序列化安全 |
C# 所有異常均繼承 Exception,編譯器不強制捕獲或聲明。開發者依賴文檔、Code Contracts 或運行時攔截。
繼承 Exception(非 RuntimeException)的為受檢異常,必須在方法簽名用 throws 聲明或用 try-catch 處理。
InsufficientBalanceException、OrderNotFoundException,強制調用者處理業務流程。RuntimeException,如 IllegalArgumentException、DataAccessException,冒泡到全局異常處理器。// 自定義業務異常(受檢)
public class BusinessException extends Exception {
private final String errorCode;
public BusinessException(String code, String msg) { super(msg); this.errorCode = code; }
}
// 全局處理器
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBiz(BusinessException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getErrorCode(), e.getMessage()));
}
}
| 語言 | 語法 | 備註 |
|---|---|---|
| C# | var sb = new StringBuilder(); | 編譯期推斷,IL 仍為強類型 |
| VB.NET | Dim sb = New StringBuilder() | Option Infer On 時 |
| Java 10+ | var sb = new StringBuilder(); | 僅限區域變數,不可用於欄位/返回類型 |
| Java 8/9 | StringBuilder sb = new StringBuilder(); | 必須顯式宣告 |
建議: Java 中局部變數類型明顯時用 var,複雜泛型或增強可讀性時保留顯式類型。
// C# async/await
public async Task<Image> LoadImagesAsync() {
var tiles = await SpriteSheet.LoadAsync(...);
return tiles;
}
// Java CompletableFuture (Java 8+)
public CompletableFuture<BufferedImage> loadImagesAsync() {
return CompletableFuture.supplyAsync(() -> {
// 同步阻塞載入邏輯
return SpriteSheet.load(...);
}, customExecutor); // 自定義執行緒池隔離 IO
}
// Java 21 Virtual Threads (最接近 async/await 體驗)
public BufferedImage loadImages() { // 標記為虛擬執行緒運行
return SpriteSheet.load(...); // 阻塞式寫法,底層非阻塞
}
// C# LINQ
var result = geometries
.SelectMany(g => g.Tessellate())
.Select(t -> new LineSegment(t.Vertex1, t.Vertex2))
.Distinct()
.Where(l -> !light.RayToBoundary(screen).Intersects(l))
.ToArray();
// Java Stream
List<LineSegment> result = geometries.stream()
.flatMap(g -> g.tessellate().stream())
.map(t -> new LineSegment(t.getVertex1(), t.getVertex2()))
.distinct()
.filter(l -> !light.rayToBoundary(screen).intersects(l))
.collect(Collectors.toList());
Java 無指針算術。高效能數值計算改用:
VarHandle / MemorySegment (Foreign Function & Memory API, Java 22+)// C# uint/ulong
uint x = 42;
ulong y = 123L;
// Java 處理無符號數
long x = 42L & 0xFFFFFFFFL; // 模擬 uint
int u = Integer.parseUnsignedInt("4294967295"); // 解析
String s = Integer.toUnsignedString(-1); // "4294967295"
long sum = Long.unsignedAdd(a, b); // 無符號加法
極少數動態場景可用 javax.script (Nashorn/GraalJS) 或 MethodHandle,但嚴重影響效能與類型安全,建議重構為靜態類型設計。
| .NET | Java 對應 | 備註 |
|---|---|---|
| Visual Studio | IntelliJ IDEA (推薦) / Eclipse / VS Code | IDEA 智能提示、重構最強 |
| NuGet | Maven Central / Gradle Plugin Portal | Maven/Gradle 雙選一,企業多用 Gradle |
| MSBuild / .csproj | pom.xml (Maven) / build.gradle.kts | Kotlin DSL 類型安全 |
| NUnit / xUnit | JUnit 5 + AssertJ + Mockito | 標準測試堆疊 |
| Entity Framework | JPA/Hibernate / MyBatis / jOOQ | jOOQ 類型安全 SQL 構建器 |
| ASP.NET Core | Spring Boot 3 / Quarkus / Micronaut | Spring Boot 生態最豐富 |
| Serilog / NLog | Logback + SLF4J / Log4j2 | Logback 為 Spring Boot 預設 |
enum 重構為 Java 枚舉類,補充業務方法unsafe/指針代碼,改用 off-heap 庫或 JNIflatMap/collect 差異async/await 遷移至 CompletableFuture 或虛擬執行緒.NET 到 Java 的遷移不只是語法翻譯,更是運行時模型、異常哲學、生態工具鏈的整體轉型。建議以「重構而非翻譯」心態對待遺留代碼:利用 Java 的強類型系統、函數式 API、模組化機制,重新設計領域模型,才能真正發揮 Java 平台優勢。祝遷移順利!