Menu

Cách chạy Java: biên dịch bằng javac và chạy bằng java

Chu trình hai bước biên dịch rồi chạy đằng sau mọi chương trình Java: chuyển mã nguồn .java thành bytecode bằng javac, rồi chạy tệp .class bằng java.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Biên dịch, rồi chạy

Giờ bạn đã cài JDK, chạy Java là một chu trình hai bước. Khác với ngôn ngữ kịch bản, nơi bạn chỉ cần trỏ trình thông dịch vào một tệp là chạy, Java trước tiên biên dịch mã nguồn mà con người đọc được thành bytecode, rồi một bước riêng biệt sẽ chạy bytecode đó trên JVM.

Hai bước này tương ứng với hai công cụ dòng lệnh đi kèm JDK:

  • javac: trình biên dịch. Nó đọc Main.java và ghi ra Main.class (bytecode).
  • java: trình khởi chạy. Nó khởi động JVM và thực thi bytecode trong Main.class.

Bạn có thể chạy mọi ví dụ độc lập ngay trên trang này: trình soạn thảo bên dưới làm cả hai bước giúp bạn. Nhưng bạn nên hiểu chuyện gì xảy ra trên máy của mình, vì các dự án thật nằm ở đó.

Hai lệnh trên máy của bạn

Giả sử bạn có đoạn code này lưu trong Main.java:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello from the terminal");
    }
}

Mở terminal trong thư mục chứa tệp và chạy trình biên dịch:

javac Main.java

Nếu code biên dịch thành công, javac không in gì cả và tạo ra một tệp mới, Main.class, cạnh mã nguồn của bạn. Tệp .class đó là bytecode: nó không phải văn bản đọc được, và không gắn với hệ điều hành của bạn.

Giờ hãy khởi chạy nó bằng lệnh java:

java Main
Hello from the terminal

Lỗi phổ biến nhất của người mới nằm ở đây: bạn chạy java, không phải javac, để khởi chạy chương trình, và bạn truyền tên lớp không kèm phần mở rộng. Đó là java Main, không bao giờ là java Main.class và không bao giờ là java Main.java.

Tên tệp phải khớp với lớp public

Java áp đặt một quy tắc khiến người mới bất ngờ: một lớp public phải nằm trong tệp có cùng tên chính xác, cộng thêm .java. Một public class Main phải nằm trong Main.java. Viết sai chữ hoa chữ thường là javac từ chối biên dịch.

// This is in a file called Greeting.java
public class Greeting {   // ERROR: class Greeting should be in Greeting.java... wait, it is
    public static void main(String[] args) {
        System.out.println("Hi");
    }
}

Sự không khớp thật sự hay làm người ta vấp tinh vi hơn: đặt tên tệp là greeting.java (chữ thường) trong khi lớp là Greeting, hoặc lưu Main.java nhưng lại viết public class Hello. Trình biên dịch báo kiểu như:

Main.java:1: error: class Hello is public, should be declared in a file named Hello.java

Cách sửa luôn như nhau: làm cho tên tệp và tên lớp public giống hệt nhau, từng ký tự một.

Lối tắt: chạy trực tiếp một tệp

Từ JDK 11, bạn có thể bỏ qua bước biên dịch tường minh với một tệp mã nguồn duy nhất. Lệnh java sẽ biên dịch nó trong bộ nhớ và chạy luôn một lượt, không có tệp .class nào được ghi ra đĩa:

java Main.java

Cách này rất hợp cho các thử nghiệm nhanh và các script nhỏ. Để ý sự khác biệt trong thứ bạn truyền vào:

  • java Main: chạy một Main.class đã được biên dịch.
  • java Main.java: biên dịch và chạy tệp mã nguồn trong một lượt.

Chế độ một tệp chỉ dùng được khi toàn bộ chương trình nằm gọn trong một tệp. Ngay khi bạn chia code ra nhiều lớp ở nhiều tệp, bạn quay lại biên dịch bằng javac trước. Khi học những điều cơ bản, chế độ một tệp giúp vòng lặp làm việc ngắn gọn.

