Lập trình Java trung cấp
Tóm tắt: Ngôn ngữ Java™ cung cấp hầu hết những gì mà các lập trình viên
chuyên nghiệp mong đợi đối với một ngôn ngữ lập trình và thậm chí là đối với
một ngôn ngữ hướng-đối tượng. Thế nhưng, ngoài những điều căn bản, ngôn ngữ
Java còn cung cấp một số công cụ có ích để tạo ra các chương trình tinh vi hơn.
Hướng dẫn này sẽ giới thiệu cho bạn một số trong các đặc tính nâng cao hơn này
của ngôn ngữ Java thường được thấy trong các dự án phát triển công nghệ Java
điển hình.
Trước khi bạn bắt đầu
Về hướng dẫn này
Hướng dẫn này giới thiệu cho bạn về các khả năng của ngôn ngữ Java tinh tế hơn
những khả năng đã trình bày trong hướng dẫn "Giới thiệu về lập trình Java" (xem
Tài nguyênđể tìm liên kết đến hướng dẫn này và các tài liệu khác được tham
chiếu trong đó). Để học được nhiều nhất từ hướng dẫn này, bạn nên tìmhiểu xong
hướng dẫn nhập môn đó hoặc làm quen với các khái niệm được trình bày trong nó.
Ngôn ngữ Java cung cấp một bộ công cụ khổng lồ có thể giúp cho một lập trình
viên hoàn thành hầu hết mọi nhiệm vụ. Trong hướng dẫn này, chúng tôi sẽ trình
bày một số trong các công cụ cao cấp hơn thường được dùng trong các dự án phát
triển Java, bao gồm như sau:
Thừa kế và trừu tượng hóa.
Các giao diện.
Các lớp lồng trong.
Các biểu thức chính quy.
Các sưu tập.
Ngày tháng.
Vào/Ra (I/O)
ác luồng ký tự. Reader
flavors read bytes from a byte stream and convert them
to characters. The Writer chuyển đổi các ký tự thành các
byte để đặt chúng vào các luồng byte.
BufferedReader and
BufferedWriter
Là bộ đệm dữ liệu trong khi đọc hoặc viết một luồng
khác, cho phép các hoạt động đọc và ghi có hiệu quả
hơn. Bạn gói một luồng khác trong một luồng có bộ
đệm.
Các luồng là một chủ đề lớn và chúng ta không thể trình bày toàn bộ chúng ở đây.
Thay vào đó, chúng ta sẽ tập trung vào các luồng được khuyến cáo dùng để đọc và
viết các tệp tin. Trong hầu hết trường hợp, đây sẽ là các luồng ký tự, nhưng chúng
tôi sẽ sử dụng cả các luồng ký tự và các luồng byte để minh họa các khả năng này.
Đọc và viết các tệp tin
Có một số cách để đọc ra từ và viết vào một File. Người ta có thể cho rằng cách
tiếp cận đơn giản nhất diễn ra như sau:
Tạo một FileOutputStream trên File để viết vào nó.
Tạo một FileInputStream trên File để đọc từ nó.
Gọi read() để đọc từ File và write() để viết vào File.
Đóng các luồng, dọn dẹp sạch sẽ nếu cần thiết.
Các mã có thể trông giống như sau:
try {
File source = new File("input.txt");
File sink = new File("output.txt");
FileInputStream in = new FileInputStream(source);
FileOutputStream out = new FileOutputStream(sink);
int c;
while ((c = in.read()) != -1)
out.write(c);
in.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
Ở đây chúng ta tạo ra hai đối tượng File: một FileInputStream để đọc từ tệp tin
nguồn và một FileOutputStream để viết tới File kết quả. (Lưu ý: Ví dụ này đã
được điều chỉnh từ ví dụ CopyBytes.java trong Java.sun.com; xem Tài nguyên).
Chúng ta sau đó đọc vào từng byte của dữ liệu đầu vào và ghi nó vào kết quả đầu
ra. Sau khi đã xong, chúng ta đóng các luồng. Có lẽ là khôn ngoan khi đặt một lời
gọi close() vào trong khối cuỗi cùng (finally). Tuy nhiên, trình biên dịch của ngôn
ngữ Java sẽ còn yêu cầu bạn phải nắm bắt nhiều trường hợp ngoại lệ khác có thể
xảy ra, điều này có nghĩa là cần một mệnh đề catch khác nữa nằm trong khối
finally của bạn. Có chắc chắn đáng làm không? Có thể.
Vậy là bây giờ chúng ta có một cách tiếp cận cơ bản để đọc và viết. Nhưng sự lựa
chọn khôn ngoan hơn, và về một vài khía cạnh, sự lựa chọn dễ dàng hơn, là sử
dụng một số luồng khác mà chúng ta sẽ thảo luận trong phần tiếp theo.
Các luồng có bộ đệm
Có một số cách để đọc ra và ghi vào một File, nhưng cách tiếp cận điển hình và
thuận tiện nhất diễn ra như sau:
Tạo một FileWriter trên File.
Gói FileWriter trong một BufferedWriter.
Gọi write() trên BufferedWriter mỗi khi cần thiết để viết các nội dung của
File, thường ở cuối mỗi dòng cần viết ký tự kết thúc dòng (đó là, \n).
Gọi flush() trên BufferedWriter để làm rỗng nó.
Đóng BufferedWriter, dọn dẹp sạch nếu cần thiết.
Các mã có thể trông giống như sau:
try {
FileWriter writer = new FileWriter(aFile);
BufferedWriter buffered = new BufferedWriter(writer);
buffered.write("A line of text.\n");
buffered.flush();
} catch (IOException e1) {
e1.printStackTrace();
}
Ở đây, chúng ta tạo ra một FileWriter trên aFile, sau đó chúng ta gói nó trong một
BufferedWriter. Thao tác viết có bộ đệm hiệu quả hơn là đơn giản viết mỗi lần
một byte. Khi chúng ta đã thực hiện viết từng dòng (mà chúng ta tự kết thúc bằng
\n), chúng ta gọi flush() trên BufferedWriter. Nếu chúng ta không làm như vậy,
chúng ta sẽ không nhìn thấy bất kỳ dữ liệu nào trong tệp tin đích, bất chấp mọi
công sức cố gắng viết tệp tin này.
Khi chúng ta có dữ liệu trong tệp tin, chúng ta có thể đọc nó bằng các mã tương tự
đơn giản:
String line = null;
StringBuffer lines = new StringBuffer();
try {
FileReader reader = new FileReader(aFile);
BufferedReader bufferedReader = new BufferedReader(reader);
while ( (line = bufferedReader.readLine()) != null) {
lines.append(line);
lines.append("\n");
}
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println(lines.toString());
Chúng ta tạo ra một FileReader, sau đó gói nó trong một BufferedReader. Điều đó
cho phép chúng ta sử dụng phương thức thuận tiện readLine(). Chúng ta đọc từng
dòng cho đến khi không có gì còn lại, viết thêm mỗi dòng vào cuối StringBuffer.
của chúng ta. Khi đọc từ một tệp tin, một IOException có thể xảy ra, do đó chúng
ta bao quanh tất cả logic đọc tệp tin của chúng ta bằng một khối try/catch.
Tóm tắt
Chúng tôi đã trình bày một phần quan trọng của ngôn ngữ Java trong hướng dẫn
"Giới thiệu về lập trình Java" (xem Tài nguyên) và hướng dẫn này, nhưng ngôn
ngữ Java là rất lớn nên chỉ một hướng dẫn nguyên khối (hoặc thậm chí một số
hướng dẫn nhỏ hơn) không thể bao gồm tất cả mọi vấn đề. Dưới đây nhặt ra một
số lĩnh vực mà chúng tôi còn chưa nêu ra:
Chủ đề Mô tả ngắn gọn
Threads Có một chương trình chỉ thực hiện một việc tại một thời điểm có thể là
có ích, nhưng hầu hết các chương trình ngôn ngữ Java tinh vi có nhiều
luồng (threads) thực thi chạy cùng một lúc. Ví dụ, các tác vụ in ấn hoặc
tìm kiếm có thể chạy ở mặt sau. Lớp Thread và các lớp có liên quan
trong java.lang có thể cung cấp cho bạn khả năng phân luồng mạnh mẽ
và linh hoạt trong chương trình của bạn. developerWorks có các trang
Web với nhiều tài nguyên tốt về phân luồng trong mã Java của bạn,
nhưng một điểm bắt đầu thích hợp là các hướng dẫn "Giới thiệu về các
luồng Java" và "Tương tranh trong JDK 5.0" và loạt các bài viết này
của Brian Goetz.
Reflection
Một trong những khía cạnh mạnh của ngôn ngữ Java (và thường là một
trong những điều ám ảnh nhất) là sự phản chiếu hay khả năng để xem
thông tin về chính mã của bạn. Gói java.lang.reflect bao gồm các lớp
như Class và Method cho phép tra xét cấu trúc mã của bạn. Ví dụ, bạn
có thể tìm thấy một phương thức bắt đầu với get, sau đó gọi nó bằng
cách gọi invoke() trên đối tượng Method -- rất mạnh. Phần 2 của loạt
bài "Các động lực trong lập trình Java" của Dennis M. Sosnoski nói về
việc sử dụng phản chiếu.
NIO
Kể từ JDK 1.4, ngôn ngữ Java đã kết hợp một số khả năng I/O tinh vi
hơn, dựa trên một API hoàn toàn mới gọi là I/O mới hoặc viết tắt là
NIO. Sự khác biệt chính là ở chỗ I/O của ngôn ngữ Java truyền thống là
dựa trên các luồng (như chúng ta đã thảo luận ở trên), trong khi NIO
dựa trên một khái niệm gọi là khối I/O, các kênh và các bộ đệm. Khối
I/O này có xu hướng có hiệu quả hơn việc gửi từng byte đơn lẻ thông
qua một luồng. Mặt hạn chế là NIO là khái niệm khó. "Khởi đầu với
I/O mới (NIO)" của Greg Travis là một hướng dẫn tuyệt vời về chủ đề
này.
Sockets
Các chương trình ngôn ngữ Java của bạn có thể giao tiếp với hầu như
bất kỳ chương trình nào trên một thiết bị có khả năng IP. Tất cả những
gì bạn cần làm là mở một kết nối ổ cắm (socket) với một địa chỉ IP và
một cổng trên thiết bị đó. API các ổ cắm (Sockets API) của ngôn ngữ
Java hỗ trợ việc này. Xem hướng dẫn "101 các ổ cắm của Java" của
Roy Miller và Adam Williams để được giới thiệu về API các ổ cắm.
Hướng dẫn "Sử dụng JSSE cho giao tiếp ổ cắm an toàn" của Greg
Travis cho bạn thấy làm thế nào để thực hiện bảo mật giao tiếp ổ cắm
của bạn.
Swing
Ngôn ngữ Java bao gồm các hỗ trợ rộng lớn cho việc phát triển GUI
dưới dạng Swing. Bộ Swing của các API bao gồm các lớp cho các vật
dụng và các phần tử khác để tạo ra các giao diện người dùng có đầy đủ
đặc tính. Có một số tài nguyên quan trọng trên developerWorks liên
quan đến Swing, nhưng một điểm thích hợp để bắt đầu là bài viết giới
thiệu "Giao diện người dùng của Java 2" của Matt Chapman. Chuyên
mục Magic với Merlin của John Zukowski tập trung vào những thay
đổi và cập nhật Swing gần đây. John cũng chủ trì trang web Diễn đàn
thảo luận lập trình Java phía khách, vì vậy bạn có thể nhận được sự hỗ
trợ cho việc lập trình Swing ở đó. Hướng dẫn "Di chuyển ứng dụng
Swing của bạn đến SWT" thảo luận cách làm thế nào để di chuyển từ
Swing đến SWT của IBM, một giải pháp thay thế gọn nhẹ nhưng vẫn
rất mạnh mẽ.
JNI
Khi chương trình Java của bạn cần phải giao tiếp với một chương trình
khác, ví dụ viết bằng ngôn ngữ C, Java cho bạn một cách để làm điều
đó, đó là: Giao diện bản địa Java (JNI). API này cho phép bạn chuyển
đổi các lời gọi phương thức của Java thành các lời gọi đến các hàm C
(để tương tác với các hệ điều hành và tương tự). Hướng dẫn "Lập trình
Java với JNI" của developerWorks thảo luận về các cơ cấu của JNI với
mã Java, C và C++.
RMI
API về viện dẫn phương thức từ xa của ngôn ngữ Java (RMI - Remote
Method Invocation) cho phép một chương trình bằng ngôn ngữ Java,
hoặc trong một tiến trình hoặc trên một máy tính, truy cập vào chương
trình ngôn ngữ Java khác đang chạy trong một tiến trình khác và/hoặc
trên máy tinh khác. Nói cách khác, RMI hỗ trợ các cuộc gọi phương
thức phân tán giữa các chương trình đang chạy trong các máy ảo Java
khác nhau. Hướng dẫn "Các đối tượng phân tán của Java: Sử dụng
RMI và CORBA" của Brad Rubin cung cấp một sự mở đầu vững chắc
về RMI và thảo luận về RMI và CORBA cùng với nhau. Bạn cũng nên
xem bài viết này của Edward Harned để tìm hiểu lý do tại sao RMI
không phải là một máy chủ ứng dụng làm sẵn.
Security
Ngôn ngữ Java bao gồm các API bảo mật tinh vi để hỗ trợ xác thực và
cấp phép. Làm thế nào bạn có thể chắc chắn rằng những người nào đó
sử dụng chương trình của bạn được phép thực hiện ? Làm thế nào bạn
có thể bảo vệ các thông tin khỏi những con mắt tò mò? Các API bảo
mật có thể trợ giúp. Trên developerWorks cung cấp nhiều nội dung có
liên quan đến bảo mật Java. Dưới đây chỉ là một vài ví dụ: Trang web
Diễn đàn thảo luận bảo mật Java được John Peck, một lập trinh viên và
chuyên gia bảo mật Java kỳ cựu, chủ trì; "Bên trong cơ chế cấp phép
Java" của Abhijit Belapurkar; và "Bảo mật Java, Phần 1: Những điều
căn bản về mật mã hóa" và "Bảo mật Java , Phần 2: Xác thực và cấp
phép" cả hai đều của Brad Rubin.
File đính kèm:
Lập trình Java trung cấp.pdf

