Khi viết code với rất nhiều điều kiện, chắc chắn bạn đã từng sử dụng câu lệnh if-else hoặc switch . Nhưng sự thay thế này cho if-else có nhược điểm. Một số người thậm chí còn gọi câu lệnh chuyển đổi là "phản mẫu".

Đó là cái gì? Anti-pattern là một dạng phổ biến của mã xấu, tức là một giải pháp tồi cho một vấn đề. Các lập trình viên cố gắng tránh sử dụng chúng trong mã, vì chúng làm giảm chất lượng mã.

Nhưng có một tin tốt: các phiên bản mới của Java đã mang lại nhiều thay đổi trong cú pháp của ngôn ngữ và một trong những thay đổi đó ảnh hưởng đến switch . Có mưu đồ? Sau đó, chúng ta hãy đi sâu vào.

Để bắt đầu, cần làm rõ lý do tại sao switch là một anti-pattern. Hãy xem xét đoạn mã sau:


switch (condition) {
    case "DECEMBER":
        seasonNumber = 1;
        break;
    case "JANUARY":
        seasonNumber = 1;
        break;
    case "FEBRUARY":
        seasonNumber = 1;
        break;
    default:
        seasonNumber = 0;
}

Được rồi, vì vậy vẫn chưa hoàn toàn rõ ràng tại sao đây là "chống mẫu".

Nhưng điều gì sẽ xảy ra nếu chúng ta thêm nhiều khối trường hợp hơn và bây giờ mã trông như thế này:


switch (condition) {
    case "DECEMBER":
        seasonNumber = 1;
        break;
    case "JANUARY":
        seasonNumber = 1;
        break;
    case "FEBRUARY":
        seasonNumber = 1;
        break;
    case “MARCH”:
        seasonNumber = 2;
        break;
    case “APRIL”:
        seasonNumber = 2;
        break;
    case “MAY”:
        seasonNumber = 2;
        break;
    default:
        seasonNumber = 0;
}

Hãy thêm một vài dòng nữa — mã sẽ dài hơn. Sau này chúng ta có thể thêm ngày càng nhiều dòng và không ai có thể ngăn cản chúng ta làm điều này.

Đây là cốt lõi của vấn đề: sau khi tạo một câu lệnh chuyển đổi nhỏ gọn ban đầu, chúng tôi thêm ngày càng nhiều mã vào nó, chiếm ngày càng nhiều không gian — nhiều hơn mức sẽ vừa với màn hình — và khiến mã trở nên bất tiện khi đọc và bảo trì.

Sự khác biệt giữa câu lệnh switch và biểu thức switch

Java 14 đã giới thiệu một công tắc mới và được cải tiến. Nó không phải là một câu lệnh chuyển đổi , mà là một biểu thức chuyển đổi .

sự khác biệt là gì, bạn yêu cầu? Sự khác biệt là một câu lệnh là một lệnh thực hiện một tập hợp các hoạt động nhất định, nhưng một biểu thức là một đoạn mã thực hiện một số phép tính và trả về một kết quả.

Nói cách khác, bây giờ bạn có thể lưu kết quả của một lần chuyển sang một biến.

Nói đủ rồi. Bây giờ hãy xem công tắc mới trông như thế nào:


var result = switch(month) {
     case DECEMBER, JANUARY, FEBRUARY -> 1;
     case MARCH, APRIL, MAY -> 2;
    case JUNE, JULY, AUGUST -> 3;
    case SEPTEMBER, OCTOBER, NOVEMBER -> 4;
    default -> 0; 
};

Điều đầu tiên thu hút sự chú ý của bạn là mã nhỏ gọn như thế nào. Đoạn mã từng chiếm phần lớn màn hình giờ chỉ còn vài dòng và trông dễ đọc hơn nhiều.

-> toán tử

Bạn cũng cần lưu ý toán tử -> (toán tử mũi tên). Bạn có thể đã quen thuộc với nó nếu bạn có kinh nghiệm với các biểu thức lambda.

Điều đó có nghĩa là bây giờ bạn có thể viết một công tắc trông bắt mắt theo kiểu câu lệnh lambda. Toán tử mũi tên chỉ ra rằng trình biên dịch sẽ không chuyển sang biểu thức trường hợp tiếp theo (nếu khối trường hợp hiện tại thiếu câu lệnh ngắt hoặc trả về ), mà thay vào đó sẽ cung cấp cho bạn giá trị của biểu thức ở bên phải mũi tên.

Bạn cũng có thể viết mã không phải là một biểu thức và chỉ cần thực hiện một số hành động nhất định thay vì trả lại bất kỳ thứ gì:


switch(condition) {
    case TRUE, FALSE -> System.out.println("True/false");
  
    default -> System.out.println("Another");
}

Lưu ý rằng switch không còn câu lệnh ngắt nữa . Nó đã bị xóa trong Java 13 và được thay thế bằng yield .

Năng suất là gì và nó có thể được sử dụng ở đâu?

Khi một công tắc bao gồm một dòng, chính toán tử -> sẽ trả về giá trị. Nhưng nếu chúng ta không chỉ có một mà là nhiều dòng mã thì sao? Trong những trường hợp như vậy, toán tử mũi tên sẽ không trả về giá trị vì có nhiều dòng chứ không phải một dòng.

Có lẽ chúng ta có thể sử dụng return ? Rốt cuộc, nó được sử dụng để trả về các giá trị trong Java. Than ôi, không, quay lại sẽ không hoạt động với một công tắc. Vì vậy, những gì chúng ta có thể sử dụng? Đã từng có break , nhưng nó đã bị loại bỏ trong Java 13. Nhưng ở vị trí của nó, giờ đây chúng ta có yield — một từ khóa mới giúp bạn trả về một giá trị từ một công tắc. Việc trả về các câu lệnh trong các phương thức cũng tương tự .


var result = switch(condition) {
//…
case "Hi" -> "greeting"
//…
};  

Mã này chứa một dòng duy nhất và toán tử -> sẽ trả về "lời chào".

Nhưng khi chúng ta có một khối mã:


var result = switch(condition) {
//…
case "Hi" -> {
// Your code
 Here you need to return "greeting"
	}
};  

Từ khóa sẽ giúp bạn trả về một giá trị là yield :


var result = switch(condition) {
//…
case "Hi" -> {
// Your code
 yield "greeting";

	}
};

năng suất đã được thêm vào trong Java 13 cho các trường hợp chúng tôi có nhiều dòng mã trong một khối trường hợp và chúng tôi cần trả về kết quả.

Bạn có thể háo hức thử chuyển đổi mới trong mã của mình, nhưng hãy nhớ rằng bạn cần Java 14 trở lên để thực hiện việc này. Với các phiên bản trước, công tắc này sẽ chỉ khả dụng nếu bạn chỉ định cờ "--enable-preview" trên dòng lệnh, vì trước phiên bản 14, nó là một phần của bản xem trước kỹ thuật, không phải là một phần chính thức của ngôn ngữ.

Đó là tất cả cho bây giờ! Thấy bạn!