Truyền đối số cho chương trình

Bạn còn nhớ String[] args trong main chứ? Đó là các đối số dòng lệnh. Bất cứ gì bạn gõ sau tên lớp trong lệnh java đều được đưa vào mảng đó:

Trên máy của mình, bạn sẽ truyền đối số cho nó như thế này:

java Main hello world
First argument: hello
Total arguments: 2

Trình soạn thảo ở trên không nhận được đối số từ terminal, nên nó chạy nhánh "không có đối số", nhưng cùng một đoạn code xử lý được cả hai trường hợp. Đây là cách chương trình Java đọc đầu vào được truyền lúc khởi chạy, từ trước khi bạn học đến tệp hay đầu vào từ người dùng.

Đọc thông báo lỗi của trình biên dịch

Khi javac từ chối code của bạn, nó cho bạn biết tệp, dòng và điều gì sai. Học cách đọc các thông báo này đã là một nửa việc gỡ rối. Đây là một ví dụ kinh điển, thiếu dấu chấm phẩy:

public class Main {
    public static void main(String[] args) {
        System.out.println("Oops")   // no semicolon
    }
}
Main.java:3: error: ';' expected
        System.out.println("Oops")
                                  ^
1 error

Dấu mũ (^) chỉ vào chỗ trình biên dịch mong đợi có thứ gì đó. Main.java:3 là tên tệp và số dòng. Đừng đoán mò: đọc dòng đó, sửa đúng một điều nó nêu, rồi biên dịch lại. Lỗi biên dịch nghĩa là chưa có gì chạy cả; lỗi lúc chạy (trông khác hẳn) nghĩa là chương trình đã bắt đầu rồi mới thất bại.

Chương trình kiểm tra nhanh

Chạy chương trình này trong trình soạn thảo, hoặc lưu thành Main.java rồi chạy javac Main.java và java Main trên máy của bạn. Nếu bạn thấy cả ba dòng, bộ công cụ của bạn đã hoạt động trọn vẹn:

Ở đây có ba thứ bạn sẽ sớm gặp kỹ hơn: một biến int, nối chuỗi bằng +, và một mảng cùng .length của nó. Lúc này chỉ cần chương trình biên dịch được và in ra là đủ.

Tiếp theo: cú pháp Java

Bạn đã chạy vài chương trình, nhưng chúng ta vẫn lướt qua phần dấu câu: dấu ngoặc nhọn, dấu chấm phẩy, public static void main, và lý do mỗi dòng trông như vậy. Trang tiếp theo phân tích cú pháp Java từng phần một, để cấu trúc không còn giống code mẫu rập khuôn mà bắt đầu trở nên hợp lý.

Câu hỏi thường gặp

Chạy một chương trình Java như thế nào?

Lưu code vào một tệp đặt theo tên lớp public (ví dụ Main.java), mở terminal trong thư mục đó và chạy hai lệnh: javac Main.java để biên dịch thành bytecode, rồi java Main để chạy. Với JDK 11 trở lên, bạn có thể bỏ qua bước đầu cho một tệp duy nhất và chạy thẳng java Main.java.

javac và java khác nhau thế nào?

javac là trình biên dịch: nó đọc mã nguồn .java của bạn và tạo ra một tệp .class chứa bytecode. java là trình khởi chạy: nó khởi động JVM và chạy bytecode trong tệp .class. Bạn biên dịch một lần bằng javac, rồi chạy bao nhiêu lần tùy thích bằng java.

Vì sao Java báo lỗi "could not find or load main class"?

Hầu như luôn là do bạn truyền sai tên cho java. Hãy dùng tên lớp, không phải tên tệp: viết java Main, không phải java Main.class hay java Main.java. Cũng đảm bảo bạn đang ở thư mục chứa Main.class và tên lớp khớp chính xác với tên tệp, kể cả chữ hoa chữ thường.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu