Lập trình · Ngôn ngữ lập trình
Hướng dẫn học Java cơ bản cho người mới
Trả lời nhanh
Java là ngôn ngữ hướng đối tượng kiểu tĩnh, biên dịch thành bytecode và chạy trên Máy ảo Java (JVM) trên mọi hệ điều hành. Hãy cài JDK, lưu một lớp vào Hello.java rồi chạy java Hello.java. Các ý tưởng cốt lõi là lớp và đối tượng, kiểu nguyên thủy và kiểu tham chiếu, bộ khung collection (List, Map, Set), ngoại lệ checked, cùng các tính năng mới như record, var và pattern matching.
Java là gì và dùng để làm gì
Java do Sun Microsystems phát hành năm 1995 và hiện được phát triển trong dự án mở OpenJDK, với Oracle là bên quản lý chính. Lời hứa của nó là "viết một lần, chạy ở mọi nơi": trình biên dịch sinh ra bytecode, và JVM chạy bytecode đó trên Windows, macOS và Linux. Java được dùng cho back end doanh nghiệp lớn (thường với Spring Boot), ứng dụng Android (cùng với Kotlin), công cụ dữ liệu lớn như Apache Kafka và Hadoop, cùng nhiều hệ thống máy tính để bàn và nhúng. Cứ sáu tháng lại có một phiên bản mới, và các phiên bản hỗ trợ dài hạn (LTS) như Java 21 là lựa chọn thông thường cho môi trường production.
Cài JDK và chạy Hello, world
Hãy cài một JDK (Java Development Kit), ví dụ một bản OpenJDK như Eclipse Temurin hoặc JDK của Oracle. Kiểm tra bằng java -version. Mọi chương trình Java đều nằm trong một lớp, và quá trình thực thi bắt đầu từ main.
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, world");
}
}java Hello.java # run a single source file directly
# Hello, world
javac Hello.java # or compile to Hello.class first
java HelloTên tệp phải khớp với tên lớp public (Hello.java cho class Hello).
Biến và các kiểu dữ liệu cơ bản
Java có tám kiểu nguyên thủy, lưu trực tiếp dưới dạng giá trị, và các kiểu tham chiếu (đối tượng như String và mảng). Mỗi biến có kiểu cố định; var cho phép trình biên dịch suy luận kiểu từ giá trị khởi tạo bên trong phương thức.
| Kiểu | Kích thước | Ví dụ |
|---|---|---|
int | 32 bit | int n = 42; |
long | 64 bit | long big = 10_000_000_000L; |
double | Số thực 64 bit | double pi = 3.14159; |
boolean | true/false | boolean ok = true; |
char | Đơn vị UTF-16 16 bit | char c = 'A'; |
byte, short, float | 8, 16, 32 bit | Ít dùng hơn |
String | tham chiếu | String s = "hi"; |
int count = 7;
double avg = count / 2; // 3.0, integer division happens first
double avg2 = count / 2.0; // 3.5
var name = "Ada"; // inferred as String
String msg = name + " has " + count + " items";
System.out.println(msg); // Ada has 7 items
System.out.println(Integer.parseInt("12") + 1); // 13Đây là một đoạn mã: hãy đặt các câu lệnh như thế này bên trong một phương thức như main.
Điều khiển luồng
int score = 72;
if (score >= 90) {
System.out.println("A");
} else if (score >= 70) {
System.out.println("B"); // B
} else {
System.out.println("C");
}
for (int i = 0; i < 3; i++) {
System.out.println(i); // 0, 1, 2
}
String day = "SAT";
String kind = switch (day) { // switch expression
case "SAT", "SUN" -> "weekend";
default -> "weekday";
};
System.out.println(kind); // weekendJava còn có while, do/while và vòng lặp for (String s : list) nâng cao để duyệt mảng và collection.
Phương thức, lớp và record
Lớp gộp các trường (dữ liệu) và phương thức (hành vi). Phương thức static thuộc về chính lớp; các phương thức khác được gọi trên một đối tượng tạo bằng new. record là cách ngắn gọn để khai báo lớp dữ liệu bất biến: trình biên dịch tự sinh constructor, các accessor, equals, hashCode và toString.
public class Shapes {
static double square(double x) {
return x * x;
}
static class Counter {
private int value;
void increment() { value++; }
int get() { return value; }
}
record Point(int x, int y) {
double distance() { return Math.sqrt(x * x + y * y); }
}
public static void main(String[] args) {
System.out.println(square(4)); // 16.0
Counter c = new Counter();
c.increment();
c.increment();
System.out.println(c.get()); // 2
Point p = new Point(3, 4);
System.out.println(p + " " + p.distance()); // Point[x=3, y=4] 5.0
}
}Lớp có thể kế thừa một lớp cha (extends) và triển khai nhiều interface (implements). Các trường thường là private, truy cập thông qua phương thức.
Collection: List, Map và Set
Bộ khung collection trong java.util cung cấp các cấu trúc dữ liệu co giãn được. Collection chứa đối tượng, nên kiểu nguyên thủy được đóng hộp tự động (int thành Integer).
import java.util.*;
public class Collections101 {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(List.of(3, 1, 2));
nums.add(5);
Collections.sort(nums);
System.out.println(nums + " " + nums.get(0)); // [1, 2, 3, 5] 1
Map<String, Integer> ages = new HashMap<>();
ages.put("ann", 31);
ages.put("bob", 25);
System.out.println(ages.getOrDefault("zed", 0)); // 0
Set<String> tags = new TreeSet<>(List.of("b", "a", "b"));
System.out.println(tags); // [a, b]
List<Integer> evensSquared = nums.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.toList();
System.out.println(evensSquared); // [4]
}
}Câu lệnh cuối dùng stream và lambda, một phong cách hàm để biến đổi collection. List.of tạo list bất biến; hãy bọc nó trong new ArrayList<>(...) khi bạn cần thay đổi.
Tính năng đặc trưng: kiểu tĩnh, interface và pattern matching
Interface định nghĩa một hợp đồng mà nhiều lớp có thể triển khai, đó là nền tảng của phần lớn thiết kế Java. Java hiện đại thêm pattern matching: instanceof và switch có thể kiểm tra kiểu và gán biến chỉ trong một bước. Sealed interface (Java 17 trở lên) liệt kê mọi cách triển khai được phép, nên trình biên dịch có thể kiểm tra rằng switch bao phủ mọi trường hợp.
public class Areas {
sealed interface Shape permits Circle, Rect {}
record Circle(double r) implements Shape {}
record Rect(double w, double h) implements Shape {}
static double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.r() * c.r();
case Rect r -> r.w() * r.h();
};
}
public static void main(String[] args) {
System.out.println(area(new Rect(2, 3))); // 6.0
}
}Pattern matching cho switch như thế này là chuẩn trong Java 21 LTS trở lên.
Ngoại lệ
Lỗi là các ngoại lệ. Ngoại lệ checked (như IOException) phải được bắt hoặc khai báo bằng throws; ngoại lệ unchecked (lớp con của RuntimeException, như NullPointerException) thì không bắt buộc. try-with-resources tự động đóng tệp và kết nối.
import java.io.*;
import java.nio.file.*;
public class ReadFirst {
static int parseAge(String text) {
int age = Integer.parseInt(text); // may throw NumberFormatException
if (age < 0) throw new IllegalArgumentException("negative age");
return age;
}
public static void main(String[] args) {
try {
System.out.println(parseAge("abc"));
} catch (NumberFormatException e) {
System.out.println("not a number"); // not a number
}
try (BufferedReader in = Files.newBufferedReader(Path.of("notes.txt"))) {
System.out.println(in.readLine());
} catch (IOException e) {
System.out.println("cannot read: " + e.getMessage());
}
}
}Một chương trình nhỏ hoàn chỉnh: đếm từ
import java.io.IOException;
import java.nio.file.*;
import java.util.*;
public class WordCount {
public static void main(String[] args) throws IOException {
if (args.length != 1) {
System.err.println("usage: java WordCount.java FILE");
System.exit(1);
}
String text = Files.readString(Path.of(args[0])).toLowerCase();
Map<String, Integer> counts = new HashMap<>();
for (String word : text.split("[^a-z']+")) {
if (!word.isEmpty()) counts.merge(word, 1, Integer::sum);
}
counts.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(5)
.forEach(e -> System.out.printf("%5d %s%n", e.getValue(), e.getKey()));
}
}Chạy bằng java WordCount.java notes.txt. Chương trình in ra năm từ phổ biến nhất cùng số lần xuất hiện.
Những lỗi thường gặp của người mới
- Phép chia nguyên:
5 / 2bằng2. Hãy biến một vế thànhdoubleđể được2.5. NullPointerExceptionkhi gọi phương thức trênnull. Hãy kiểm tranull, hoặc dùngOptionalcho giá trị có thể thiếu.- Cố thay đổi list tạo bằng
List.of, sẽ némUnsupportedOperationException. - Quên rằng chỉ số của mảng và
Listbắt đầu từ 0, nên phần tử cuối nằm ởlength - 1.
Học tiếp ở đâu
Hãy theo các lộ trình học trên dev.java, trang chính thức dành cho nhà phát triển Java, và để tài liệu Java SE API mở bên cạnh làm tham chiếu. Học một công cụ build (Maven hoặc Gradle), kiểm thử đơn vị với JUnit, rồi một framework như Spring Boot cho dịch vụ web. Kotlin, cũng chạy trên JVM, là ngôn ngữ tiếp theo tự nhiên.
Câu hỏi thường gặp
Java có khó học không?
Java dài dòng hơn Python vì bạn phải khai báo kiểu và đặt mã trong lớp, nhưng quy tắc của nó nhất quán và trình biên dịch giải thích lỗi từ sớm. Nhiều trường đại học dùng nó làm ngôn ngữ đầu tiên.
JDK và JVM khác nhau thế nào?
JVM chạy bytecode đã biên dịch. JDK là bộ công cụ phát triển đầy đủ: JVM cùng trình biên dịch javac, thư viện chuẩn và các công cụ. Lập trình viên cài JDK.
Nên học phiên bản Java nào?
Hãy học một phiên bản hỗ trợ dài hạn hiện hành, như Java 21 hoặc LTS mới hơn. Mã cũ vẫn chạy trên JVM mới, nên kỹ năng hiện đại cũng áp dụng được cho các dự án có sẵn.
Java có giống JavaScript không?
Không. Dù tên gần giống nhau, chúng là hai ngôn ngữ riêng biệt với hệ thống kiểu, môi trường chạy và mục đích sử dụng khác nhau.
Java còn được dùng không?
Có. Nó vẫn là một trong những ngôn ngữ được dùng nhiều nhất cho back end doanh nghiệp, Android và hạ tầng dữ liệu.