Backend

99 Ngày Java — Ngày 03: Biến & kiểu dữ liệu nguyên thủy

SSite Admin
31 tháng 07, 2026 5 phút đọc 179 lượt xem
99 Ngày Java — Ngày 03: Biến & kiểu dữ liệu nguyên thủy

Hai ngày đầu bạn đã chạy được chương trình và hiểu tường tận hàm main. Hôm nay lập trình thật sự bắt đầu: biến — chiếc hộp có tên để cất dữ liệu — và 8 kiểu dữ liệu nguyên thủy, những viên gạch nhỏ nhất mà mọi chương trình Java, từ Hello World đến hệ thống ngân hàng, đều xây lên từ đó.

Sketchnote Ngày 03: Biến và 8 kiểu dữ liệu nguyên thủy trong Java

Biến là gì?

Hãy hình dung bộ nhớ là một dãy tủ khóa. Biến là một ngăn tủ được đặt tên: bạn khai báo kiểu (ngăn to cỡ nào, đựng loại gì) và tên (nhãn dán ngoài cửa), rồi cất giá trị vào. Java là ngôn ngữ kiểu tĩnh (statically typed) — mỗi biến phải khai báo kiểu ngay từ đầu và giữ nguyên kiểu đó suốt đời, khác với Python hay JavaScript.

int age = 25;              // khai báo + khởi tạo một dòngdouble price = 19.99;
boolean isActive = true;

int score;                 // khai báo trước...
score = 90;                // ...gán giá trị sau

Quy tắc đặt tên: bắt đầu bằng chữ cái (không phải số), phân biệt hoa thường, và theo quy ước camelCasestudentCount chứ không phải student_count hay StudentCount. Tên biến nên nói rõ nó chứa gì: age tốt hơn a gấp nhiều lần khi đọc lại code sau một tuần.

8 kiểu dữ liệu nguyên thủy

Java có đúng 8 kiểu nguyên thủy (primitive types) — học thuộc hôm nay, dùng cả sự nghiệp. Chia làm 4 nhóm: số nguyên (byte, short, int, long), số thực (float, double), ký tự (char) và logic (boolean):

byte    b  = 127;              // 1 byte  : -128 → 127short   s  = 32_000;           // 2 bytes : ±32,767int     i  = 2_000_000_000;    // 4 bytes : ±2,1 tỷ — mặc định cho số nguyênlong    l  = 9_000_000_000L;   // 8 bytes : cần hậu tố Lfloat   f  = 3.14f;            // 4 bytes : cần hậu tố fdouble  d  = 3.14159265358979; // 8 bytes : mặc định cho số thựcchar    c  = 'J';              // 2 bytes : MỘT ký tự UTF-16, nháy đơnboolean ok = true;             // true / false
  • Dấu gạch dưới _ trong literal số (2_000_000_000) chỉ để dễ đọc — compiler bỏ qua hoàn toàn.

  • Số nguyên viết thẳng (9_000_000_000) mặc định là int — vượt phạm vi int là lỗi compile, nên literal long cần hậu tố L.

  • Số thực viết thẳng (3.14) mặc định là double — muốn float phải thêm f, nếu không compiler báo "possible lossy conversion".

  • char dùng nháy đơn cho một ký tự ('J'); nháy kép là String — không phải kiểu nguyên thủy, hẹn Ngày 09.

Vì sao gọi là "nguyên thủy"? Vì chúng không phải object: giá trị nằm trực tiếp trong biến, không có method nào để gọi, nhờ vậy cực nhanh và gọn. Mỗi kiểu có phiên bản wrapper object tương ứng (Integer, Double…) — chuyện của Ngày 22.

Giá trị mặc định — field có, biến local không

Đây là điểm hay bị hỏi khi phỏng vấn: field (biến khai báo trong class) được JVM tự gán giá trị mặc định — số về 0, boolean về false, char về '\u0000'. Nhưng biến local (khai báo trong method) thì không có mặc định — dùng khi chưa khởi tạo là compiler chặn ngay:

public class Defaults {
    static int counter;      // field: tự nhận 0
    static boolean flag;     // field: tự nhận false

    public static void main(String[] args) {
        System.out.println(counter); // 0
        System.out.println(flag);    // false

        int local;
        // System.out.println(local); // ❌ KHÔNG compile: biến local
        //                            //    chưa được khởi tạo
    }
}

Compiler khó tính ở đây là để cứu bạn: một biến "quên khởi tạo" trong C có thể mang giá trị rác ngẫu nhiên và gây bug ma quái — Java chọn cách từ chối biên dịch ngay từ đầu.

