Làm việc với Java bằng dòng lệnh
TIL
720
Java
155
terminal
5
Cli
5
White

Quang Dương viết ngày 18/11/2018

Mở đầu

Không ít người khi đọc bài viết này, thậm chí là khi nhìn thấy tiêu đề bài viết này sẽ đặt ra câu hỏi chẳng hạn như: "Tại sao lại phải khổ sở như thế khi mà có bao nhiêu IDE hiện đại hỗ trợ rồi? IntelliJ, Eclipse, Netbeans,... nhanh và tiện hơn nhiều."

À thì đồng ý rằng dùng IDE rất tiện và nhanh, chỉ cần tập trung vào việc code. Thế nhưng vẫn có một số người (như mình), cảm thấy không thoải mái khi dùng một thứ mà bản thân chưa biết rõ, muốn biết chuyện gì đang xảy ra ở phía sau, muốn học hỏi và sử dụng giao diện dòng lệnh thay vì các IDE, hoặc chỉ đơn giản là thích sử dụng dòng lệnh hơn những công cụ khác.

Mình là một người mới học Java. Trong bài viết này mình sẽ trình bày những gì mình đã tìm hiểu được:

  • Cách tổ chức thư mục trong project Java.
  • Sử dụng hai công cụ dòng lệnh là javacjava để biên dịch, chạy, sử dụng thư viện bên ngoài.

Nội dung

Tổ chức thư mục

Bên trong project của chúng ta nên có những thư mục sau:

|- src/
|- target/
|- lib/

src là thư mục chứa mã nguồn, chính là các file .java. Tại đây ta có thể đóng gói các file .java trong các thư mục.

target sẽ chứa các file .class - kết quả của quá trình biên dịch các file .java.

lib chứa các file .jar, những thư viện Java.

Biên dịch

Chúng ta khi mới học Java đều hẳn đã biết cách biên dịch một file Java duy nhất.

javac path/to/filename.java

Nếu biên dịch thành công thì chúng ta sẽ có một file .class cùng tên và cùng thư mục với file .java vừa biên dịch.

Tuy nhiên, đó lại không phải điều mà ta muốn/cần làm. Nếu chỉ có vậy thì không lẽ phải biên dịch từng file hay sao? Bởi trong thực tế, chúng ta làm việc với nhiều file, thậm chí còn là nhiều thư mục con.

Nhưng không vì thế mà ước mong sử dụng dòng lệnh bị dập tắt. Với cách tổ chức thư mục như phần trước, ta sẽ thực hiện lệnh như sau:

# Đối với Unix
javac $(find "./src" -name "*.java") -d "./target"
# Mọi nền tảng
javac -sourcepath "./src" "./src/path/to/Main.java" -d "./target"
# Có thể bỏ dấu nháy chuỗi cũng được 

Đối với Unix thì sử dụng dòng lệnh là quá hợp và việc biên dịch một project Java cũng là chuyện đơn giản. Như trong câu lệnh trên, ta lồng thêm lệnh find, liệt kê toàn bộ các file .java có trong thư mục src và đưa kết quả biên dịch vào thư mục target. Ý tưởng này mình lượm được từ Stack Overflow. Có lẽ không cần bình luận gì về cách làm này vì nó đảm bảo tính đầy đủ.

Tuy nhiên đối với cách 2, việc chỉ đưa vào 2 options -sourcepath-d cùng với đúng một file .java chứa hàm main làm ta có cảm giác thiếu thiếu, hình như là chỉ biên dịch duy nhất file chứa hàm main? Tất nhiên là mình có lời giải thích cho điều này: Khi làm việc với Java, ta luôn phải thực hiện công việc đóng gói, import các class. Giả sử một file import một hoặc vài class của file khác, trong số các file khác đó lại import class của các file khác nữa... Tất cả tạo nên sự liên kết. Chương trình viết bằng Java phải chạy từ hàm main, nếu nó không import gì cả thì không tận dụng được các class khác và chỉ cần biên dịch mình nó là được. Ngược lại nếu nó có import thì khi đó, mọi file có liên quan đều được biên dịch theo. Option -sourcepath sẽ tìm kiếm các file .java có trong đường dẫn thư mục được chỉ định. Do đó, làm như vậy là đủ tốt rồi.

