Cú pháp cơ bản Java
Sau bài này, bạn sẽ:
- Hiểu cấu trúc một chương trình Java với package, import, class, và main method
- Áp dụng naming conventions chuẩn cho class, method, variable, constant, và package
- Sử dụng comments hiệu quả (single-line, multi-line, Javadoc) để document code
- Organize code bằng packages và import classes từ các packages khác
- Thực hiện input/output với System.out (println, print, printf) và Scanner
Bài trước: Cài đặt môi trường phát triển — Đã cài đặt JDK và IDE. Bài này sẽ học về cú pháp cơ bản để viết code Java đúng chuẩn.
Bài học này sẽ giới thiệu cú pháp cơ bản của Java - nền tảng để bạn viết code Java đúng chuẩn và dễ đọc.
Cấu trúc một chương trình Java
Anatomy of a Java Program
// 1. Package declaration (optional)
package com.example.tutorial;
// 2. Import statements (optional)
import java.util.Scanner;
import java.time.LocalDate;
// 3. Class declaration (required)
public class MyFirstProgram {
// 4. Class-level variables (optional)
private static final String APP_NAME = "My App";
// 5. Main method (entry point)
public static void main(String[] args) {
// 6. Statements
System.out.println("Hello, World!");
}
// 7. Other methods (optional)
public void greet(String name) {
System.out.println("Hello, " + name);
}
}
Phân tích từng phần
1. Package Declaration (Dòng 1)
package com.example.tutorial;
- Khai báo package mà class này thuộc về
- Giúp organize code và tránh name conflicts
- Convention: domain ngược lại + module (
com.example.project) - Optional nhưng nên dùng cho projects lớn
2. Import Statements (Dòng 3-4)
import java.util.Scanner; // Import specific class
import java.util.*; // Import all classes in package (không khuyến khích)
- Import classes từ packages khác
java.lang.*được import tự động (String, System, Math, ...)
3. Class Declaration (Dòng 6)
public class MyFirstProgram {
// Class body
}
- Mọi code Java phải nằm trong một class
- File name PHẢI trùng với public class name
4. Main Method (Dòng 11-14)
public static void main(String[] args) {
// Statements
}
- Entry point của application
- Signature phải chính xác
5. Statements
- Mỗi statement kết thúc bằng
; - Được execute theo thứ tự từ trên xuống dưới
Naming Conventions
Java có naming conventions rất rõ ràng. Tuân thủ conventions giúp code dễ đọc và professional.
1. Class Names - PascalCase
Convention: Mỗi từ viết HOA chữ cái đầu, không có dấu gạch dưới
// ✅ GOOD
public class Student { }
public class BankAccount { }
public class UserProfileService { }
// ❌ BAD
public class student { } // Chữ thường
public class bank_account { } // Underscore
public class userprofileservice { } // Khó đọc
Rules:
- Bắt đầu bằng chữ cái (A-Z)
- Danh từ hoặc noun phrase
- Descriptive và meaningful
2. Method Names - camelCase
Convention: Chữ cái đầu tiên thường, các từ sau viết HOA chữ cái đầu
// ✅ GOOD
public void calculateTotal() { }
public void sendEmail() { }
public void getUserById(int id) { }
// ❌ BAD
public void CalculateTotal() { } // PascalCase (dành cho class)
public void calculate_total() { } // Snake_case
public void CALCULATETOTAL() { } // All caps
Rules:
- Bắt đầu bằng động từ:
get,set,calculate,create,delete,update - Boolean methods:
is,has,canpublic boolean isValid() { }
public boolean hasPermission() { }
public boolean canDelete() { }
3. Variable Names - camelCase
Convention: Giống method names
// ✅ GOOD
int age;
String firstName;
double accountBalance;
List<String> studentNames;
// ❌ BAD
int Age; // PascalCase
String first_name; // Snake_case
double a; // Không descriptive (trừ loop counters)
Rules:
- Meaningful và descriptive
- Avoid single letters (trừ loop counters:
i,j,k) - Boolean variables:
is,has,canprefixboolean isActive;
boolean hasChildren;
boolean canVote;
4. Constants - UPPER_SNAKE_CASE
Convention: Tất cả chữ HOA, phân cách bằng underscore
// ✅ GOOD
public static final int MAX_SIZE = 100;
public static final String API_KEY = "abc123";
public static final double PI = 3.14159;
// ❌ BAD
public static final int maxSize = 100; // camelCase
public static final String apiKey = "123"; // camelCase
Rules:
- Dùng
static finalcho constants - Immutable values
5. Package Names - lowercase
Convention: Tất cả chữ thường, phân cách bằng dấu chấm
// ✅ GOOD
package com.example.myapp;
package com.company.project.module;
package edu.university.library;
// ❌ BAD
package com.Example.MyApp; // PascalCase
package com.example.my_app; // Underscore
Convention pattern:
- Domain ngược:
com.google,org.apache,edu.mit - Project name:
com.google.android - Module:
com.google.android.maps
Summary Table
| Element | Convention | Example |
|---|---|---|
| Class | PascalCase | BankAccount, UserService |
| Interface | PascalCase | Runnable, Serializable |
| Method | camelCase | calculateTotal(), getName() |
| Variable | camelCase | firstName, totalAmount |
| Constant | UPPER_SNAKE_CASE | MAX_SIZE, API_KEY |
| Package | lowercase | com.example.project |
- Descriptive > Short:
calculateTotalPrice()tốt hơncalc() - Avoid abbreviations:
customertốt hơncust - Consistency: Giữ style nhất quán trong toàn project
Unicode Identifiers — Java hỗ trợ tiếng Việt!
Java identifiers hỗ trợ Unicode — bạn có thể dùng chữ cái từ bất kỳ ngôn ngữ nào (Vietnamese, Chinese, Arabic, emoji...).
Ví dụ hợp lệ:
// ✅ Tiếng Việt
int tuổi = 25;
String tên = "Nguyễn Văn A";
double giáTiền = 100.5;
// ✅ Tiếng Trung
int 年龄 = 30;
// ✅ Tiếng Nhật
String 名前 = "田中";
// ✅ Tiếng Ả Rập
int عدد = 42;
// ✅ Thậm chí emoji (nhưng không khuyến khích!)
int 😀 = 10;
// Tất cả đều compile OK!
System.out.println(tuổi); // 25
System.out.println(giáTiền); // 100.5
Quy tắc Unicode identifiers:
- Bắt đầu bằng Unicode letter hoặc
_,$ - Có thể chứa Unicode letters, Unicode digits,
_,$
// ✅ Valid Unicode identifiers
int số = 5;
String địaChỉ = "Hà Nội";
double π = 3.14159; // Greek letter pi
int café = 100; // Accented characters
// ❌ Invalid
int 123abc = 5; // Bắt đầu bằng số
int my-var = 10; // Có dấu gạch ngang (không phải Unicode letter/digit)
Java được thiết kế để international — Unicode identifiers giúp developers trên toàn thế giới viết code bằng ngôn ngữ mẹ đẻ!
Nhưng có nên dùng không?
| Pros | Cons |
|---|---|
| ✅ Dễ đọc cho non-English speakers | ❌ Hầu hết codebase dùng English |
| ✅ Tên biến gần với business domain | ❌ Khó type (cần input method) |
| ✅ Hợp lệ theo JLS | ❌ Khó collaborate với international team |
| ✅ Có thể match thuật ngữ chuyên ngành | ❌ Một số tools có thể không hỗ trợ tốt |
Trong thực tế: Hầu hết projects dùng English cho identifiers (class, method, variable names) để:
- Dễ collaborate với international teams
- Consistency với Java libraries (toàn bộ đều English)
- Tránh vấn đề encoding khi share code
- IDE và tools hỗ trợ tốt hơn
Ngoại lệ: Comments và string literals có thể dùng tiếng Việt:
int age = 25; // Tuổi của người dùng ✅
String message = "Xin chào!"; // ✅ String content OK
Keywords (Từ khóa)
Java có 51 reserved keywords không thể dùng làm identifiers.
Keywords đầy đủ
// Control flow
if, else, switch, case, default, for, while, do, break, continue, return
// OOP
class, interface, extends, implements, new, this, super
abstract, final, static, native
// Access modifiers
public, protected, private
// Types
byte, short, int, long, float, double, char, boolean, void
// Exception handling
try, catch, finally, throw, throws
// Package
package, import
// Other
synchronized, volatile, transient, strictfp
assert, enum
// Literals (không phải keywords, nhưng reserved)
true, false, null
Keywords ít dùng (OCP thường hỏi)
strictfp (strict floating-point):
- Từ Java 17,
strictfplà no-op (JEP 306) — tất cả floating-point operations đều strict by default. Keyword vẫn tồn tại nhưng không có tác dụng.
public strictfp class Calculator {
double calculate() {
return 0.1 + 0.2; // Từ Java 17+: strictfp không còn ảnh hưởng
}
}
transient:
- Đánh dấu field không serialize (không lưu vào file/network)
- Dùng với
Serializableinterface
class User implements Serializable {
String username;
transient String password; // Không serialize password!
}
volatile:
- Đảm bảo field được đọc/ghi từ main memory (không cache)
- Dùng trong multithreading
class Counter {
private volatile int count = 0; // Mọi thread thấy giá trị mới nhất
}
native:
- Đánh dấu method implemented bằng native code (C/C++)
- JVM gọi native library (JNI)
public class System {
public static native long currentTimeMillis(); // Implemented in C
}
assert:
- Kiểm tra assumptions trong development
- Disabled by default (phải enable với
-eaflag)
assert age >= 18 : "Age must be >= 18";
// Nếu age < 18 → AssertionError
Reserved nhưng không dùng
goto và const: Reserved nhưng không implement trong Java.
int const = 10; // ❌ Compile error - reserved word
goto label; // ❌ Compile error - reserved word
Comments - Chú thích
Comments giúp explain code, document logic, và improve readability.
Phân biệt 3 loại comments
| Type | Syntax | Use case |
|---|---|---|
| Single-line | // | Chú thích ngắn, inline comments |
| Multi-line | /* */ | Block comments, license headers |
| Javadoc | /** */ | API documentation (generate HTML docs) |
1. Single-line Comments
// Đây là single-line comment
int age = 25; // Comment ở cuối dòng
// Có thể comment nhiều dòng liên tiếp
// bằng cách dùng // ở mỗi dòng
Use cases:
- Explain complex logic
- Temporary notes (TODO, FIXME)
- Disable code temporarily
// TODO: Implement validation
// FIXME: Bug when input is negative
// int x = 10; // Temporarily disabled
2. Multi-line Comments
/*
* Đây là multi-line comment
* Thường dùng cho explain blocks of code
* hoặc license headers
*/
public void processData() {
/*
Algorithm explanation:
1. Validate input
2. Transform data
3. Save to database
*/
}
3. Javadoc Comments
Javadoc là special comments để generate API documentation.
/**
* Tính tổng của hai số nguyên.
*
* @param a số thứ nhất
* @param b số thứ hai
* @return tổng của a và b
*/
public int add(int a, int b) {
return a + b;
}
Class-level Javadoc:
/**
* Class đại diện cho một tài khoản ngân hàng.
*
* <p>Tài khoản có thể thực hiện các thao tác:
* <ul>
* <li>Gửi tiền (deposit)</li>
* <li>Rút tiền (withdraw)</li>
* <li>Kiểm tra số dư (checkBalance)</li>
* </ul>
*
* @author Nguyen Van A
* @version 1.0
* @since 2024-01-01
*/
public class BankAccount {
// ...
}
Common Javadoc tags:
| Tag | Mô tả | Ví dụ |
|---|---|---|
@param | Mô tả parameter | @param name tên khách hàng |
@return | Mô tả giá trị trả về | @return true nếu hợp lệ |
@throws | Mô tả exception | @throws IOException nếu file không tồn tại |
@author | Tác giả | @author John Doe |
@version | Phiên bản | @version 2.0 |
@since | Từ version nào | @since 1.5 |
@see | Reference | @see BankAccount#deposit(double) |
@deprecated | Đánh dấu deprecated | @deprecated Use newMethod() instead |
- Không over-comment: Code tốt nên tự explain (self-documenting)
- Update comments: Comments cũ/sai còn tệ hơn không có comments
- Explain WHY, not WHAT: Code đã nói "what", comment nên nói "why"
Good vs Bad Comments:
// ❌ BAD - Comment giải thích code rõ ràng
int age = 25; // Set age to 25
// ✅ GOOD - Comment giải thích WHY
int age = 25; // Minimum age requirement for voting
// ❌ BAD - Obvious
i++; // Increment i
// ✅ GOOD - Explain business logic
i++; // Skip header row in Excel file
Khi nào dùng comment nào?
//: Quick notes, disable code tạm thời, TODO/FIXME/* */: Explain algorithms, license headers, large blocks/** */: Public API documentation (classes, methods visible bên ngoài)
Ví dụ thực tế:
/**
* Service quản lý user accounts.
*
* @author Nguyen Van A
* @since 1.0
*/
public class UserService {
// TODO: Implement caching
private Map<Long, User> cache;
/**
* Tìm user theo ID.
*
* @param id ID của user
* @return User object hoặc null nếu không tìm thấy
*/
public User findById(long id) {
/*
* Algorithm:
* 1. Check cache trước
* 2. Nếu không có, query database
* 3. Cache kết quả
*/
User user = cache.get(id); // Check cache
if (user == null) {
user = database.query(id); // Query DB
cache.put(id, user); // Cache it
}
return user;
}
}
Packages và Import
Packages giúp tổ chức code và tránh xung đột tên. Import cho phép sử dụng classes từ packages khác.
Chi tiết về packages và import sẽ được trình bày trong bài Packages.
Vị trí của package và import statements
File .java PHẢI tuân thủ thứ tự này:
1. package statement (optional, nhưng nếu có PHẢI là dòng đầu)
2. import statements (optional, sau package)
3. class/interface/enum (required)
Rules:
- ✅ Chỉ một
packagestatement (hoặc không có) - ✅ Nhiều
importstatements - ❌
importkhông thể đứng trướcpackage - ❌
packagekhông thể đứng sauimporthoặcclass
Ví dụ hợp lệ:
// ✅ CORRECT
package com.example.app; // 1. Package đầu tiên
import java.util.List; // 2. Imports
import java.util.ArrayList;
public class MyClass { // 3. Class declaration
// ...
}
Ví dụ SAI:
// ❌ ERROR 1: import trước package
import java.util.List;
package com.example.app; // Compile error!
// ❌ ERROR 2: package sau class
public class MyClass { }
package com.example.app; // Compile error!
Input và Output
Output - System.out
1. println() - Print và xuống dòng
System.out.println("Hello, World!");
System.out.println("Dòng 1");
System.out.println("Dòng 2");
Output:
Hello, World!
Dòng 1
Dòng 2
2. print() - Print không xuống dòng
System.out.print("Hello, ");
System.out.print("World!");
System.out.println(); // Xuống dòng
Output:
Hello, World!
3. printf() - Formatted output
String name = "Alice";
int age = 25;
double salary = 50000.5;
System.out.printf("Name: %s\n", name);
System.out.printf("Age: %d\n", age);
System.out.printf("Salary: $%.2f\n", salary);
Output:
Name: Alice
Age: 25
Salary: $50000.50
Format specifiers:
| Specifier | Type | Example |
|---|---|---|
%s | String | %s → "Alice" |
%d | Integer (decimal) | %d → 25 |
%f | Float/Double | %f → 3.141593 |
%.2f | Float (2 decimal places) | %.2f → 3.14 |
%c | Character | %c → 'A' |
%b | Boolean | %b → true |
%n | Newline (platform-independent) | %n → \n |
Advanced formatting:
System.out.printf("%-10s | %5d | %8.2f\n", "Alice", 25, 1000.5);
System.out.printf("%-10s | %5d | %8.2f\n", "Bob", 30, 2500.75);
Output:
Alice | 25 | 1000.50
Bob | 30 | 2500.75
%-10s: Left-aligned, width 10%5d: Right-aligned, width 5%8.2f: Width 8, 2 decimal places
Input - Scanner
Scanner là class để đọc input từ keyboard (hoặc file, string).
Import:
import java.util.Scanner;
Basic usage:
Scanner scanner = new Scanner(System.in);
System.out.print("Nhập tên: ");
String name = scanner.nextLine();
System.out.print("Nhập tuổi: ");
int age = scanner.nextInt();
System.out.println("Xin chào, " + name + "! Bạn " + age + " tuổi.");
scanner.close(); // Đóng scanner
Scanner methods:
| Method | Đọc type | Example |
|---|---|---|
nextLine() | String (entire line) | "Hello World" |
next() | String (next token) | "Hello" (stop at space) |
nextInt() | int | 25 |
nextDouble() | double | 3.14 |
nextBoolean() | boolean | true/false |
nextLong() | long | 1000000L |
nextFloat() | float | 3.14f |
Problem: nextInt() không consume newline character!
Scanner sc = new Scanner(System.in);
System.out.print("Nhập tuổi: ");
int age = sc.nextInt(); // Nhập: 25\n → chỉ đọc 25, \n vẫn ở buffer
System.out.print("Nhập tên: ");
String name = sc.nextLine(); // ❌ Đọc luôn \n → empty string!
System.out.println("Tên: " + name); // Output: "Tên: " (rỗng!)
Solution: Thêm một nextLine() để consume newline:
int age = sc.nextInt();
sc.nextLine(); // Consume leftover newline
String name = sc.nextLine(); // ✅ OK
Bài tập thực hành
Bài 1: Chương trình chào hỏi
Viết chương trình:
- Hỏi tên người dùng
- Hỏi tuổi
- In ra lời chào với tên và tuổi
Expected output:
Nhập tên: Alice
Nhập tuổi: 25
Xin chào, Alice! Bạn 25 tuổi.
Xem đáp án
import java.util.Scanner;
public class GreetingProgram {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Nhập tên: ");
String name = scanner.nextLine();
System.out.print("Nhập tuổi: ");
int age = scanner.nextInt();
System.out.println("Xin chào, " + name + "! Bạn " + age + " tuổi.");
scanner.close();
}
}
Bài 2: Tính diện tích hình chữ nhật
Viết chương trình:
- Nhập chiều dài và chiều rộng
- Tính diện tích và chu vi
- In kết quả với 2 số thập phân
Expected output:
Nhập chiều dài: 5.5
Nhập chiều rộng: 3.2
Diện tích: 17.60
Chu vi: 17.40
Xem đáp án
import java.util.Scanner;
public class RectangleArea {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Nhập chiều dài: ");
double length = scanner.nextDouble();
System.out.print("Nhập chiều rộng: ");
double width = scanner.nextDouble();
double area = length * width;
double perimeter = 2 * (length + width);
System.out.printf("Diện tích: %.2f%n", area);
System.out.printf("Chu vi: %.2f%n", perimeter);
scanner.close();
}
}
Bài 3: Format output
In ra bảng thông tin sinh viên:
| ID | Name | Age | GPA |
|------|------------|-----|-------|
| 1001 | Alice | 20 | 3.85 |
| 1002 | Bob | 22 | 3.50 |
| 1003 | Charlie | 21 | 3.92 |
Xem đáp án
public class StudentTable {
public static void main(String[] args) {
System.out.println("| ID | Name | Age | GPA |");
System.out.println("|------|------------|-----|-------|");
System.out.printf("| %-4d | %-10s | %3d | %5.2f |%n", 1001, "Alice", 20, 3.85);
System.out.printf("| %-4d | %-10s | %3d | %5.2f |%n", 1002, "Bob", 22, 3.50);
System.out.printf("| %-4d | %-10s | %3d | %5.2f |%n", 1003, "Charlie", 21, 3.92);
}
}
Tổng kết
Trong bài này, bạn đã học:
✅ Cấu trúc chương trình Java: Package, import, class, main method
✅ Naming conventions: PascalCase (class), camelCase (method, variable), UPPER_SNAKE_CASE (constant), lowercase (package)
✅ Comments: Single-line (//), multi-line (/* */), Javadoc (/** */)
✅ Packages: Organize code, avoid conflicts
✅ Import: Sử dụng classes từ packages khác
✅ Output: println(), print(), printf() với format specifiers
✅ Input: Scanner với nextLine(), nextInt(), nextDouble()
Bài tiếp theo chúng ta sẽ học về Kiểu dữ liệu và Biến - primitive types, reference types, type casting!