- 1 1. Biến (Variables) là gì trong Java?
- 2 2. Những điều cơ bản về biến: Sự khác nhau giữa khai báo, gán và khởi tạo
- 3 3. Hiểu về “Kiểu” của biến (Kiểu nguyên thủy và Kiểu tham chiếu)
- 3.1 3.1 Kiểu Java Rơi Vào Hai Danh Mục Lớn
- 3.2 3.2 Kiểu Nguyên Thủy Là Gì? (Các Kiểu Giữ Giá Trị Tự Mình)
- 3.3 3.3 Đặc Điểm và Lưu Ý Của Kiểu Nguyên Thủy
- 3.4 3.4 Kiểu Tham Chiếu Là Gì? (Các Kiểu Xử Lý Vị Trí Lưu Trữ Giá Trị)
- 3.5 3.5 Điều Gì Xảy Ra Khi Bạn Gán Kiểu Tham Chiếu?
- 3.6 3.6 Các Điểm Nhầm Lẫn Thường Gặp Của Người Mới
- 3.7 3.7 Tóm Tắt Phần
- 4 4. Các Loại Biến (Nơi Chúng Sống) và Phạm Vi (Nơi Chúng Có Hiệu Lực)
- 5 5. Sử dụng var (Suy luận kiểu) Đúng cách trong Java 10+
- 6 6. “Tôi Không Muốn Thay Đổi Giá Trị Này”—final và Ý Tưởng Về Hằng Số
- 6.1 6.1 final Là Gì? (Cấm Gán Lại)
- 6.2 6.2 Tại sao nên dùng final cho các biến cục bộ?
- 6.3 6.3 Sử dụng final cho các trường (fields)
- 6.4 6.4 Lưu ý quan trọng cho final với các kiểu tham chiếu (Sự nhầm lẫn thường gặp của người mới bắt đầu)
- 6.5 6.5 Hằng số là gì? (static final)
- 6.6 6.6 Cách quyết định khi nào nên dùng final
- 6.7 6.7 Tóm tắt phần
- 7 7. Giá trị khởi tạo, Giá trị mặc định và Các lỗi thường gặp (Phục hồi từ những sai lầm của người mới bắt đầu)
- 8 8. Tóm Tắt: Những Điểm Chính Cần Nắm Vững Đầu Tiên Về Biến Java
- 8.1 8.1 Nghĩ Về Biến Java Như Một Bộ “Kiểu, Tên và Giá Trị”
- 8.2 8.2 Phân Biệt Rõ Ràng Giữa Khai Báo, Gán Giá Trị và Khởi Tạo
- 8.3 8.3 Nhận Thức Sự Khác Biệt Giữa Kiểu Nguyên Tử và Kiểu Tham Chiếu
- 8.4 8.4 Hiểu về Phạm vi Giảm Lỗi Một Cách Đáng Kể
- 8.5 8.5 Sử dụng var và final Dựa trên Mục đích
- 8.6 8.6 Hướng dẫn cho Người mới bắt đầu Viết An toàn
- 8.7 8.7 Các Chủ đề Tiếp theo để Học cho Hiểu Biết Sâu hơn
1. Biến (Variables) là gì trong Java?
Khi bạn bắt đầu học Java, một trong những khái niệm quan trọng đầu tiên bạn gặp phải là “biến”.
Nói ngắn gọn, biến là một container dùng để tạm thời lưu trữ các giá trị (dữ liệu) trong chương trình để bạn có thể tái sử dụng chúng bao nhiêu lần tùy ý.
Tuy nhiên, trong Java, bạn sẽ nhanh chóng gặp khó khăn nếu chỉ ghi nhớ biến là “các hộp”.
Bởi vì các biến trong Java được xử lý cùng với một “kiểu” (type) (loại dữ liệu).
Trong phần này, chúng ta sẽ sắp xếp vai trò của biến và cách suy nghĩ đặc thù của Java (tầm quan trọng của kiểu) dành cho người mới bắt đầu.
1.1 Những gì bạn có thể làm với biến (Lưu giá trị và tái sử dụng chúng)
Với biến, một chương trình có thể chuyển từ “các phép tính một lần duy nhất” sang “xử lý có ý nghĩa”.
Ví dụ, bạn có thể viết số trực tiếp như sau:
System.out.println(100 + 20);
Cách này hoạt động, nhưng các giá trị không có ý nghĩa, vì vậy người đọc mã sau này (kể cả bạn trong tương lai) sẽ gặp khó khăn.
Bạn sẽ không biết “100 là gì?” hay “20 là gì?”
Bằng cách sử dụng biến, bạn có thể gán ý nghĩa cho các giá trị.
int price = 100;
int tax = 20;
System.out.println(price + tax);
Sử dụng biến như vậy mang lại các lợi ích sau:
- Dễ hiểu ý định hơn (các tên như price và tax truyền tải ý nghĩa)
- Bạn có thể tái sử dụng giá trị nhiều lần (không cần viết lại cùng một giá trị liên tục)
- Dễ thay đổi sau này (nếu tỷ lệ thuế thay đổi, bạn chỉ cần thay đổi giá trị của biến)
- Bạn có thể giữ các kết quả trung gian (chia logic phức tạp thành các bước nhỏ hơn)
Đặc biệt đối với người mới bắt đầu, việc nghĩ “biến = đặt tên cho giá trị” là hợp lý.
Tuy nhiên, trong Java, khái niệm tiếp theo—“kiểu”—luôn xuất hiện như một bộ.
1.2 Các biến Java được sử dụng cùng với “Kiểu” (Type Safety)
Trong Java, các biến thường được tạo ra theo dạng sau:
type variableName = value;
Ví dụ:
int age = 20;
String name = "Sagawa";
Điểm then chốt ở đây là kiểu.
intlà số nguyên (ví dụ: 20, 100, -5)Stringlà chuỗi ký tự (ví dụ: “Hello”, “Java”)
Trong Java, khi bạn tạo một biến, bạn phải khai báo rõ ràng “kiểu giá trị nào mà biến này có thể chứa”.
Nhờ hệ thống này, Java có những ưu điểm như sau.
“Type‑Safe” có nghĩa là gì?
Vì bạn chỉ định kiểu, Java có thể ngăn bạn khi cố gắng gán giá trị sai kiểu vào một biến.
Ví dụ, nếu bạn cố gắng gán một chuỗi vào biến kiểu int, bạn sẽ nhận được lỗi biên dịch.
int age = "20"; // This is an error
Điều này không phải là phiền phức—ngược lại, nó thực sự hữu ích.
Thay vì “bị lỗi sau khi chạy chương trình”, bạn có thể “phát hiện lỗi trước khi chạy”.
Người mới bắt đầu đôi khi cảm thấy “Java có quá nhiều lỗi” vì điều này, nhưng nếu bạn thay đổi cách nhìn:
- Java phát hiện sự không khớp kiểu sớm
- Dự án càng lớn, các kiểu càng giúp giảm thiểu tai nạn
Ý tưởng này—“kiểu và biến luôn đi kèm”—là một trong những nền tảng cơ bản nhất của Java.
Lưu ý: Ngay cả với “Biến”, cũng có “Giá trị” và “Tham chiếu”
Các biến Java được xử lý chủ yếu theo hai cách:
- Kiểu nguyên thủy : lưu trữ trực tiếp giá trị (ví dụ:
int,double,boolean) - Kiểu tham chiếu : không lưu trữ giá trị trực tiếp, mà lưu trữ vị trí (tham chiếu) nơi giá trị được lưu (ví dụ:
String, mảng, lớp)
Chúng ta sẽ không đi sâu vào đây, nhưng đây là một điểm gây nhầm lẫn phổ biến cho người mới, vì vậy cần đề cập ngay từ đầu.
Ví dụ, String là một kiểu tham chiếu.
Nó có vẻ như bạn đang “lưu một chuỗi”, nhưng thực tế, bạn đang giữ “một tham chiếu tới một đối tượng chuỗi”.
Sự khác biệt này cũng liên quan tới các chủ đề bạn sẽ học sau, như “== vs equals” và “cách final hoạt động”.
2. Những điều cơ bản về biến: Sự khác nhau giữa khai báo, gán và khởi tạo
Để hiểu đúng các biến trong Java,
cần sắp xếp rõ ràng sự khác nhau giữa “khai báo” (declaration), “gán” (assignment) và “khởi tạo” (initialization).
Beginners often use these three words as if they mean the same thing,
but in reality, they have clearly different roles.
Nếu bạn để điều này mơ hồ,
bạn sẽ dễ rơi vào trạng thái
“I don’t know why it’s an error” hoặc “I don’t know why I can’t use it.”
2.1 Khai báo: Chuẩn bị sử dụng một biến
Khai báo có nghĩa là nói với Java:
“Tôi sẽ sử dụng một biến với tên này,” và “kiểu của nó là như vậy.”
Cách khai báo cơ bản nhất trông như sau:
int count;
Tại thời điểm này, chỉ có hai điều đã xảy ra:
- Tạo một biến có tên
count - Quyết định rằng kiểu của nó là
int(số nguyên)
Chưa có giá trị nào được lưu trữ.
Đây là một hiểu lầm phổ biến của người mới:
chỉ khai báo một biến không làm cho nó “sẵn sàng sử dụng.”
2.2 Gán giá trị: Đặt một giá trị vào biến
Gán giá trị có nghĩa là đặt một giá trị vào một biến đã được khai báo.
count = 10;
Dấu = này không có nghĩa là “bằng” trong toán học.
Nó có nghĩa là đặt giá trị ở bên phải vào biến ở bên trái.
Vì vậy luồng thực hiện sẽ như sau:
int count; // declaration
count = 10; // assignment
Đó là ý chính.
Lưu ý: Bạn không thể gán cho một biến chưa được khai báo
Mã sau sẽ gây ra lỗi:
count = 10; // Error: count has not been declared
Trong Java, thứ tự phải là khai báo → gán giá trị.
2.3 Khởi tạo: Gán giá trị ngay khi khai báo
Khởi tạo có nghĩa là thực hiện khai báo và gán giá trị đồng thời.
int count = 10;
Điều này về mặt ngữ nghĩa tương đương với hai dòng sau:
int count;
count = 10;
Trong Java—cả trong công việc thực tế và trong quá trình học—
trong hầu hết các trường hợp, bạn có thể yên tâm sử dụng “khởi tạo”.
Đó là vì nó mang lại các lợi ích sau:
- Biến trở nên có thể sử dụng ngay khi nó được tạo
- Nó ngăn ngừa lỗi do biến chưa được khởi tạo
- Mã nguồn trở nên dễ đọc hơn
Vì vậy, với người mới, nên hình thành thói quen
“khởi tạo biến ngay khi khai báo chúng.”
2.4 Tại sao bạn không thể sử dụng một biến chỉ với khai báo (Quy tắc biến cục bộ)
Trong Java, có những quy tắc rất nghiêm ngặt đối với biến cục bộ (biến trong các phương thức).
Java đặc biệt nghiêm khắc ở đây.
Mã sau sẽ gây ra lỗi biên dịch:
int number;
System.out.println(number); // Error
Lý do rất rõ ràng:
Biến cục bộ không thể được sử dụng nếu chúng chưa được khởi tạo
Quy tắc đó tồn tại.
Java coi trạng thái “chúng ta không biết giá trị bên trong biến” là một trạng thái nguy hiểm và ngăn chặn nó như một lỗi trước khi thực thi.
Điều này có thể cảm thấy nghiêm khắc đối với người mới, nhưng trong phát triển quy mô lớn, nó là một cơ chế an toàn rất quan trọng.
2.5 Khai báo nhiều biến cùng lúc (Cẩn thận)
Trong Java, bạn có thể khai báo nhiều biến cùng kiểu cùng lúc.
int x, y, z;
Bạn cũng có thể viết như sau:
int a = 1, b = 2, c = 3;
Cú pháp này đúng, nhưng nó có thể làm giảm khả năng đọc, vì vậy hãy cẩn thận.
Đặc biệt đối với người mới và phát triển theo nhóm, an toàn hơn khi viết:
int a = 1;
int b = 2;
int c = 3;
với một biến mỗi dòng.
2.6 Tóm tắt phần
Các điểm chính cần nhớ từ phần này:
- Khai báo : quyết định tên và kiểu của biến
- Gán giá trị : đặt một giá trị vào biến
- Khởi tạo : khai báo và gán giá trị đồng thời
- Biến cục bộ không thể được sử dụng nếu chưa được khởi tạo
- Đối với người mới, hãy sử dụng “khai báo + khởi tạo” làm mặc định
3. Hiểu về “Kiểu” của biến (Kiểu nguyên thủy và Kiểu tham chiếu)
Khi làm việc với các biến Java, bạn không thể tránh khỏi việc hiểu các kiểu. Điều thường làm người mới bối rối là:
- Tại sao có quá nhiều kiểu
- Tại sao các số có cả
intvàdouble Stringkhác gì so với các kiểu số
Trong phần này, chúng ta sẽ sắp xếp các kiểu Java từ hai góc độ:
“kiểu nguyên thủy” và “kiểu tham chiếu.”
3.1 Kiểu Java Rơi Vào Hai Danh Mục Lớn
Các kiểu biến Java có thể được phân loại rộng rãi thành hai danh mục sau:
- Kiểu nguyên thủy
- Kiểu tham chiếu
Khi bạn hiểu được cách phân loại này, các chủ đề bạn sẽ học sau—như “== vs equals,” “cách final hoạt động,” và “cách bộ nhớ hoạt động”—sẽ trở nên dễ hiểu hơn rất nhiều.
3.2 Kiểu Nguyên Thủy Là Gì? (Các Kiểu Giữ Giá Trị Tự Mình)
Kiểu nguyên thủy là các kiểu giữ giá trị trực tiếp.
Hãy xem một vài kiểu nguyên thủy phổ biến:
int count = 10;
double price = 19.99;
boolean isActive = true;
Các biến này lưu trữ
“giá trị tự nó” bên trong biến.
Các Kiểu Nguyên Thủy Thường Dùng
| Type | Meaning | Example Use |
|---|---|---|
int | Integer | Counts, age, number of times |
long | Large integer | Amounts of money, IDs |
double | Decimal | Prices, ratios |
boolean | True/false | Flag checks |
char | Single character | Character processing |
Đối với người mới bắt đầu, chỉ cần nắm vững int, double, và boolean là đủ.
3.3 Đặc Điểm và Lưu Ý Của Kiểu Nguyên Thủy
Kiểu nguyên thủy có các đặc điểm sau:
- Chúng giữ giá trị tự nó
- Chúng xử lý nhanh
- Bạn không thể gán
null - Kích thước cố định
Ví dụ, trong đoạn mã dưới đây,
a và b giữ các giá trị hoàn toàn độc lập.
int a = 5;
int b = a;
b = 10;
Trong trường hợp này:
avẫn là 5bthay đổi thành 10
Đó là kết quả.
Điều này xảy ra vì giá trị tự nó đã được sao chép.
3.4 Kiểu Tham Chiếu Là Gì? (Các Kiểu Xử Lý Vị Trí Lưu Trữ Giá Trị)
Ngược lại, kiểu tham chiếu
là các kiểu không xử lý giá trị trực tiếp, mà xử lý vị trí (tham chiếu) nơi giá trị tồn tại.
Các kiểu tham chiếu điển hình bao gồm:
String name = "Java";
int[] numbers = {1, 2, 3};
String- Mảng
- Lớp
- Giao diện
- Các collection như List / Map
Tất cả những thứ này đều là kiểu tham chiếu.
Hiểu Kiểu Tham Chiếu Bằng Một Hình Ảnh
Một biến kiểu tham chiếu giữ:
- không phải đối tượng thực tế, mà
- một “địa chỉ” chỉ tới nơi đối tượng thực tế được lưu trữ
Đó là mô hình tư duy.
3.5 Điều Gì Xảy Ra Khi Bạn Gán Kiểu Tham Chiếu?
Xem đoạn mã sau:
String a = "Hello";
String b = a;
b = "World";
Trong trường hợp này:
alà “Hello”blà “World”
Đó là kết quả.
Nếu chỉ nhìn vào đây, bạn có thể nghĩ,
“Điều này không giống như kiểu nguyên thủy sao?”
Vậy còn ví dụ tiếp theo thì sao?
int[] array1 = {1, 2, 3};
int[] array2 = array1;
array2[0] = 100;
Kết quả là:
array1[0]→ 100array2[0]→ 100
Điều này xảy ra vì array1 và array2 tham chiếu tới cùng một mảng.
Với kiểu tham chiếu:
- Gán biến có thể làm cho chúng “trỏ tới cùng một đối tượng thực tế”
- Thay đổi nội dung có thể ảnh hưởng đến mọi thứ tham chiếu tới nó
Đó là đặc điểm then chốt.
3.6 Các Điểm Nhầm Lẫn Thường Gặp Của Người Mới
Hãy tóm tắt các điểm gây bối rối phổ biến:
- Kiểu nguyên thủy → giá trị được sao chép
- Kiểu tham chiếu → tham chiếu (vị trí) được sao chép
Sự khác biệt này liên quan chặt chẽ tới các chủ đề sau:
- Sự khác nhau giữa
==và.equals() - Điều gì xảy ra khi bạn dùng
final - Cách truyền giá trị làm đối số phương thức ảnh hưởng tới phạm vi và hành vi
Hiện tại, chỉ cần nhớ điều này là đủ:
kiểu tham chiếu đôi khi có thể chia sẻ cùng một đối tượng thực tế.
3.7 Tóm Tắt Phần
- Kiểu Java được chia thành kiểu nguyên thủy và kiểu tham chiếu
- Kiểu nguyên thủy xử lý “giá trị tự nó”
- Kiểu tham chiếu xử lý “vị trí (tham chiếu) của giá trị”
- Với kiểu tham chiếu, việc gán và thay đổi có thể ảnh hưởng tới các biến khác
4. Các Loại Biến (Nơi Chúng Sống) và Phạm Vi (Nơi Chúng Có Hiệu Lực)
Trong Java, các biến không chỉ khác nhau về “kiểu.”
Hành vi của chúng còn thay đổi tùy thuộc vào nơi chúng được khai báo (nơi chúng “sống”).
Nếu bạn không hiểu sự khác biệt này, bạn có thể bị nhầm lẫn bởi những thứ như:
.
- “Tôi không thể sử dụng biến mà tôi đã khai báo trước đó”
- “Nó có cùng tên, nhưng giá trị lại khác”
- “Tôi không hiểu tại sao tôi không thể tham chiếu tới nó ở đây”
Trong phần này, chúng ta sẽ sắp xếp
các loại biến và phạm vi cho người mới bắt đầu.
4.1 Phạm vi là gì? (Nơi một biến có thể được sử dụng)
Phạm vi có nghĩa là
khoảng nơi một biến có thể được sử dụng.
Trong Java, phạm vi được xác định một cách chặt chẽ bởi:
- nơi biến được khai báo
- phạm vi của các dấu ngoặc nhọn
{ }
Quy tắc cơ bản rất đơn giản:
Một biến chỉ có thể được sử dụng bên trong khối mà nó được khai báo
4.2 Biến cục bộ (Biến trong phương thức)
Biến cục bộ là các biến được khai báo bên trong các phương thức hoặc khối (như if và for).
public void sample() {
int x = 10; // local variable
System.out.println(x);
}
Biến x này có các đặc điểm sau:
- Chỉ hợp lệ bên trong phương thức
sample - Biến mất khi phương thức kết thúc
Ví dụ về Phạm vi với Các Khối
if (true) {
int y = 5;
System.out.println(y);
}
System.out.println(y); // Error
Vì y được khai báo bên trong khối if, nên không thể sử dụng nó bên ngoài khối đó.
Các Quy tắc Quan trọng cho Biến Cục bộ
Biến cục bộ có các quy tắc nghiêm ngặt:
- Bạn không thể sử dụng chúng nếu chưa được khởi tạo
- Không có giá trị mặc định nào được gán tự động
int value; System.out.println(value); // compile-time error
Đây là một phần của thiết kế an toàn của Java để ngăn việc sử dụng “giá trị chưa định nghĩa”.
4.3 Trường (Biến thể hiện)
Trường là các biến được khai báo bên trong một lớp nhưng ngoài các phương thức.
public class Sample {
int count; // field (instance variable)
public void printCount() {
System.out.println(count);
}
}
Trường có các đặc điểm khác với biến cục bộ:
- Mỗi đối tượng của lớp có một bản sao riêng
- Chúng được khởi tạo tự động với các giá trị mặc định
- Có thể được sử dụng từ bất kỳ phương thức nào trong lớp
Giá trị Mặc định cho Trường
Tùy thuộc vào kiểu dữ liệu, các giá trị mặc định sau sẽ được đặt tự động:
int→ 0double→ 0.0boolean→ false- Kiểu tham chiếu → null
Vì vậy đoạn mã sau không gây lỗi:
public class Sample {
int count;
public void print() {
System.out.println(count); // 0
}
}
Tuy nhiên, phụ thuộc quá nhiều vào giá trị mặc định là không được khuyến khích.
Việc khởi tạo rõ ràng sẽ làm cho ý định của mã trở nên minh bạch hơn.
4.4 Biến static (Biến lớp)
Một biến có static trở thành
một biến được chia sẻ trên toàn bộ lớp.
public class Counter {
static int total = 0;
}
Biến total này có các đặc điểm sau:
- Chỉ có một thể hiện duy nhất cho mỗi lớp
- Được chia sẻ bởi tất cả các đối tượng
Mô hình Tư duy cho Biến static
- Biến thể hiện → ví tiền của mỗi người
- Biến static → két sắt chung của công ty
Mô hình này giúp dễ hiểu hơn.
Lưu ý khi dùng Biến static
Biến static hữu ích, nhưng lưu trữ quá nhiều trạng thái có thể gây lỗi.
- Khó theo dõi nơi các thay đổi đã xảy ra
- Việc kiểm thử trở nên khó khăn hơn
- Các vấn đề có khả năng xuất hiện trong xử lý đồng thời
Đối với người mới bắt đầu, nên hạn chế sử dụng cho các mục đích như:
- Hằng số
- Các giá trị cấu hình chung
và các mục đích tương tự.