Còn nếu bạn thích dùng cách làm với Unix như trên thì có thể cài đặt và sử dụng git-bash, tận dụng được nhiều lệnh trên Unix, đương nhiên là có cả find.

Sau khi biên dịch(thành công), cấu trúc thư mục/file được bảo toàn. Cấu trúc trong src như thế nào thì trong target vẫn thế, chỉ là phần mở rộng của các file là .class thay vì .java.

Chạy chương trình

javac là công cụ để biên dịch file .java, còn java lại là công cụ để chạy file .class. Đương nhiên hầu hết người học Java sẽ biết cách chạy file .class duy nhất từ dòng lệnh.

# Đối với file tại thư mục hiện hành
java filename
# Đối với file trong một thư mục khác
java -cp path/to/file filename
# hoặc dài hơn nhưng tương đương
java -classpath path/to/file filename
# Chẳng hạn như ta đang ở thư mục A, nhưng file .class lại ở trong thư mục B, thư mục B lại nằm trong thư mục A thì ta dùng lệnh
java -cp B filename

Và bạn cũng biết đấy, chúng ta chỉ cần chạy file .class chứa hàm main mà thôi.

Kết hợp với thư viện

Vậy là chúng ta đã giải quyết xong hai phần chính của project là các thư mục srctarget, giờ chỉ còn lại các thư viện trong lib.

Các thư viện Java của chúng ta là những file .jar. Để tận dụng được chúng, đương nhiên chúng ta phải sử dụng các tiện ích của chúng trong mã nguồn rồi, việc còn lại là biên dịch/chạy như thế nào khi có thư viện mà thôi.

Việc biên dịch vẫn được thực hiện không khác gì mình đã trình bày ở trên. Chỉ có khi chạy, giá trị của option -classpath phải được bổ sung đường dẫn đến thư viện đó. Mình có ví dụ ngay đây: chẳng hạn mình có một file something.jar trong thư mục lib thì khi chạy chương trình, mình sẽ viết như sau:

# Đối với Windows
java -cp "./target;./lib/something.jar" Main
# hoặc
java -cp "./target;./lib/*" Main
# Đối với Unix
java -cp "./target:./lib/something.jar" Main
# hoặc
java -cp "./target:./lib/*" Main
# chỉ khác nhau đúng kí tự : và ;.

Mình có một chút lưu ý sau khi thử nghiệm, đó là nếu dùng wildcard * thì sẽ load được tất cả file .jar trong thư mục lib (nhưng chỉ ở gốc thư mục thôi nhé, nếu nằm trong thư mục con là chịu). Nếu muốn load từ thư mục con đến lúc đó ta lại nối tiếp đường dẫn vào -classpath:

# Đối với Windows
java -cp "./target;./lib/dir1/*;./lib/dir1/dir2/*" Main
# Đối với Unix
java -cp "./target:./lib/dir1/*:./lib/dir1/dir2/*" Main

Nếu như bạn thấy việc này làm dòng lệnh quá dài dòng, hãy đưa những file .jar mà bạn muốn tận dụng vào thư mục %JAVA_HOME%/jre/lib/ext (Windows) / $JAVA_HOME/jre/lib/ext (Unix) - khi đó chúng ta chỉ cần quan tâm đến đường dẫn tới main class.

Tạm kết

Đến đây thì mình tin rằng vấn đề dùng Java chỉ với dòng lệnh đã ổn. Giờ chúng ta có thể khá thoải mái làm việc với Java và công cụ dòng lệnh mà ngôn ngữ này cung cấp.

Có cách khác để biên dịch và chạy Java trên dòng lệnh nhưng dùng đến công cụ Maven, mình sẽ tìm hiểu vấn đề này sau, và có thể sẽ trở lại trong một bài viết khác về nó.

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Quang Dương

1 bài viết.
2 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Bài viết liên quan
White
0 0
Trong bài viết này, một số hình ảnh hoặc nọi dung có thể bị thiếu do quá trình chế bản. Vui lòng xem nội dung ở blog gốc sau: (Link) (Link), chúng...
programmerit viết gần 4 năm trước
0 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
1 bài viết.
2 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!