1. Khởi tạo cú đúp
Khởi tạo bằng dấu ngoặc kép (
sau đây gọi là Khởi tạo dấu ngoặc kép ) là một công cụ Java để tạo các bộ sưu tập như danh sách, tập hợp và ánh xạ đồng thời với khai báo của chúng.
Khi bạn cần danh sách có các phần tử cố định, chẳng hạn như danh sách các sản phẩm được hỗ trợ hoặc đơn vị tiền tệ, việc khai báo danh sách cùng lúc với việc khởi tạo sẽ cải thiện khả năng đọc mã. Đây là lý do tại sao việc khởi tạo cú đúp đang trở nên phổ biến, vì không có phương pháp tiêu chuẩn nào khác để tạo các bộ sưu tập có khởi tạo đồng thời trong mã. Thật không may, không giống như các ngôn ngữ lập trình khác, Java không hỗ trợ các bộ sưu tập chữ. Do hạn chế này, việc tạo một Danh sách không thể sửa đổi
với một số lượng nhỏ phần tử buộc chúng ta phải viết nhiều dòng mã dưới dạng các lệnh gọi lặp lại
add()
để thêm các phần tử mong muốn với gói cuối cùng:
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(3);
list.add(5);
list.add(7);
List<Integer> unmodifiableList = Collections.unmodifiableList(list);
Đây là một mô tả dư thừa không cần thiết có thể được đơn giản hóa. Hãy điền vào danh sách tĩnh theo cách thuận tiện cho chúng ta, cụ thể là trực tiếp trong các khối tĩnh trong quá trình khởi tạo, đây là điều mà
Double brace
việc khởi tạo sẽ giúp chúng ta, cho phép chúng ta viết mọi thứ trong một dòng:
List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>() {{
add(2);
add(3);
add(5);
}});
Tương tự
Double brace
việc khởi tạo sẽ giúp chúng ta điền các giá trị và
HashMap
:
Map<Integer, String> intToString = new HashMap<Integer, String>(){{
put(1, "one");
put(2, "two");
put(3, "three");
}};
Tất cả đều trông rất thanh lịch, nhưng nó có nhược điểm, khiến cho việc khởi tạo cú đúp đôi trở thành phản mẫu. Chúng ta sẽ xem xét chúng sâu hơn trong chương tiếp theo.
Ưu và nhược điểm của việc khởi tạo cú đúp.
Double
Khởi tạo cú đúp sử dụng việc tạo một lớp
bên trong ẩn danh . Tuy nhiên, những gì ban đầu bị ẩn trên bề mặt,
Double brace
việc khởi tạo sẽ tạo ra một lớp với sự khởi tạo thêm thể hiện của nó mỗi khi bạn sử dụng nó. Ngoài ra, một tham chiếu ẩn đến lớp riêng tư này được sử dụng, điều này có thể khiến chúng ta bị rò rỉ bộ nhớ. Bạn cũng không thể sử dụng toán tử ghost cho generic (toán tử kim cương < >), vì chúng ta không thể truy cập vào bên trong một lớp ẩn danh.
(Từ người dịch: Một lần nữa chi tiết hơn:
sau lớp đầu tiên { , một lớp ẩn danh nội bộ được tạo, sau lớp thứ hai, { quá trình khởi tạo xảy ra khi tạo một phiên bản của lớp, trong đó chúng ta có quyền truy cập vào các trường và phương thức của lớp bên ngoài ( liên quan đến lớp ẩn danh).) |
Ưu điểm:
- Giảm dòng trong mã
- Tạo và khởi tạo trong một biểu thức.
Nhược điểm:
- Tạo một lớp ẩn danh ẩn khỏi bạn.
- Điều này khiến chúng tôi phải trả thêm chi phí cho phiên bản của nó mỗi khi chúng tôi sử dụng nó.
- Mỗi lần một tham chiếu ẩn được tạo ra, điều này có thể dẫn đến rò rỉ bộ nhớ.
Nhận định: Do những nhược điểm trên và sự tồn tại của các lựa chọn thay thế cho cú đúp, việc khởi tạo được coi là một phản mẫu trong thế giới Java.
Các lựa chọn thay thế cho việc khởi tạo cú đúp trong Java
Tin vui là có nhiều cách khác để đạt được mục tiêu tương tự trong Java. Chúng ta có thể triển khai trong một dòng mã việc tạo và khởi tạo một ArrayList bằng cách sử dụng hàm tạo Copy từ lớp Collection như dưới đây:
List<Integer> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(2, 3, 5)));
Arrays.asList()
sẽ trả về cho chúng tôi danh sách độ dài cố định được truyền cho
ArrayList
hàm tạo bản sao. Hãy ghi nhớ sự khác biệt giữa các danh sách có độ dài cố định được trả về từ
Arrays.asList()
và
Collections.unmodifiableList()
: bạn không thể thêm hoặc xóa các phần tử
ArrayList
của - , nhưng bạn có thể thay đổi một phần tử theo chỉ mục bằng cách sử dụng
set()
, điều mà bạn không thể thực hiện với danh sách được trả về bởi
Collections.unmodifiableList()
. Nếu bạn muốn lấy một danh sách nhỏ thì đây là cách tốt nhất, mặc dù nó sẽ kém minh bạch hơn đối với
Set
các bộ sưu tập khác, vì vậy bạn sẽ phải tạo nó
List
trước khi tạo
Set
-a. Nhưng điều này vẫn tốt hơn so với khởi tạo cú đúp, vì trong trường hợp này, một lớp ẩn danh nội bộ bổ sung không được tạo mỗi khi nó được sử dụng. Nếu bạn đang chạy Java 8, bạn có một phương pháp thay thế khác. API luồng JDK 8 sẽ giúp bạn tạo các bộ sưu tập nhỏ bằng cách kết hợp
Stream Factory
các phương thức đầu ra thành một bộ sưu tập
List
:
List<String> list = Collections.unmodifiableList(Stream.of("abc", "bcd", "cde").collect(toList()));
Vì
Set
bạn có thể sử dụng
Collectors.toSet()
phương pháp thay thế
Collectors.toList()
như dưới đây:
Set<String> set = Collections.unmodifiableSet(Stream.of("abc", "bcd", "cde").collect(toSet()));
Nhân tiện,
Stream collect
các phương thức không đảm bảo rằng các bộ sưu tập mà chúng tạo ra được bảo vệ khỏi những thay đổi. Trong Java 8, các bộ sưu tập mà chúng trả về (chẳng hạn như -
ArrayList
,
HashSet
và
HashMap
) khá phổ biến (chúng ta có thể thay đổi chúng), nhưng thực tế này có thể được sửa trong các bản phát hành JDK trong tương lai. Bây giờ đó là tất cả về
Double brace
việc khởi tạo trong Java. Mẫu này có thể chấp nhận được để thử nghiệm và demo nhưng không đủ tốt để sử dụng trong sản xuất. Do những nhược điểm cố hữu của nó, việc khởi tạo cú đúp ngày nay đã trở thành một mô hình phản đối, đặc biệt là khi có các lựa chọn thay thế có sẵn. Bản thân tôi vẫn sử dụng cấu trúc này để khởi tạo bản đồ tĩnh và thế là xong. Vì
List
tôi thích tạo
Collections
bằng cách kết hợp với việc tạo
Array.asList
trong hàm tạo của nó. Và nếu tôi sử dụng Java 8 - một thiết kế sử dụng API Stream và
collect()
.
Các bài viết liên quan: Nếu bạn thích hướng dẫn này và muốn tìm hiểu thêm về các mẫu, nguyên tắc và cách thực hành tốt nhất trong lập trình Java, bạn cũng có thể muốn xem các bài viết khác trên
trang web của chúng tôi .
Đề xuất đọc: Nếu bạn muốn tìm hiểu thêm về các mô hình và phương pháp hay nhất, bạn nên đọc
Lập trình hiệu quả của Joshua Bloch , không cuốn sách nào có thể thay thế được. Và nếu bạn đã thành thạo Java và đang tìm một cuốn sách về các mẫu thiết kế, có phong cách trình bày hài hước thú vị và dễ đọc, hãy chú ý đến
“Head First. Mẫu thiết kế" .
Từ người dịch: Tôi đã cố tình cung cấp một liên kết đến cuốn sách gốc của Bloch, vì bản dịch sang tiếng Nga của nó không thành công (ví dụ: Builder = constructor). |
Bản dịch bài viết Khởi tạo cú đúp trong Java là gì? Ví dụ về Anti Pattern (xuất bản tháng 10 năm 2015).
GO TO FULL VERSION