Overflow — khi chiếc hộp tràn

Mỗi kiểu có phạm vi hữu hạn. int dùng 4 byte nên chỉ đếm được tới 2_147_483_647 (Integer.MAX_VALUE). Cộng thêm 1? Java không báo lỗi — giá trị lặng lẽ quay vòng về số âm nhỏ nhất, như đồng hồ công-tơ-mét quay hết vòng:

int max = Integer.MAX_VALUE;       // 2_147_483_647
System.out.println(max + 1);       // -2147483648 — quay vòng về âm!

long safe = (long) max + 1;        // 2147483648 — ép sang long TRƯỚC khi cộng
System.out.println(safe);

Math.addExact(max, 1);             // ném ArithmeticException — sai thì báo,
                                   // không sai lặng lẽ

Overflow từng gây sự cố thật: YouTube phải nâng bộ đếm view của Gangnam Style lên long khi video vượt 2,1 tỷ lượt xem. Bài học: đại lượng có thể lớn (view, tiền theo đơn vị nhỏ nhất, timestamp) — dùng long ngay từ đầu; phép tính nhạy cảm — dùng Math.addExact để sai là ném exception thay vì sai lặng lẽ.

Chọn kiểu nào cho đúng?

  • Số nguyên: cứ int mà dùng — nhanh, đủ cho hầu hết trường hợp. Chỉ lên long khi giá trị có thể vượt 2,1 tỷ.

  • Số thực: mặc định doublefloat gần như chỉ còn trong đồ họa/mảng lớn cần tiết kiệm bộ nhớ.

  • Tiền tệ: đừng dùng float/double! Số thực nhị phân không biểu diễn chính xác 0.1 — Ngày 27 ta học BigDecimal cho việc này.

  • byte/short hiếm khi cần — chủ yếu khi làm việc với file nhị phân, mạng, hoặc mảng rất lớn.

  • boolean cho mọi cờ trạng thái — đặt tên dạng khẳng định: isActive, hasError.

Bài tập nhỏ

  • Khai báo đủ 8 biến cho 8 kiểu nguyên thủy, in từng biến ra màn hình.

  • In Integer.MAX_VALUE + 1Integer.MIN_VALUE - 1 — quan sát chiều quay vòng của overflow.

  • Thử gán int big = 3_000_000_000; rồi đọc kỹ thông báo lỗi của compiler — sửa bằng cách nào?

  • In 0.1 + 0.2 và giải thích vì sao kết quả không phải 0.3 — gợi ý cho Ngày 27.

Kết luận

Bạn đã biết biến là gì, thuộc mặt 8 kiểu nguyên thủy, hiểu vì sao biến local phải khởi tạo trước khi dùng và overflow nguy hiểm ra sao. Ngày 04, ta cho những chiếc hộp này "nói chuyện" với nhau bằng toán tử và biểu thức — cộng trừ nhân chia, so sánh, logic và cả toán tử 3 ngôi bí ẩn. Hẹn gặp lại!

S

Site Admin

Engineer and writer. Building things with TypeScript and distributed systems.

Bình luận (0)

Bạn cần đăng nhập bằng Google để bình luận.

Hãy là người bình luận đầu tiên.

Bài viết liên quan

99 Ngày Spring — Ngày 14: Bean Validation — @Valid & bộ constraint chuẩn

Ngày 14 của 99 Ngày Spring: Bean Validation khai báo luật ngay trên DTO — @Valid kích hoạt, bộ constraint chuẩn (@NotBlank vs @NotEmpty vs @NotNull, @Size, @Email, @Min/@Max), bẫy int vs Integer, validate object lồng nhau không tự lan, và lỗi 400 gom một lượt.

10 thg 8, 20265 phút0
99 Ngày Java — Ngày 14: Kế thừa (Inheritance)

Ngày 14 của 99 Ngày Java: extends trao gia tài từ lớp cha, override với @Override và super., thứ tự khai sinh cha trước con sau qua super(...), protected trả nợ Ngày 13, và phép thử is-a vs has-a — khi nào nên composition thay vì kế thừa.

10 thg 8, 20266 phút0
99 Ngày Spring — Ngày 13: @RequestBody & DTO — đừng công khai entity ra API

Ngày 13 của 99 Ngày Spring: @RequestBody + Jackson deserialize JSON thành object, DTO là hợp đồng API — chặn lỗ hổng mass assignment chiều vào và rò rỉ dữ liệu chiều ra, request/response DTO khác nhau là bình thường, và Jackson annotations tinh chỉnh hợp đồng JSON.

9 thg 8, 20266 phút9