Đây là bài thực hành khép lại Module 2. Không có lý thuyết mới — chỉ có một bài toán thực tế để bạn kết hợp những gì vừa học: double cho tính toán thực, String.format xuất 2 chữ số thập phân, và enum có field để phân loại BMI theo WHO.
🎯 Đề bài
Viết chương trình Java tính chỉ số BMI (Body Mass Index) và phân loại theo WHO. Người dùng nhập cân nặng và chiều cao từ console.
Output mẫu:
Nhap can nang (kg): 65
Nhap chieu cao (m): 1.70
BMI: 22.49
Phan loai: Binh thuong
Yêu cầu:
- Nhập cân nặng (kg) và chiều cao (m) từ
Scanner - Tính BMI theo công thức WHO
- Hiển thị BMI làm tròn 2 chữ số thập phân
- Phân loại đúng theo ngưỡng WHO
- Dùng
enumcó field để mã hoá phân loại và tên hiển thị
🔍 Phân tích I-P-O
Input: Cân nặng double (kg), chiều cao double (m) — nhập từ Scanner
Processing:
- Tính BMI = cân nặng / (chiều cao × chiều cao)
- Phân loại theo ngưỡng WHO:
| BMI | Phân loại |
|---|---|
| < 18.5 | Gầy |
| 18.5 – 24.9 | Bình thường |
| 25.0 – 29.9 | Thừa cân |
| ≥ 30.0 | Béo phì |
Output: BMI dạng %.2f + tên phân loại
📦 Concept dùng trong bài
| Concept | Bài đã học | Dùng ở đây |
|---|---|---|
Scanner nhập từ console | Module 1, bài 5 | Đọc canNang, chieuCao |
double tính toán thực | Module 2, bài 2 | Tính BMI tránh integer division |
String.format("%.2f", x) | Module 2, bài 6 | In BMI 2 chữ số thập phân |
enum có field + static factory | Module 2, bài 7 | PhanLoai với tên hiển thị và tuBmi() |
if/else if rẽ nhánh | Sẽ học Module 3 | Dùng tạm trong static factory |
| try-with-resources | Sẽ học sau | Tự đóng Scanner khi xong |
▶️ Starter code
Copy file này, điền vào các TODO:
import java.util.Scanner;
public class BmiCalculator {
// TODO: dinh nghia enum PhanLoai voi 4 values: GAY, BINH_THUONG, THUA_CAN, BEO_PHI
// moi value co field String hienThi (ten hien thi tieng Viet ASCII)
// them static method tuBmi(double bmi) tra ve PhanLoai tuong ung
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
System.out.print("Nhap can nang (kg): ");
double canNang = sc.nextDouble();
System.out.print("Nhap chieu cao (m): ");
double chieuCao = sc.nextDouble();
// TODO: tinh BMI
// TODO: lay PhanLoai tu BMI
// TODO: in BMI voi 2 chu so thap phan
// TODO: in phan loai
}
}
}
Dành 15–20 phút thử tự làm trước khi xem gợi ý.
javac BmiCalculator.java
java BmiCalculator
💡 Gợi ý
💡 💡 Gợi ý — đọc khi bị kẹt
Công thức BMI:
double bmi = canNang / (chieuCao * chieuCao);
Định nghĩa enum với field:
enum PhanLoai {
GAY("Gay"),
BINH_THUONG("Binh thuong"),
THUA_CAN("Thua can"),
BEO_PHI("Beo phi");
private final String hienThi;
PhanLoai(String hienThi) {
this.hienThi = hienThi;
}
public String getHienThi() { return hienThi; }
}
Static factory method bên trong enum:
public static PhanLoai tuBmi(double bmi) {
if (bmi < 18.5) return GAY;
if (bmi < 25) return BINH_THUONG;
if (bmi < 30) return THUA_CAN;
return BEO_PHI;
}
In BMI 2 chữ số thập phân:
System.out.printf("BMI: %.2f%n", bmi);
// hoac:
System.out.println("BMI: " + String.format("%.2f", bmi));
try-with-resources cho Scanner — Scanner implement Closeable, dùng được với try-with-resources để tự đóng khi ra khỏi block:
try (Scanner sc = new Scanner(System.in)) {
// dung sc o day
}
// sc tu dong dong -- khong can sc.close()
✅ Lời giải
ℹ️ ✅ Lời giải — xem sau khi đã thử
import java.util.Scanner;
public class BmiCalculator {
enum PhanLoai {
GAY("Gay"),
BINH_THUONG("Binh thuong"),
THUA_CAN("Thua can"),
BEO_PHI("Beo phi");
private final String hienThi;
PhanLoai(String hienThi) {
this.hienThi = hienThi;
}
public String getHienThi() {
return hienThi;
}
public static PhanLoai tuBmi(double bmi) {
if (bmi < 18.5) return GAY;
if (bmi < 25) return BINH_THUONG;
if (bmi < 30) return THUA_CAN;
return BEO_PHI;
}
}
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
System.out.print("Nhap can nang (kg): ");
double canNang = sc.nextDouble();
System.out.print("Nhap chieu cao (m): ");
double chieuCao = sc.nextDouble();
double bmi = canNang / (chieuCao * chieuCao);
PhanLoai pl = PhanLoai.tuBmi(bmi);
System.out.printf("BMI: %.2f%n", bmi);
System.out.println("Phan loai: " + pl.getHienThi());
}
}
}
Giải thích từng phần:
enum PhanLoaivới fieldhienThi— mỗi value mang tên hiển thị riêng, tách biệt với tên khai báo (BINH_THUONGvs"Binh thuong"). Không cầnswitchrải rác khắp nơi.static PhanLoai tuBmi(double bmi)— static factory method ngay trong enum: truyền vào BMI, nhận về phân loại đúng kiểu. Logic phân loại đóng gói trong một chỗ.try (Scanner sc = ...)— try-with-resources: Java tự gọisc.close()khi ra khỏi block dù có exception hay không. Tránh resource leak.printf("BMI: %.2f%n", bmi)—%.2flàm tròn đến 2 chữ số thập phân theo standard rounding;%nxuống dòng platform-independent.- Tại sao
doublechocanNangvàchieuCao? —sc.nextDouble()đọc số thực. Nếu dùngint, người nhập1.70sẽ gây lỗi parse. BMI = cân/cao² cần tính toán thực — haidoubleđảm bảo không xảy ra integer division.
🎓 Mở rộng
Đã hoàn thành bài cơ bản? Thử tiếp:
Mức 1 — Validate input:
if (canNang <= 0 || chieuCao <= 0 || chieuCao > 3.0) {
System.out.println("Input khong hop le. Can nang > 0 va chieu cao 0 < h <= 3.0");
return;
}
Mức 2 — Xử lý exception khi nhập sai định dạng:
import java.util.InputMismatchException;
try {
double canNang = sc.nextDouble();
} catch (InputMismatchException e) {
System.out.println("Loi: vui long nhap so thuc, vi du 65.5");
}
Mức 3 — Lặp lại cho đến khi người dùng gõ quit:
System.out.print("Nhap can nang (kg) hoac 'quit' de thoat: ");
String input = sc.next();
if ("quit".equalsIgnoreCase(input)) break;
double canNang = Double.parseDouble(input);
Mức 4 — Tính khoảng cân nặng lý tưởng:
// BMI ly tuong: 18.5 -- 24.9
double canNangMin = 18.5 * chieuCao * chieuCao;
double canNangMax = 24.9 * chieuCao * chieuCao;
System.out.printf("Can nang ly tuong: %.1f -- %.1f kg%n", canNangMin, canNangMax);
✨ Điều bạn vừa làm được
Hoàn thành mini-challenge này, bạn đã:
- Kết hợp
Scannernhập liệu từ console vớidoublecho tính toán thực — tránh integer division khi tính BMI - Dùng
String.format("%.2f", ...)/printfđể kiểm soát số chữ số thập phân trong output - Định nghĩa
enumcó field và static factory method — đóng gói phân loại + tên hiển thị + logic lookup trong một chỗ - Áp dụng try-with-resources để
Scannertự đóng, không lo resource leak - Thực hành tư duy I-P-O: phân tích bài toán thành Input, Processing, Output trước khi viết code
Chúc mừng — bạn đã hoàn thành Module 2! Module 3 sẽ đi vào cấu trúc điều kiện và vòng lặp: if/else, switch, for, while — những công cụ để điều khiển luồng chạy của chương trình.