Chuyển tới nội dung chính

Cú pháp cơ bản Java

Mục tiêu bài học

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, can
    public 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, can prefix
    boolean 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 final cho 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

ElementConventionExample
ClassPascalCaseBankAccount, UserService
InterfacePascalCaseRunnable, Serializable
MethodcamelCasecalculateTotal(), getName()
VariablecamelCasefirstName, totalAmount
ConstantUPPER_SNAKE_CASEMAX_SIZE, API_KEY
Packagelowercasecom.example.project
Best Practice
  • Descriptive > Short: calculateTotalPrice() tốt hơn calc()
  • Avoid abbreviations: customer tốt hơn cust
  • Consistency: Giữ style nhất quán trong toàn project

Unicode Identifiers — Java hỗ trợ tiếng Việt!

📖 Theo JLS §3.8 (Identifiers)

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)
💡 Cách nhớ: Java "đa ngôn ngữ"

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?

ProsCons
✅ 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
Best Practice

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)

🔥 Bẫy OCP: Keywords ít gặp

strictfp (strict floating-point):

  • Từ Java 17, strictfpno-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 Serializable interface
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 -ea flag)
assert age >= 18 : "Age must be >= 18";
// Nếu age < 18 → AssertionError

Reserved nhưng không dùng

gotoconst: 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

TypeSyntaxUse 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:

TagMô tảVí dụ
@paramMô tả parameter@param name tên khách hàng
@returnMô tả giá trị trả về@return true nếu hợp lệ
@throwsMô tả exception@throws IOException nếu file không tồn tại
@authorTác giả@author John Doe
@versionPhiên bản@version 2.0
@sinceTừ version nào@since 1.5
@seeReference@see BankAccount#deposit(double)
@deprecatedĐánh dấu deprecated@deprecated Use newMethod() instead
Chú ý
  • 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?

💡 Cách nhớ: 3 loại comments cho 3 mục đích
  • //: 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

🔥 Bẫy OCP: Thứ tự bắt buộc

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 package statement (hoặc không có)
  • ✅ Nhiều import statements
  • import không thể đứng trước package
  • package không thể đứng sau import hoặc class

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:

SpecifierTypeExample
%sString%s → "Alice"
%dInteger (decimal)%d → 25
%fFloat/Double%f → 3.141593
%.2fFloat (2 decimal places)%.2f → 3.14
%cCharacter%c → 'A'
%bBoolean%b → true
%nNewline (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 typeExample
nextLine()String (entire line)"Hello World"
next()String (next token)"Hello" (stop at space)
nextInt()int25
nextDouble()double3.14
nextBoolean()booleantrue/false
nextLong()long1000000L
nextFloat()float3.14f
Chú ý: nextLine() vs next()

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:

  1. Hỏi tên người dùng
  2. Hỏi tuổi
  3. 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:

  1. Nhập chiều dài và chiều rộng
  2. Tính diện tích và chu vi
  3. 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ước tiếp theo

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!

👉 Tiếp theo: Kiểu dữ liệu và Biến →

Đọc thêm