Giảng giải chi tiết cho người mới học Java và hướng đối tượng
Tài liệu này giảng lại từng bài tập từ số 0: đề nói gì, từ mới nào cần biết, ý tưởng làm sao, từng dòng code nghĩa gì, và bẫy nào hay vấp. Đọc xong phần 0 và 1 thì đọc tiếp đúng Lab mình đang học.
0. Java từ số 0
0.1. Viết code ở đâu, chạy thế nào
- Code Java nằm trong file đuôi
.java. Một file là một lớp (class), tên file phải giống hệt tên lớp, kể cả hoa thường. Ví dụ lớpChao2nằm trongChao2.java. - Muốn chạy phải cài JDK (bộ công cụ Java). Hai lệnh duy nhất cần nhớ:
javac TenFile.javađể biên dịch (dịch code thành mã máy),java TenLopđể chạy (chú ý:javakhông có.java). - Lỗi khi biên dịch gọi là lỗi biên dịch (sai chính tả, thiếu dấu). Lỗi khi đang chạy gọi là lỗi runtime (chia 0, truy cập ô nhớ rỗng).
0.2. Chương trình đầu tiên mổ xẻ
public class Chao2 {
public static void main(String[] args) {
System.out.println("Chao");
}
}
- Dòng 1: khai báo lớp tên
Chao2. Mọi code đều phải nằm trong một lớp. - Dòng 2: hàm
main— cửa ra vào, chương trình luôn bắt đầu từ đây. Đừng hỏi vì sao dài thế, cứ chép đúng:public static void main(String[] args). - Dòng 3: in ra màn hình rồi xuống dòng. Muốn in không xuống dòng
dùng
printthay choprintln. - Dấu
{ }gom một khối lệnh. Mỗi lệnh kết thúc bằng dấu;. Quên;là lỗi biên dịch đầu tiên ai cũng gặp.
0.3. Biến và kiểu dữ liệu
Biến là cái hộp có dán nhãn, đựng dữ liệu. Java bắt khai báo hộp đựng gì:
| Kiểu | Đựng gì | Ví dụ |
|---|---|---|
int |
số nguyên | int n = 10; |
double |
số thực | double r = 3.5; |
String |
chuỗi chữ (hoa S) | String ten = "An"; |
boolean |
chỉ true/false |
boolean ok = true; |
char |
1 ký tự (nháy đơn) | char c = 'e'; |
Bẫy số 1 của người mới: int / int ra int.
5 / 2 bằng 2, không phải 2.5. Muốn số thực phải có một bên là
double: 5 / 2.0 bằng 2.5, hoặc ép kiểu (double) tong / soLuong.
0.4. Nhập dữ liệu bằng Scanner
import java.util.Scanner; // dòng xin phép dùng Scanner
Scanner sc = new Scanner(System.in); // mở micro nghe bàn phím
int n = sc.nextInt(); // đọc 1 số nguyên
double r = sc.nextDouble(); // đọc 1 số thực
sc.nextLine(); // đọc cả dòng chữ (sau nextInt phải gọi 1 lần để nuốt Enter thừa)
String ten = sc.nextLine();
sc.close(); // dùng xong đóng lại
0.5. Rẽ nhánh và vòng lặp
if (n < 0) { // nếu đúng thì làm khối này
System.out.println("sai");
} else { // ngược lại làm khối này
System.out.println("dung");
}
for (int i = 0; i < n; i++) { // lặp n lần, i = 0, 1, ..., n-1
System.out.print(i + " ");
}
while (a < x) { // lặp khi điều kiện còn đúng
a = a + b;
}
% là phép chia lấy dư: 7 % 2 bằng 1. Dư 0 tức là chia hết —
đây là cách kiểm tra chẵn lẻ và kiểm tra nguyên tố.
0.6. Mảng: dãy hộp đánh số từ 0
int[] a = new int[n]; // xin n hộp int, đánh số a[0] .. a[n-1]
a[0] = 5; // gán hộp đầu tiên
System.out.println(a.length); // số hộp = n
Ba quy tắc sống còn:
- Ô đầu tiên là
a[0], ô cuối làa[n-1]. Không cóa[n]. - Vòng lặp duyệt mảng luôn viết
i < n, không bao giời <= n. Thêm dấu=là tràn mảng, chương trình chết ngay. - Kiểm tra
n > 0trước khinew int[n].
1. Hướng đối tượng từ số 0
1.1. Object là gì
Lớp (class) là bản thiết kế, đối tượng (object) là sản phẩm đúc từ
bản thiết kế đó. Lớp SinhVien là bản thiết kế chung;
new SinhVien("An", ...) đúc ra một sinh viên cụ thể tên An.
- Thuộc tính = dữ liệu object nắm giữ (tên, điểm).
- Phương thức = việc object làm được (tính điểm, in ra).
SinhVien sv = new SinhVien("Nguyen Van An", d1, d2); // đúc object
System.out.println(sv.tinhDTB()); // gọi phương thức: object.tênViệc()
new nghĩa là đúc mới. Dấu chấm . nghĩa là "của": sv.tinhDTB()
là "tính điểm trung bình của sv".
1.2. Đóng gói: giấu dữ liệu bằng private
public class PS {
private int tu; // private = chỉ code trong lớp này được đụng
private int mau;
public int layTu() { return tu; } // getter: cho đọc
public void ganTu(int tu) { this.tu = tu; } // setter: cho sửa
}
private là khóa tủ. Muốn lấy/sửa phải qua getter/setter (cửa có
người gác). Setter tốt còn kiểm tra trước khi nhận:
public void ganMau(int m) { if (m != 0) { this.mau = m; } } // mẫu 0 thì từ chối
this nghĩa là "của chính tôi": this.tu là thuộc tính tu của object
hiện tại, phân biệt với tham số tu truyền vào.
1.3. Constructor: lò đúc object
Constructor là phương thức tên giống hệt lớp, không có kiểu trả về,
chạy đúng 1 lần lúc new:
public PS(int tu, int mau) {
this.tu = tu;
this.mau = (mau == 0) ? 1 : mau; // mẫu 0 thì tự sửa thành 1
chuanHoa();
}
Dòng (mau == 0) ? 1 : mau đọc là: "mẫu bằng 0 thì lấy 1,
không thì lấy mẫu". Đây là if viết gọn 1 dòng.
1.4. Kế thừa: lớp con dùng lại code lớp cha
public class HPLyThuyet extends DiemHP { ... } // LyThuyet KẾ THỪA DiemHP
extends nghĩa là "kế thừa": lớp con có sẵn mọi thứ public của lớp cha,
chỉ viết thêm phần riêng. Constructor lớp con phải gọi super(...)
(đúc phần của cha) ở dòng đầu tiên:
public HPLyThuyet(String ten, int tc, ...) {
super(ten, tc); // đúc phần cha trước, bắt buộc dòng đầu
...
}
1.5. Đa hình: cùng một lời gọi, mỗi đứa làm khác nhau
Lớp cha khai báo khung, lớp con mỗi đứa viết ruột riêng:
public abstract class BuuPham {
public abstract double phiGui(); // khung: chưa biết tính sao
}
public class Thu extends BuuPham {
public double phiGui() { return 800; } // ruột của Thư
}
public class BuuKien extends BuuPham {
public double phiGui() { return 5000; } // ruột của Bưu kiện
}
abstract nghĩa là "dở dang": lớp dở dang không đúc object trực tiếp
được, chỉ để kế thừa. Cái hay: một danh sách BuuPham[] đựng chung cả
Thư lẫn Bưu kiện, gọi phiGui() thì mỗi đứa tự tính giá của mình —
gọi là đa hình. @Override dán trên phương thức viết lại để trình
biên dịch kiểm tra giúp mình.
2. Lab 01 giảng cho người mới
2.1. Chao2 — tham số dòng lệnh là gì
Chạy java Chao2 Nguyen Van An, mấy chữ sau tên lớp gọi là tham số
dòng lệnh, Java hứng vào mảng args: args[0]="Nguyen",
args[1]="Van", args[2]="An".
if (args.length == 0) { // không gõ tên thì nhắc rồi dừng
System.out.println("Cach dung: java Chao2 <ten>");
return; // return trong main = dừng chương trình
}
String ten = "";
for (int i = 0; i < args.length; i++) {
ten += args[i]; // nối từng chữ
if (i < args.length - 1) ten += " "; // chữ chưa phải cuối thì thêm cách
}
ten += args[i] là viết gọn của ten = ten + args[i].
Điều kiện i < args.length - 1 để không thừa dấu cách ở cuối.
2.2. DocSo — switch-case và break
switch là "xem giá trị rồi nhảy đúng nhánh". Mỗi nhánh case phải
có break, không là rơi xuống nhánh dưới:
switch (n) {
case 7: System.out.println("bay"); break; // đúng n=7: in rồi THOÁT
default: System.out.println("chin"); break; // còn lại rơi hết vào đây
}
Vì chỉ viết tới case 8 nên số 9 rơi vào default in "chin".
Trước switch đã chặn n < 0 || n > 9 in "Khong hop le" —
đây gọi là kiểm tra miền giá trị: không cho số lạ đi tiếp.
2.3. HinhTron — kiểm tra trước khi tính
double r = sc.nextDouble();
if (r <= 0) {
System.out.println("Ban kinh phai duong");
sc.close();
return; // số sai thì dừng, không tính tiếp
}
double dienTich = Math.PI * r * r; // Math.PI là số pi có sẵn
Math.round(dienTich * 100) / 100.0 là mẹo làm tròn 2 chữ số:
nhân 100 → làm tròn thành nguyên → chia 100.0.
Chia cho 100.0 (số thực) để không rơi vào bẫy chia nguyên.
2.4. GiaiThua — int tràn số
5! = 1*2*3*4*5 = 120. Vòng lặp bắt đầu từ 2 vì nhân thêm 0, 1
không đổi kết quả (kq khởi đầu bằng 1 — phần tử trung hòa của
phép nhân, giống số 0 của phép cộng).
Vì sao long mà không int? int chứa tối đa ~2.1 tỉ,
12! đã 479 triệu, 13! là 6.2 tỉ → tràn. long chứa tới 9e18.
Số âm thì báo "n phai >= 0" rồi dừng.
2.5. NguyenToTrongMang — hàm kiểm tra viết riêng
public static boolean laNguyenTo(int n) {
if (n < 2) return false; // 0, 1 và số âm: loại ngay
for (int i = 2; i <= Math.sqrt(n); i++)
if (n % i == 0) return false; // tìm được ước thì không phải
return true;
}
Vì sao chỉ cần tới căn bậc hai? Ước luôn đi theo cặp
(100 = 4 × 25), một trong hai không vượt quá căn.
return false giữa chừng nghĩa là "kết luận luôn, khỏi kiểm tiếp".
static nghĩa là hàm của lớp, gọi thẳng laNguyenTo(x) mà không
cần đúc object — vì nó không đụng thuộc tính của object nào cả.
2.6. FibonacciTrongMang — sinh dãy để đối chiếu
Dãy Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13..., số sau bằng tổng hai số trước.
Hàm laFibonacci(x) sinh dãy tới khi a >= x, rồi xem có trúng không:
int a = 0, b = 1;
while (a < x) { int tiep = a + b; a = b; b = tiep; } // bước lên 1 nấc
return a == x;
Muốn hiểu thì chạy tay: x=5: (0,1)→(1,1)→(1,2)→(2,3)→(3,5),
dừng vì a=5, 5==5 → đúng.
2.7. SapXepNgauNhien — sắp xếp nổi bọt
(int)(Math.random() * 100) sinh số nguyên 0..99.
Sắp xếp nổi bọt: đi từng cặp kề nhau, sai thứ tự thì đổi chỗ,
số lớn "nổi" dần về cuối như bọt nước:
if (a[j] > a[j + 1]) { int tmp = a[j]; a[j] = a[j + 1]; a[j + 1] = tmp; }
Đổi chỗ cần biến tạm tmp như đổi nước hai cốc cần cốc thứ ba.
Vòng ngoài chạy n-1 lượt vì sau mỗi lượt, một số đã về đúng chỗ.
3. Lab 02 giảng cho người mới
3.1. PS — rút gọn phân số bằng UCLN
Phân số 6/9 phải rút thành 2/3 bằng cách chia cả tử mẫu cho
ước chung lớn nhất (UCLN). Tìm UCLN bằng thuật toán Euclid:
lấy dư liên tục tới khi dư 0:
int a = Math.abs(tu), b = Math.abs(mau);
while (b != 0) { int r = a % b; a = b; b = r; } // a còn lại là UCLN
if (a != 0) { tu /= a; mau /= a; }
Chạy tay 6/9: (6,9)→ dư 6 →(9,6)→ dư 3 →(6,3)→ dư 0 → dừng,
UCLN=3, chia ra 2/3. if (a != 0) để tử 0 không bị chia 0.
3.2. PS — cộng trừ nhân chia
Muốn cộng 1/2 + 5/7: quy đồng mẫu chung 2*7=14,
tử mới là 1*7 + 5*2 = 17 → 17/14. Code y hệt công thức:
public PS cong(PS p) { return new PS(tu * p.mau + p.tu * mau, mau * p.mau); }
Chú ý: các phép toán trả về phân số mới (new PS), không sửa
phân số cũ. Còn tang, gap, rutGon (không trả về gì — void)
thì sửa trực tiếp object hiện tại. Hai kiểu này khác nhau, đừng lẫn.
Ví dụ kiểm tra t = 2*p - p/q với p=1/2, q=5/7:
2p = 1 (viết thành 1/1), p/q = 1/2 ÷ 5/7 = 7/10,
1 - 7/10 = 3/10. Nhiều bạn nhầm 2p = 2 nên ra sai.
3.3. PS — so sánh và sắp xếp
So sánh bằng nhân chéo: 1/2 với 5/7 thì so 1*7 với 5*2,
7 < 10 nên 1/2 < 5/7. Không chia số thực nên không sợ sai số.
Sắp xếp 5 phân số dùng nổi bọt, nhưng so object thì gọi
ds[j].soSanh(ds[j+1]) > 0 thay vì ds[j] > ds[j+1]
(object không so bằng > được).
3.4. ATM — boolean và luật nghiệp vụ
rutTien trả về boolean (đúng/sai) thay vì in ra:
public boolean rutTien(double st) {
if (st <= 0 || st > soDu) return false; // tiền sai hoặc không đủ: từ chối
soDu -= st; // đủ thì trừ rồi báo thành công
return true;
}
chuyenTien dùng lại rutTien rồi napTien — viết code kiểu này
gọi là tái sử dụng, khỏi kiểm tra số dư lần nữa.
tk == null || tk == this chặn chuyển cho tài khoản rỗng và tự chuyển
cho chính mình. final trên soTK nghĩa là số tài khoản không đổi
suốt đời object.
Thử tay với code mẫu: 5 tài khoản tổng 1000+100+100+100+100=1400 (tài khoản 50 tự nâng lên 100 vì dưới mức tối thiểu). Nạp 1000 vào TK1 → 2000. Chuyển 500 sang TK2: TK1 còn 1500, TK2 thành 600. Rút 200 ở TK2 → 400. Rút 99999 → từ chối. Tổng cuối 1500+400+100+100+100 = 2200.0. Khớp output mẫu.
3.5. PTB2 — chia mọi trường hợp trước khi code
Nguyên tắc: liệt kê trường hợp rồi mới viết code.
a == 0 thì hết là bậc hai: b == 0 nữa thì c == 0 vô số nghiệm,
ngược lại vô nghiệm; còn b khác 0 thì nghiệm x = -c/b.
a khác 0 mới tính delta: âm vô nghiệm, bằng 0 nghiệm kép -b/2a,
dương thì hai nghiệm với Math.sqrt(delta).
Phương thức giai() trả về chuỗi thay vì in — để main chỉ việc
in ra, sau này muốn dùng kết quả vào việc khác vẫn được.
3.6. NhanVien — công thức lương đọc từ code
public double luong() { return (heSoLuong + phuCap()) * luongCoBan; }
Phụ cấp theo chức vụ: GD 1.0, PGD 0.8, TP 0.5, PP 0.4, còn lại 0.
chucVu.equals("GD") — so chuỗi bắt buộc .equals,
== chỉ so địa chỉ ô nhớ. Ví dụ Nguyễn Văn A:
(5.0 + 1.0) * 1500000 = 9000000, trừ BHXH 6% và BHTN 1%
còn thực lĩnh 9000000 * 0.93 = 8370000. Khớp output mẫu.
tuoi() lấy năm 2026 trừ năm sinh. Date cũ lưu năm = năm thực − 1900
nên phải cộng lại 1900 — đây là cái bẫy của thư viện cũ, cứ nhớ công thức.
4. Lab 03 giảng cho người mới
4.1. Diem — setter có gác cổng
public void setCuoiKy(double d) { if (d >= 0 && d <= 10) cuoiKy = d; }
Điểm ngoài 0..10 thì lờ đi (giữ giá trị cũ), không báo lỗi.
Thử trong code mẫu: d1.setCuoiKy(15) bị từ chối nên
getCuoiKy() vẫn là 7. Đây là ý nghĩa của đóng gói: dữ liệu sai
không bao giờ lọt vào object. Tín chỉ cũng vậy, chỉ nhận 1..4.
tinhDiem() = chuyenCan*0.1 + giuaKy*0.2 + cuoiKy*0.7 —
cuối kỳ hệ số cao nhất nên 1 điểm cuối kỳ đáng giá gấp 7 lần chuyên cần.
4.2. SinhVien — quan hệ HAS-A và trung bình trọng số
SinhVien chứa hai object Diem — quan hệ "có một"
(HAS-A): sinh viên có các điểm môn. Điểm tích lũy:
return (dm1.tinhDiem() * tc1 + dm2.tinhDiem() * tc2) / (tc1 + tc2);
Môn 3 tín chỉ phải "nặng" gấp 3 môn 1 tín chỉ — cộng đều rồi chia 2
là sai. Thử tay bạn An: Java 9*0.1+8*0.2+7*0.7 = 7.4 (3 TC),
Toán 6*0.1+7*0.2+8*0.7 = 7.6 (2 TC),
tích lũy (7.4*3 + 7.6*2)/5 = 37.4/5 = 7.48. Khớp output mẫu.
if (tc1 + tc2 == 0) return 0 chặn chia 0.
4.3. SinhVienMoRong — mảng object và số lượng thật
Mảng new Diem[soMonToiDa] lúc đầu toàn ô rỗng (null).
Biến soHP đếm số môn đã thêm thật. Mọi vòng lặp chỉ chạy tới
soHP, không bao giờ tới dsHP.length — đây là mẫu chuẩn
"danh sách trên mảng", gặp lại ở Lab 04, 05:
public boolean themHP(Diem d) {
if (d == null || soHP >= dsHP.length) return false; // rỗng hoặc đầy: từ chối
dsHP[soHP] = d; soHP++; return true;
}
Vì sao in ra 7.82 chứ không phải 7.83? Máy tính lưu số thực dạng nhị
phân, 7.82 thật ra là 7.8249999..., làm tròn 2 chữ số còn 7.82.
Nhớ: không bao giờ so double bằng ==.
4.4. DiemToaDo và HCN — tái sử dụng lớp
HCN không lưu 4 số rời rạc mà lưu hai object DiemToaDo
(góc trên-trái, góc dưới-phải) — tái sử dụng lớp đã có.
Dài = trị tuyệt đối hiệu hoành độ, rộng = trị tuyệt đối hiệu tung độ.
Math.abs để trừ ngược vẫn ra dương.
Khoảng cách hai điểm theo Pi-ta-go: sqrt(dx*dx + dy*dy).
Ví dụ (0,4)-(3,0): dài 3 rộng 4, chu vi 14, diện tích 12.
5. Lab 04 giảng cho người mới
5.1. SV — tách họ tên bằng split
"Nguyen Van An".split("\\s+") cắt chuỗi theo khoảng trắng thành
mảng ["Nguyen", "Van", "An"]. Ô đầu là họ, ô cuối là tên,
ở giữa là đệm:
layTen():p[p.length - 1]— ô cuối cùng.layDem(): nối các ô giữa, mỗi ô cách nhau 1 dấu cách, điều kiệni < p.length - 2để không thừa cách ở cuối (giống mẹo nối tên ở bài Chao2).
ganHoTen dùng (hoTen == null) ? "" : hoTen.trim():
null thì lấy chuỗi rỗng, trim() cắt cách thừa hai đầu.
Xếp loại là if bậc thang 8/7/5 — đọc từ trên xuống,
đúng ngưỡng nào dừng ở đó.
5.2. DSSV — thêm, sắp xếp, tìm, xóa
them(sv) chặn null và chặn đầy rồi mới gán vào ds[soSV],
xong tăng soSV. Ba hàm sắp xếp đều là nổi bọt, chỉ khác cái so:
- theo điểm:
layDTB() <bên sau thì đổi (giảm dần), - theo tên: khóa
tên+họ+đệmso bằngcompareTo, - theo tuổi:
layTuoi() >bên sau thì đổi (tăng dần).
timTen dùng equalsIgnoreCase (so không phân biệt hoa thường),
duyệt tới soSV (số thật) chứ không phải ds.length (sức chứa).
5.3. Xóa bằng cách dồn mảng
for (int i = k; i < soSV - 1; i++) ds[i] = ds[i + 1]; // dồn lên lấp chỗ trống
ds[soSV - 1] = null; // ô cuối thành rác thì gán null cho sạch
soSV--; // giảm số lượng thật
Xóa ô k thì mọi object sau k tiến lên 1 bước.
Ô cuối cùng thừa ra phải gán null để không còn trỏ vào object cũ
(kẻo liệt kê nhầm). tuoiTrungBinh() ép (double) trước khi chia
để tuổi lẻ không bị cắt ngọn. tangDTBTruoc1980 duyệt cộng 0.5 cho
ai sinh trước 1980 — ví dụ bạn 1978 từ 4.5 lên 5.0, đổi xếp loại
từ Yếu thành Trung bình.
6. Lab 05 giảng cho người mới
6.1. DiemHP — lớp trừu tượng là bản cam kết
public abstract class DiemHP {
...
public abstract double tinhDiem(); // cam kết: con nào cũng phải có cách tính
}
Lớp cha giữ phần chung (tên, tín chỉ, in ấn), để trống đúng một chỗ
(tinhDiem) cho lớp con điền. toString() của cha đã gọi sẵn
tinhDiem() — khi chạy với object con, Java tự gọi bản của con.
Đây là đa hình trong 1 dòng code, ngấm được chỗ này là hiểu nửa bài.
6.2. Ba lớp con — ghi đè là viết lại theo ý mình
- Lý thuyết:
cc*0.1 + gk*0.2 + ck*0.7(giống Lab 03). - Thực hành: trung bình 3 đầu điểm
(db1+db2+db3)/3. - Đồ án: trung bình mảng điểm hội đồng, mảng rỗng/null thì trả 0.
Mỗi constructor đều super(tenHP, soTinChi) dòng đầu.
Thử tay bạn An: LT Java 9*0.1+8*0.2+7*0.7=7.4 (3TC),
TH Java (8+9+7)/3=8.0 (2TC), ĐTB (7.4*3+8*2)/5=7.64.
Khớp output mẫu. Ba bạn còn lại tính y hệt ra 7.84 và 7.21.
6.3. Mảng đa hình — một danh sách, nhiều cách tính
DiemHP[] cacHP = {lt1, th1, th2, lt2, lt3, th3};
for (int i = 0; i < cacHP.length; i++) tong += cacHP[i].tinhDiem();
Khai báo là DiemHP nhưng object thật là Lý thuyết/Thực hành lẫn lộn.
Cùng một lời gọi tinhDiem(), đứa nào tính theo ruột đứa nấy —
tổng 6 môn ra 47.07. Thêm loại học phần mới sau này không phải sửa
vòng lặp này: đó là lý do người ta dùng đa hình.
6.4. Bưu phẩm — đa hình áp vào bài toán thật
Thu thêm thuộc tính baoDam (thư bảo đảm hay thường).
phiGui(): thường 800? — không, bài này quy định thường 2400
(3 lá = 7200... khoan). Đọc code: baoDam ? 2000 : 800?
Không — code thật: thường 800? Kiểm tra output mẫu:
"Thu thuong: 2400.0" với 3 lá thường → mỗi lá 800. Đúng:
thường 800, bảo đảm 2000 (2 lá = 4000), bưu kiện 5000 (3 cái = 15000).
Tổng 3*800 + 2*2000 + 3*5000 = 2400 + 4000 + 15000 = 21400.0.
Khớp output mẫu. ThungThu là danh sách BuuPham[] đa hình:
lietKe, tongTien, tongTheoLoai đều duyệt một vòng,
lọc theo loai().equals(...) khi cần.
7. Mảng bổ trợ giảng nhanh cho người mới
- BinhPhuong: tách hàm
binhPhuong(x)trả vềx*x,mainchỉ gọi rồi in. Bài đầu tiên dạy "hàm con". - BoiSoCua5:
5*ivớiitừ 1 đến 10. Muốn bội của k thì thay 5 bằng k. - MuoiNguyenTo:
while (dem < 10)— chưa đủ 10 thì xét số tiếp theo.whiledùng khi không biết trước lặp bao nhiêu lần. - NhapTen:
nextLine()đọc cả dòng (có dấu cách). SaunextInt()mà gọinextLine()ngay sẽ hứng Enter thừa — phải gọi mộtnextLine()trắng để nuốt nó trước. - ThuTrongTuan: switch 7 nhánh +
defaultbắt số lạ (nhập 8). - ChanLe:
n % 2 == 0là chẵn. Số âm vẫn đúng (-3 % 2bằng -1, khác 0 nên là lẻ). Số 0 là chẵn. - NguyenAm:
s.charAt(0)lấy ký tự đầu,toLowerCaseđổi thường để bắt cảE. Nhiềucasechung một nhánh thì xếp chồng khôngbreakgiữa — đây là lần hiếm hoi rơi nhánh có chủ đích. - CapBangNhau: so
a[i] == a[i+1], vòng tớin-2đểa[i+1]không vượt mảng. Dãy mẫu1 1 2 2 2 3 4 4cho 4 cặp (cặp ở vị trí 0, 1, 3, 6). Ít hơn 2 phần tử thì báo ngay. - KhongNhoHonTruoc: giữ
maxTruoc, gặp số>=max thì in và cập nhật. Dãy3 1 4 1 5 9 2 6cho3 4 5 9. Dấu>=(không phải>) nên số bằng max vẫn được in. - MaTranDonVi: ma trận là mảng 2 chiều
int[n][n], nhập/xét bằng vòng lặp lồng nhau (hàng i, cột j). Cờokbắt đầu đúng, gặp ô khác 0/1 thì hạ cờ +breakthoát vòng trong, điều kiệni < n && okthoát luôn vòng ngoài.n <= 0báo lỗi trước.
8. Từ điển lỗi cho người mới
Thông báo javac |
Nghĩa là gì | Sửa sao |
|---|---|---|
';' expected |
thiếu ; cuối lệnh |
thêm ; |
cannot find symbol |
sai tên biến/lớp/phương thức | kiểm tra chính tả, hoa thường |
incompatible types |
nhét kiểu này vào biến kiểu khác | ép kiểu hoặc đổi kiểu biến |
array index out of bounds (lúc chạy) |
i <= length hoặc a[n] |
sửa thành i < length |
NullPointerException (lúc chạy) |
gọi phương thức trên ô rỗng/null |
new object / kiểm tra null |
ArithmeticException: / by zero (lúc chạy) |
chia 0 | kiểm tra mẫu/số chia trước |
class X is public, should be in X.java |
tên file khác tên lớp | đổi tên file giống hệt lớp |
non-static ... cannot be referenced |
gọi hàm object từ main static |
thêm static hoặc đúc object |
Quy tắc đọc lỗi: đọc dòng đầu tiên, nó ghi đúng file và số dòng. Sửa từ lỗi đầu tiên trở đi, vì một lỗi hay đẻ ra thêm nhiều lỗi giả phía sau.