4.5 Cẩn thận với các biến có cùng tên (Shadowing)
Xem đoạn mã sau:
public class Sample {
int value = 10;
public void test() {
int value = 5;
System.out.println(value);
}
}
Trong trường hợp này, kết quả là 5.
Điều này xảy ra vì
biến cục bộ đang ẩn trường (shadowing).
Vì đây là một nguồn gây nhầm lẫn phổ biến cho người mới bắt đầu:
- Tránh trùng tên biến
- Không tái sử dụng cùng một tên trừ khi có mục đích rõ ràng
Kỷ luật này rất quan trọng.
4.6 Tóm tắt phần
- Scope nghĩa là “phạm vi mà một biến có thể được sử dụng”
- Các biến cục bộ chỉ hợp lệ bên trong các khối và phải được khởi tạo
- Các trường được tự động gán giá trị mặc định
- Các biến static được chia sẻ trên toàn lớp
- Hãy cẩn thận với việc che khuất (shadowing) do các biến có cùng tên gây ra
5. Sử dụng var (Suy luận kiểu) Đúng cách trong Java 10+
Được giới thiệu trong Java 10, var là
một cách để cho trình biên dịch suy luận kiểu của biến.
Nó có thể trông tiện lợi, nhưng nếu lạm dụng, nó có thể dễ dàng dẫn đến “mã khó đọc.”
Vì vậy, điều quan trọng là phải hiểu các quy tắc và khi nào nên sử dụng nó.
5.1 var Là Gì? (Cách Hoạt Động Mà Không Cần Viết Kiểu)
Trong Java thông thường, bạn khai báo một biến như thế này:
String message = "Hello";
Với var, bạn có thể viết:
var message = "Hello";
Tại thời điểm này, Java xem xét bên phải "Hello" và quyết định:
- Biến này có kiểu
String
Điểm quan trọng là var không phải là kiểu động.
- Kiểu được xác định tại thời điểm biên dịch
- Kiểu không thay đổi tại thời điểm chạy
Vì vậy, hãy nghĩ về var như “cách viết tắt cho phép bạn bỏ qua kiểu.”
5.2 Nơi Bạn Có Thể và Không Thể Sử Dụng var
var chỉ có thể được sử dụng ở những nơi được định nghĩa nghiêm ngặt.
Nơi Bạn Có Thể Sử Dụng Nó
- Chỉ biến cục bộ
public void sample() { var count = 10; }
Nơi Bạn Không Thể Sử Dụng Nó
Tất cả các cách sử dụng sau đây đều dẫn đến lỗi:
var x; // No initialization → error
var y = null; // Cannot infer the type → error
class Sample {
var value = 10; // Cannot be used for fields → error
}
Lý do cho những hạn chế này là rõ ràng: để tránh giảm khả năng đọc và an toàn.
5.3 Lợi Ích Của Việc Sử Dụng var
var tỏa sáng khi
kiểu có xu hướng dài.
ArrayList<String> list = new ArrayList<String>();
Với var:
var list = new ArrayList<String>();
Nó trở nên sạch sẽ hơn nhiều.
Nói cách khác, var hữu ích khi:
- Generics dài
- Kiểu rõ ràng từ bên phải
Sử dụng theo cách này, nó có thể cải thiện khả năng đọc.
5.4 Những Sai Lầm Của var (Những Lỗi Thường Gặp Của Người Mới Bắt Đầu)
var tiện lợi, nhưng nếu người mới lạm dụng nó, các vấn đề sau có thể xảy ra.
Kiểu Trở Nên Khó Thấy
var data = getData();
Từ dòng này thôi, bạn không thể biết:
- Dữ liệu có kiểu gì
- Nó chứa gì
Trong những trường hợp như vậy, an toàn hơn là viết kiểu một cách rõ ràng.
Data data = getData();
Nó Có Thể Trở Thành Kiểu Không Mong Muốn
var number = 10; // int
Người mới thường gặp phải các trường hợp như,
“Tôi nghĩ nó sẽ là long.”
Khi bạn không viết kiểu một cách rõ ràng, ý định của bạn và kiểu suy luận thực tế có thể khác biệt, vì vậy hãy cẩn thận.
5.5 Cách Quyết Định Có Nên Sử Dụng var Hay Không
Nếu bạn không chắc chắn, hãy sử dụng các tiêu chí sau:
- Nếu kiểu rõ ràng từ bên phải →
varlà OK - Nếu kiểu mang ý nghĩa quan trọng → viết kiểu một cách rõ ràng
- Thân thiện với người mới / mã học tập → viết kiểu càng nhiều càng tốt
- Phát triển nhóm → tuân theo các tiêu chuẩn mã hóa
Đặc biệt trong quá trình học,
việc viết kiểu giúp làm sâu sắc thêm sự hiểu biết,
vì vậy bạn không cần ép buộc bản thân sử dụng var.
5.6 Tóm Tắt Phần
varlà cách viết tắt cho suy luận kiểu- Nó không phải là kiểu động; kiểu được cố định tại thời điểm biên dịch
- Nó chỉ dành cho biến cục bộ và yêu cầu khởi tạo
- Điều quan trọng là phân biệt khi nào nó cải thiện so với giảm khả năng đọc
6. “Tôi Không Muốn Thay Đổi Giá Trị Này”—final và Ý Tưởng Về Hằng Số
Trong Java, ý tưởng thiết kế “một khi giá trị đã được quyết định, đừng để nó bị thay đổi sau đó” rất quan trọng.
Công cụ cho điều đó là final.
Người mới thường nghĩ “final là thứ bạn đặt lên hằng số,” nhưng thực tế, nó có ý nghĩa rộng hơn.
6.1 final Là Gì? (Cấm Gán Lại)
Một biến có final không thể được gán lại sau khi bạn đã gán một lần.
final int maxCount = 10;
maxCount = 20; // compile-time error
Quy tắc rất đơn giản:
- Bạn có thể khởi tạo nó
- Bạn không thể gán lại nó
Đó là tất cả những gì bạn cần nhớ.
6.2 Tại sao nên dùng final cho các biến cục bộ?
Thêm final vào một biến cục bộ làm cho nó rõ ràng rằng:
- Biến này không thay đổi giữa chừng
- Giá trị được cố định
Nó giúp diễn đạt ý định của bạn một cách rõ ràng trong mã.
final int basePrice = 100;
int total = basePrice + 20;
Viết như vậy:
- Giúp ngăn ngừa các thay đổi vô tình
- Khiến người đọc cảm thấy an toàn hơn
Đó là những lợi ích.
6.3 Sử dụng final cho các trường (fields)
Thêm final vào một trường làm cho nó
trở thành một giá trị bất biến cho instance đó.
public class User {
final String name;
public User(String name) {
this.name = name;
}
}
Trong trường hợp này:
namechỉ có thể được đặt một lần trong constructor- Nó không thể được thay đổi sau đó
Đây là một cách thiết kế quan trọng để ổn định trạng thái của đối tượng.
6.4 Lưu ý quan trọng cho final với các kiểu tham chiếu (Sự nhầm lẫn thường gặp của người mới bắt đầu)
Đây là một điểm rất quan trọng:
final int[] numbers = {1, 2, 3};
numbers[0] = 100; // OK
numbers = new int[]{4, 5, 6}; // Error
Tại sao lại xảy ra như vậy?
Lý do là final hạn chế “việc gán lại tham chiếu”.
- Thay đổi nội dung của mảng → OK
- Thay đổi mảng mà biến tham chiếu tới → NG
Nói cách khác, final không làm cho nội dung bất biến.
Nếu bạn không hiểu điều này, bạn có thể bị nhầm lẫn và nghĩ:
- “Tại sao nó vẫn có thể thay đổi dù đã được đánh dấu final?”
- “Đây có phải là lỗi không?”
Đó là lý do tại sao sự phân biệt này quan trọng.
6.5 Hằng số là gì? (static final)
Trong Java, những gì mọi người thường gọi là “hằng số” thường được định nghĩa bằng static final theo quy ước.
public class Config {
public static final int MAX_USERS = 100;
}
Loại hằng số này có các đặc điểm sau:
- Được chia sẻ trong toàn bộ lớp
- Giá trị không thể thay đổi
- Bạn có thể đặt cho nó một tên có ý nghĩa
Quy ước đặt tên cho Hằng số
Hằng số thường được viết theo kiểu sau:
UPPER_SNAKE_CASE
Ví dụ:
static final double TAX_RATE = 0.1;
6.6 Cách quyết định khi nào nên dùng final
Là người mới bắt đầu, các tiêu chí sau rất dễ áp dụng:
- Nếu giá trị không cần thay đổi → thêm
final - Các giá trị cấu hình / giá trị cơ bản → dùng
static final - Nếu thay đổi vô tình sẽ gây vấn đề → thêm
final
Đặc biệt trong thực tế, một quan điểm phổ biến là:
“Nếu không chắc, hãy thêm final.”
Trong nhiều trường hợp, đó là một cân bằng tốt.
6.7 Tóm tắt phần
- Với
final, bạn không thể gán lại biến - Bạn có thể dùng nó cho cả biến cục bộ và trường
finaltrên các kiểu tham chiếu không có nghĩa là “nội dung bất biến”- Hằng số được định nghĩa bằng
static final finallà công cụ để viết mã an toàn, rõ ràng hơn
7. Giá trị khởi tạo, Giá trị mặc định và Các lỗi thường gặp (Phục hồi từ những sai lầm của người mới bắt đầu)
Cho đến nay, bạn đã học về khai báo, kiểu dữ liệu, phạm vi, var, và final. Tuy nhiên, trong thực tế, có rất nhiều tình huống mà “Tôi hiểu về mặt khái niệm, nhưng vẫn gặp lỗi.”
Trong phần này, chúng ta sẽ sắp xếp những điểm khó khăn thường gặp của người mới bắt đầu cùng với các nguyên nhân.
7.1 Biến cục bộ không nhận giá trị mặc định
Đầu tiên, một quy tắc rất quan trọng:
Biến cục bộ không nhận giá trị mặc định tự động
Đoạn mã sau sẽ gây lỗi biên dịch:
public void sample() {
int x;
System.out.println(x); // Error
}
Lý do rất đơn giản: Java không cho phép trạng thái “chúng ta không biết nội dung của x”.
Cách tiếp cận đúng
public void sample() {
int x = 0;
System.out.println(x);
}
Đối với các biến cục bộ, hãy tuân thủ nghiêm ngặt quy tắc: luôn tự mình khởi tạo chúng.
.### 7.2 Các Trường Tự Động Nhận Giá Trị Mặc Định
Ngược lại, các trường (biến instance và biến static)
được tự động gán các giá trị khởi tạo.
public class Sample {
int count;
boolean active;
String name;
}
Các giá trị mặc định như sau:
int→ 0double→ 0.0boolean→ false- Kiểu tham chiếu → null
Do đó đoạn mã sau sẽ không gây lỗi:
public class Sample {
int count;
public void print() {
System.out.println(count); // 0
}
}
Tuy nhiên, các thiết kế dựa vào giá trị mặc định không được khuyến khích.
Chúng làm cho ý định khó nhận biết và dễ trở thành môi trường sinh ra lỗi.
7.3 Lỗi Gây Ra Bởi null (NullPointerException)
Giá trị mặc định cho các kiểu tham chiếu là null.
String text;
Nếu bạn gọi một phương thức trong trạng thái này, sẽ nhận được lỗi thời gian chạy:
System.out.println(text.length()); // NullPointerException
Đây là một trong những ngoại lệ phổ biến nhất mà người mới bắt đầu gặp phải.
Các Biện Pháp Cơ Bản
- Khởi tạo khi có thể
- Xem xét khả năng
null - Thiết kế để tránh sử dụng
nullmột cách không cố ýString text = "";
Ngay cả khi khởi tạo bằng một chuỗi rỗng cũng có thể ngăn ngừa nhiều tai nạn.
7.4 Sử Dụng Biến Ngoài Phạm Vi Của Nó
Đây là một lỗi phổ biến khác:
if (true) {
int value = 10;
}
System.out.println(value); // Error
Đây là vấn đề tham chiếu ra ngoài phạm vi.
valuechỉ hợp lệ bên trong khốiif- Ngoài khối, nó không tồn tại
Hãy xác nhận lại quy tắc này.
7.5 Nhầm Lẫn Khi Các Biến Có Tên Trùng Nhau (Shadowing Được Xem Lại)
public class Sample {
int value = 10;
public void test() {
int value = 5;
System.out.println(value);
}
}
Đoạn mã này in ra 5.
Người mới thường nhầm lẫn rằng:
- Giá trị của trường sẽ được sử dụng
Nhưng thực tế,
phạm vi bên trong được ưu tiên.
Vì shadowing gây ra nhầm lẫn:
- Sử dụng tên biến khác nhau dựa trên vai trò
Hãy ghi nhớ điều này.
7.6 Lỗi Biên Dịch Do Không Khớp Kiểu Dữ Liệu
Việc gán sau không được phép:
int number = 3.14; // Error
Nguyên nhân là:
double→intkhông được tự động chuyển đổi
Đó là quy tắc.
Cách Tiếp Cận Đúng (Khi Bạn Cố Ý Làm Điều Đó)
int number = (int) 3.14; // 3
Tuy nhiên, hãy cẩn thận vì phần thập phân sẽ bị cắt bỏ.
7.7 Tóm Tắt Phần
- Biến cục bộ phải được khởi tạo
- Các trường có giá trị mặc định, nhưng không nên phụ thuộc quá mức vào chúng
nullthường gây ra lỗi thời gian chạy- Bạn không thể sử dụng biến ngoài phạm vi của nó
- Các lỗi không khớp kiểu được ngăn chặn bằng lỗi biên dịch
8. Tóm Tắt: Những Điểm Chính Cần Nắm Vững Đầu Tiên Về Biến Java
Trong bài viết này, chúng tôi đã sắp xếp chủ đề “Biến Java” từng bước,
tập trung vào những điểm mà người mới thường gây nhầm lẫn.
Cuối cùng, hãy tóm tắt các điểm quan trọng
theo dạng hữu ích cho cả việc học và lập trình thực tế.
8.1 Nghĩ Về Biến Java Như Một Bộ “Kiểu, Tên và Giá Trị”
Biến Java luôn đi kèm với ba yếu tố này:
- Kiểu : loại giá trị mà nó chứa
- Tên : đại diện cho giá trị đó
- Giá trị : dữ liệu thực tế được lưu trữ
int count = 10;
Dòng duy nhất này chứa toàn bộ bản chất của biến Java.
8.2 Phân Biệt Rõ Ràng Giữa Khai Báo, Gán Giá Trị và Khởi Tạo
Một bẫy phổ biến của người mới là nhầm lẫn ba khái niệm này:
- Khai báo: chuẩn bị sử dụng một biến
- Gán giá trị: đưa một giá trị vào biến
- Khởi tạo: khai báo và gán giá trị đồng thời
Đặc biệt với các biến cục bộ,
hãy nhớ quy tắc: không thể sử dụng chúng nếu chưa được khởi tạo.
8.3 Nhận Thức Sự Khác Biệt Giữa Kiểu Nguyên Tử và Kiểu Tham Chiếu
Các kiểu Java được chia rộng thành hai loại:
- Các kiểu nguyên thủy: xử lý giá trị chính nó
- Các kiểu tham chiếu: xử lý vị trí (tham chiếu) của giá trị
Giữ sự khác biệt này trong đầu giúp bạn hiểu tự nhiên:
- Sao chép giá trị
- Cách mảng và đối tượng hoạt động
finalthực sự có nghĩa là gì
8.4 Hiểu về Phạm vi Giảm Lỗi Một Cách Đáng Kể
Biến chỉ có thể được sử dụng trong nơi chúng được khai báo.
- Biến cục bộ → chỉ hợp lệ bên trong khối
- Trường (fields) → có sẵn trong suốt lớp
- Biến static → được chia sẻ qua lớp
Nếu bạn từng nghĩ “Tôi không biết tại sao không thể sử dụng nó,”
nghi ngờ phạm vi trước tiên.
8.5 Sử dụng var và final Dựa trên Mục đích
var→ Chỉ sử dụng khi kiểu rõ ràng và cải thiện khả năng đọcfinal→ Sử dụng để thể hiện rõ ý định “giá trị này không nên thay đổi”
Cả hai đều tiện lợi, nhưng hãy cẩn thận không biến “sử dụng chúng” thành mục tiêu chính.
8.6 Hướng dẫn cho Người mới bắt đầu Viết An toàn
Trong giai đoạn học tập, các chính sách sau giảm lỗi:
- Khởi tạo biến khi khai báo chúng
- Viết kiểu rõ ràng nhất có thể
- Sử dụng tên có ý nghĩa
- Nếu không chắc chắn, thử thêm
final
Chỉ riêng điều này thôi cũng đưa bạn gần hơn với mã Java dễ đọc và an toàn.
8.7 Các Chủ đề Tiếp theo để Học cho Hiểu Biết Sâu hơn
Sau khi hiểu về biến, khuyến nghị chuyển sang:
- Câu lệnh điều kiện (
if/switch) - Vòng lặp (
for/while) - Mảng và bộ sưu tập (List / Map)
- Phương thức và tham số
- Cơ bản hướng đối tượng
Biến là nền tảng của tất cả mã Java.
Bằng cách hiểu chúng kỹ lưỡng, việc học sau này của bạn trở nên mượt mà hơn đáng kể.

