Category Archives: Java

Tìm hiểu chia sẽ về ngôn ngữ Java

REFACTORING TRONG NETBEANS PHẦN 1

Tutorial :Refactoring Java Source

REFACTORING TRONG NETBEANS

Tutorial này mình sẽ nói về tính năng rất mạnh mẽ trong NetBeans một tính năng này cá nhân mình yêu thích: “Refactoring”.

Nếu bạn chưa  biết gì NetBeans thì vào đây tìm hiểu nhé: http://netbeans.org/features/index.html, thằng này nó  miễn phí(free), Cross-flastform(Đa nền tảng).Nó là một Môi trường mã nguồn mở(Open Source) phát triển(Development) giao diện(Interface) [IDE] cho các nhà phát triển phần mềm.Netbeans là sản phẩm của Sun Microsystems. Một IDE là một ứng dụng phần mềm cung cấp các tiện ích mở rộng để các lập trình viên phát triển phần mềm, chẳng hạn như một trình soạn thảo mã nguồn(editor), trình biên dịch(Editor compiler), thông dịch, xây dựng các công cụ tự động hóa, và một trình gỡ lỗi(Debug). …

“Refactoring”, nó hổ trợ thay đổi mã nguồn của bạn một cách dễ dàng. Hãy tưởng tượng di chuyển một class giữa các gói(package) và phải chỉnh sửa nội dung trong gói bằng tay ở phía trên cùng của mỗi tập tin, hoặc muốn xóa một biến trong code  và bạn không biết rằng nếu nó được tham chiếu ở một nơi khác trong ứng dụng của bạn. Thực hiện sữa chữa bằng tay có thể dễ bị lỗi. Tuy nhiên, với khả năng sắp xếp tiên tiến có sẵn trong NetBeans, bạn có thể làm thay đổi như vậy  một cách rất dễ dàng. NetBeans cung cấp các tùy chọn sắp xếp(Menu sổ xuống) nhiều trên menu Refactor của nó. Mình sẽ minh họa một nửa trong số tiện ích trong Refactor(Netbeans) ngày hôm nay và một nửa khác trong một bài viết tiếp theo.

Refactor trong Netbeans:

Chúng ta đi tìm hiểu vào từng thành phần một của Menu sổ xuống này nhé.

Rename:

Rename refactoring cho phép bạn thay đổi không chỉ là tên của lớp(class name) mà còn bất kỳ constructor(Phương thức khởi tạo),Các member(Field,Method)….. Ở đây, tôi sẽ thay đổi tên của giá trị biến thành AddedValue trong lớp ImportingClass:

Chọn Refactor

Tự động, tên biến cũng được thay đổi trong lớp MoveClass:

Move(Di chuyển):

Move(di chuyển) một class(Lớp) từ một package(gói) đến một package(gói) khác có thể xem như là một nhiệm vụ dễ dàng, bạn chỉ cần sao chép và dán nội dung của tập tin nguồn vào thư mục mới và sau đó chỉnh sửa các câu lệnh trong gói ở phía trên cùng của tập tin .Tuy nhiên, nếu các lớp khác Import hoặc reference class đó.Sau đó các nhà phát triển(Chúng ta) cũng phải tìm kiếm thông qua và sửa đổi các tập tin. Ở đây là làm thế nào bạn có thể di chuyển MoveClass từ gói refactoringpackage2 tới  refactoringpackage1:

Copy(sao chép):

Copy refactoring  cho phép bạn sao chép nội dung của một class tới  package(gói) khác.Ttự động thay đổi package(gói) câu lệnh ở trên cùng của tập tin nguồn.

Chuyển class nội dung class copyClass đến gói refactoringpackage2

Chon copy

To Package:Copy tới gói….(bạn chọn gói để copy tới)

Safe Delete(Xóa an toàn):

Đôi khi bạn xem lại code trước đây, bạn quyết định loại bỏ một biến thành viên của 1 Class mà bạn nghĩ rằng nó không được sử dụngchỉ để tìm ra nó không thực sự xuất hiện trong code của bạn, và sau đó class của bạn không biên dịch được. Với refactoring Xóa an toàn, bạn có thể xác định từng cách sử dụng một Method(Phương thức), Class(Lớp), hoặc field(biến) trong code trước khi xóa nó. mình sẽ minh họa  nó bằng việc cố gắng để xóa các biến AddedValue từ lớp ImportingClass :

Tuy nhiên , biến được tham chiếu trong MoveClass class, vì vậy xóa nó sẽ gây ra một lỗi. Thì NetBeans cảnh báo bạn, và thậm chí có thể hiển thị cho bạn nơi mà các member  bạn  muốn xóa bị tham chiếu. nếu bạn nhấp vào  nút “Show Useges…”

Change Method Parameters (Thay đổi Tham số Phương thức):

Change Method Parameters cho phép bạn thay đổi mọi thứ một cách an toàn. Ở đây bạn có thể add Paramater(Thêm tham số) ,xóa(Remove),sữa(tên biến,kiểu dữ liệu….) Paramater(Tham số).thay đổi mức truy cập(Access),kiểu trả về(Return Type),tên phương thức(Name Method) và cho bạn create new Method(Tạo mới 1 phương thức) và Delegate phương thức tồn tại(Nghỉa là gọi phương thức hiện hành trong Create new  Method ).Hình ảnh này mình sẽ cố gắng để xóa tham số x của phương thức Show trong ImportingClass Class:

Tham số X được sử dụng trong thân của phương thức, và do đó một cảnh báo sẽ được hiển thị:

Đối các ví dụ sau , mình sẻ tạo ra thêm một lớp được gọi là Truck, lớp này được thừa kế từ một lớp  Vehicles

Pull Up:

Khi làm việc với Class và lớp cha(Supper Class), Pull Up refactoring là rất hữu ích. Nó cho phép bạn di chuyển các thành viên lớp (Field  và Method) từ một lớp con(subclass ) vào lớp cha(Supper Class).

-Chúng ta thấy nó chuyển method stop() trong class con(subclass) chuyển lên class cha(supperclass)

Push Down:

Push Down là đối lập với Pull Up refactoring. Nó đẩy một thành viên lớp cha xuống thành một lớp con.

Chỉ có bao nhiêu đây cho hướng dẫn này, lưu ý rằng ở đây chỉ có một nửa các tính năng của NetBeans refactoring. Nhóm mình sẽ viết tiếp một  nửa còn lại về Repactoring trong một bài tiếp .Các bạn đón theo giỏi nhé.

Tác giả : Trần Thanh Nhã

Trang tham khảo:

http://significantinsignificance.wordpress.com   |  http://docs.oracle.com/javase/

Sử dụng Thread trong java

Trong lập trình Thread được sử dụng rất phổ biến, đặc biệt là trong những ứng dụng game thì điều này hoàn toàn chắc chắn. Nhưng đối với những người mới học thì định nghĩa này còn khá mơ hồ đúng không nào? Vậy Thread là gì nhỉ? Bài này chúng ta sẽ cùng tìm hiểu và trao đổi những vấn đề liên quan đến Thread. Mình sẽ cập nhật bài viết từ từ, mong sớm nhận được những phản hồi tích cực hoặc những đóng góp của bạn để bài viết sớm hoàn thành.

Định nghĩa: Thread là một tiến trình tách ứng dụng ra một hoặc nhiều luồng khác nhau để cùng thực hiện nhiều nhiệm vụ cùng một lúc. (Tự định nghĩa)
[IMG]
Như hình trên chùng ta thấy người đàn ông và chiếc xe tăng là hai tiến trình khác nhau. Gọi chung là thực thể, hai thực thể này được thực hiện đồng thời bằng cách sử dụng Thread. (Bài viết chỉ mang tính chất tương đối, dùng để cụ thể hóa bài viết ở tính chất tham khảo, thực tế game sẽ hoạt động dựa vào nhiều kỹ thuật khác nữa, vì thế chúng ta đề cập đến vấn đề này chỉ ở mức độ sử dụng sử dụng Thread mà không bàn nhiều về Game)

Thread được tạo bời lớp java.lang.Thread
Khai báo và sử dụng

PHP:
public class DemoThread {
public static void main(String[] args) {
Thread th1 = new Thread(); //Khởi tạo Thread

th1.start(); //Thực thi Thread th1
}
}

Đoạn code trên là cơ bản về tạo và thực thi một Thread.
Tiếp theo chúng ta sẽ định nghĩa nội dung mà Thread được thực hiện như thế nào bằng cách viết code trong phương thức run() (mặc định như đoạn code phía trên thì chương trình sẽ thực thi phương thức run() với nội dung rỗng, đồng nghĩa với việc không làm gì cả).

PHP:
public class DemoThread {
public static void main(String[] args) {
Thread th1 = new Thread(){
public void run(){
System.out.println("Thread vừa được thực thi");
}
}; //Khởi tạo Thread

th1.start(); //Thực thi Thread th1

}
}

[IMG]

Người dùng tự định nghĩa Thread
Đến đây chúng ta sẽ tìm hiểu cách để tạo ra một Thread như thế nào? Java cung cấp cho chúng ta 2 cách để tự định nghĩa một Thread đó là extend từ lớp Thread hoặc implement từ Runnable interface.

[IMG]
Hình trên chúng ta thấy rằng khi Thread được implement từ Runnale thì phải chạy bằng phương thức run() do phương thức start() không có sẵn trong Runnable interface.
Tiếp đến chúng ta sẽ định nghĩa nội dung cho hàm run() của hai Thread phía trên.

PHP:
public static void main(String[] args) {
My_Thread my = new My_Thread();
MyThread_Impl imp = new MyThread_Impl();

my.start();
imp.run();
//Thêm dòng này nữa để kiểm tra thử
System.out.println("Kết thúc chương trình!");
}

[IMG]

Ở trên tôi sử dụng thêm phương thức sleep() với giá trị 1000 milliseconds (tương đương với một giây), mục đích của việc này để tạm dừng tiến trình sau 1 giây. Lúc này kết quả sẽ được như sau:
[IMG]

Như hình trên các bạn thấy cả hai tiến trình đều được thực hiện song song, vì vậy nó trộn lẫn vào với nhau, tuy nhiên các bạn để ý nếu đúng như định nghĩa thì hai tiến trình này tách biệt so với ứng dụng mới đúng và vòng lặp với mỗi lần một giây tổng cộng là 3 giây. Với khoảng thời gian này thì chương trình dư sức thực hiện in ra dòng “Kết thúc chương trình”. Thế nhưng tại sao dòng “Kết thúc chương trình!” lại được thực hiện cuối cùng? Quay lại hàm main các bạn sẽ thấy.

[IMG]

Chúng ta chưa kết luận vội thử thay đổi cách viết để ép Thread được thực hiện bằng phương thức start() thử xem:

[IMG]

Ở trên tôi tạo một đối tượng Thread với tên “th” với tham số truyền vào là một đối tượng Thread được implement từ Runnable interface. Mục đích để chạy phương thức start() được cung cấp sẵn trong lớp java.lang.Thread
Sau khi run kết quả như sau:
[IMG]
Như vậy có thể nhận thấy rằng chương trình sẽ thực hiện từ đầu đến cuối và tách ra 2 tiến trình chạy song song luôn không ảnh hưởng gì cả, đây chính là mục đích chúng ta cần. Chương trình chạy hết hàm main còn hai tiến trình vẫn chạy đến khi kết thúc mới thôi.
Vậy các bạn lưu ý khi sử dụng lớp được implement từ interface Runnable nhé!

Đồng bộ hóa trong java
Bây giờ chúng ta sẽ tìm hiểu đồng bộ hóa trong java với từ khóa synchronized

synchronized methods
Giả sử chồng và vợ có 2 cái thẻ ATM. Hai người cùng rút một số tiền nhất định vào cùng một thời điểm, sau khi rút tiền máy ATM hiển thị kết quả ngược lại so với mong muốn.
[IMG]
Như vậy số tiền kia bay đi đâu rồi! Ai sẽ chịu trách nhiệm đây? (Chắc là ngân hàng):D
Minh họa cho sự cố này:
[IMG]
Hình trên tôi cố tình chạy hai tiến trình vào cùng một thời điểm, cùng với việc trừ 1000$ salary trong tài khoản. Tôi sử dụng thêm phương thức getName() để biết được chính xác tên của Thread hiện tại. Và được kết quả:
[IMG]
Tài khoản salary của gia đình là $2000, mà vợ rút $1000 thì phải còn $1000 nhưng còn lại $0. Nguyên nhân do Thread của vợ đang rút $1000 thì Thread của chồng cũng rút $1000 vào cùng thời điểm đó dẫn đến bất đồng bộ.
Và để giả quyết vấn đề trên ta chỉ cần thêm từ khóa synchronized vào trước kiểu giá trị trả về của phương thức là đủ. Minh họa hình dưới:
[IMG]

Mục đích của chính của synchronized là khi đã có một tiến trình A sử dụng tài nguyên này rồi thì những tiến trình khác phải chờ đến khi tiến trình A kết thúc thì mới được phép sử dụng. Kết quả:
[IMG]
Như vậy tiến trình của người chồng phải chờ tiến trình người vợ kết thúc mới được phép sử dụng tài nguyên, đồng nghĩa với việc thời gian xử lý sẽ tăng lên gấp đôi (do phải chờ tiến trình trước kết thúc) nhưng điều này đảm bảo rằng dữ liệu luôn luôn được toàn vẹn.

synchronized block
Thay vì sử dụng synchronized một phương thức như ở trên thì chúng ta cũng có thể synchronized một đoạn nhỏ trong phương thức của một đối tượng bằng cách sử dụng synchronized block, minh họa hình dưới:
[IMG]
Ở hình trên tôi đã đánh dấu khối được synchronized, các bạn để ý bên cạnh từ khóa synchronized sẽ có cấu trúc “<TênClass.Class>” như trong trường hợp này sẽ là mThread.Class hoặc đơn giản hơn bạn thay thế bằng từ khóathis cũng được, mục đích của từ khóa đó dùng để chỉ rõ đối tượng đối tượng hiện tại sẽ được synchronized và tôi vừa thêm một dòng thông báo “đăng xuất [X]” để xem chuyện gì sẽ xảy ra, kết quả:
[IMG]
Như vậy tiến trình người vợ sau khi thực hiện xong khối lệnh được synchronized thì sẽ nhường quyền cho tiến trình người chồng thực hiện mà không hề ép tiến trình người chồng chờ đợi thêm.
Như vậy với cách trên chúng ta cũng có thể synchronized một đối tượng khác mà thread hiện tại đang nắm giữ với cú pháp như sau:

PHP:
Object obj = new Object();
...
synchronized (obj) {  // in a method
... // nội dung
}

Đến đây xem như kết thúc phần đồng bộ hóa trong java!

http://congdongjava.com

JTable trong Java:Cách sử dụng cơ bản

Trong Java, JTable là một trong những component chủ đạo trong việc hiển thị dữ liệu. Nó là một Swing component cung cấp khả năng biểu diễn dữ liệu ở dạng bảng biểu. Ngoài ra, JTable còn cho phép bạn có thể dễ dàng chỉnh sửa thông tin ngay trên các cell của nó như khi bạn làm việc với Excel vậy. Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách thao tác với dữ liệu của bảng để hiển thị chúng lên JTable.

Như các bạn đã biết, kiến trúc của JTable nói riêng và Swing nói chung, đều được xây dựng dựa theo mô hình MVC nên phần data (Model) sẽ tách biệt với phần giao diện (UI). Điều này tạo nên sự rõ ràng, mạch lạc cho code, nhưng có thể gây khó khăn với những ai mới bắt đầu.

Để hiển thị dữ liệu với JTable, chúng ta có nhiều cách. Bạn có thể lợi dụng một contructor của JTable như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MyTable extends javax.swing.JFrame {
    public final static boolean GENDER_MALE = true;
    public final static boolean GENDER_FEMALE = false;
    public final static String[] columnNames = {
        "First Name", "Last Name", "Date of Birth", "Account Balance", "Gender"
    };
    public Object[][] values = {
        {
            "Clay", "Ashworth",
            new GregorianCalendar(1962, Calendar.FEBRUARY, 20).getTime(),
            new Float(12345.67), GENDER_MALE}, {
            "Jacob", "Ashworth",
            new GregorianCalendar(1987, Calendar.JANUARY, 6).getTime(),
            new Float(23456.78), GENDER_MALE}, {
            "Jordan", "Ashworth",
            new GregorianCalendar(1989, Calendar.AUGUST, 31).getTime(),
            new Float(34567.89), GENDER_FEMALE}, {
            "Evelyn", "Kirk",
            new GregorianCalendar(1945, Calendar.JANUARY, 16).getTime(),
            new Float(-456.70), GENDER_FEMALE}, {
            "Belle", "Spyres",
            new GregorianCalendar(1907, Calendar.AUGUST, 2).getTime(),
            new Float(567.00), GENDER_FEMALE}
    };
    /** Creates new form MyTable */
    public MyTable() {
        initComponents();
        setLayout(new BorderLayout());
        JTable myTable = new JTable(values, columnNames);
        JScrollPane jsp = new JScrollPane(myTable);
        getContentPane().add(jsp, BorderLayout.CENTER);
    }

Bạn cũng lưu ý rằng, để JTable có thể hiển thị tên cột, các bạn cần bao nó lại bằng một JScrollPane.

Cách trên giúp bạn nhanh chóng tạo ra một JTable với dữ liệu được hiển thị. Mảng 1 chiều cung cấp tên cột, mảng 2 chiều cung cấp data cho bảng. Tuy nhiên, cách này không thực tế, chúng ta thường chỉ sử dụng nó trong demo, khi bạn mới học về JavaSE. Một cách khác mà mình sẽ giới thiệu cho các bạn, cách mà các bạn sẽ thường dùng trong bài tập lớn, project…, đó là sử dụng data model.

Data model đảm nhận nhiệm vụ cung cấp dữ liệu hiển thị cho JTable. Sử dụng data model giúp ứng dụng “MVC” hơn bằng việc tách riêng phần data và phần UI, tạo ra sự custom tốt hơn cho những bài toán phức tạp.

Về cơ bản, một data model được cài đặt 9 phương thức do interface TableModel định nghĩa. Các phương thức đó được liệt kê trong hình dưới đây:

table model method JTable trong Java: Cách sử dụng cơ bản

Tác dụng của những phương thức trên bạn có thể dễ dàng suy ra thông qua tên của chúng, mình không nói lại nữa nhé. Bạn cũng có thể tham khảo thêm trên Java docs. Bạn sẽ phải tự mình cài đặt cả 9 phương thức trong trường hợp bạn tạo ra data model bằng cách implements interface TableModel. Tuy nhiên Java cũng tạo ra một số các lớp khác được cài đặt sẵn một số phương thức, giúp cho công việc của chúng ta đơn giản hơn. Cụ thể như class DefaultTableModel và abstract class AbstractTableModel, tất cả đều implements interface TableModel. Thông thường, chúng ta sẽ tạo ra data model bằng cách kế thừa AbstractTableModel. Khi đó, chúng ta chỉ cần thiết phải override lại 4 phương thức.

Dưới đây, mình sẽ tạo ra lớp CustomTableModel như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class CustomTableModel extends AbstractTableModel {
    public final static boolean GENDER_MALE = true;
    public final static boolean GENDER_FEMALE = false;
    public final static String[] columnNames = {
        "First Name", "Last Name", "Date of Birth", "Account Balance", "Gender"
    };
    public Object[][] values = {
        {
            "Clay", "Ashworth",
            new GregorianCalendar(1962, Calendar.FEBRUARY, 20).getTime(),
            new Float(12345.67), GENDER_MALE}, {
            "Jacob", "Ashworth",
            new GregorianCalendar(1987, Calendar.JANUARY, 6).getTime(),
            new Float(23456.78), GENDER_MALE}, {
            "Jordan", "Ashworth",
            new GregorianCalendar(1989, Calendar.AUGUST, 31).getTime(),
            new Float(34567.89), GENDER_FEMALE}, {
            "Evelyn", "Kirk",
            new GregorianCalendar(1945, Calendar.JANUARY, 16).getTime(),
            new Float(-456.70), GENDER_FEMALE}, {
            "Belle", "Spyres",
            new GregorianCalendar(1907, Calendar.AUGUST, 2).getTime(),
            new Float(567.00), GENDER_FEMALE}
    };
    @Override
    public int getRowCount() {
        return values.length;
    }
    @Override
    public int getColumnCount() {
        return columnNames.length;
    }
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        return values[rowIndex][columnIndex];
    }
    // Need for showing column name
    @Override
    public String getColumnName(int columnIndex) {
        return columnNames[columnIndex];
    }
}

Trong thực tế, dữ liệu của bảng thường được cung cấp dưới dạng Vector hoặc List thay vì mảng 2 chiều như demo này. Khi đó, bạn cần sửa lại những phương thức đã override cho phù hợp.

Để JTable của chúng ta sử dụng data model vừa được tạo ra, chúng ta có thể sử dụng phương thức setModel() của JTable:

1
myTable.setModel(new CustomTableModel());

Kết quả khi chạy chương trình:

demo jtable basic JTable trong Java: Cách sử dụng cơ bản

Nhìn từ bề nổi, bạn có thể nhận xét rằng cấu trúc của 2 lớp này chỉ khác nhau ở chỗ DefaultTableModel được cài đặt nốt 3 phương thức mà AbstractTableModel còn bỏ ngỏ. Thế nhưng còn có sự khác biệt khá lớn nữa, để AbstractTableModel được khuyến khích sử dụng, chứ không phải DefaultTableModel.

Sở dĩ như vậy là bởi vì AbstractTableModel cho phép chúng ta toàn quyền điều khiển dữ liệu input cũng như output. Để xuất dữ liệu ra bảng, chúng ta phải tự mình cài đặt phương thức getValueAt(). Phương thức này nhận 2 tham số là chỉ số cột và chỉ số dòng. Nó quy định dữ liệu gì sẽ được cung cấp cho mỗi ô trong bảng (được xác định bởi 2 tham số hình thức). Không giống như thế, DefaultTableModel thiếu tính mềm dẻo và mở rộng hơn nhiều. Mặc định nó được cài sẵn tất cả các phương thức mà đã implements từ TableModel. Điều này dẫn đến việc bạn sẽ khó khăn hơn khi muốn can thiệp vào quá trình xử lý bảng. Hơn nữa, DefaultTableModel sử dụng Vector (chính xác hơn là một Vector bao gồm những Vector khác) làm dữ liệu input. Và kéo theo đó, các phương thức như getValueAt()setValueAt()… trong quá trình thực thi cũng thao tác với dữ liệu dạng Vector này. Vector là một Collection đã “lỗi thời” xuất hiện từ thời Java 1.0. Bạn có thể thấy trong Netbeans, bạn sẽ nhận được thông báo “Obsolete Collection” nếu cố tình dùng Vector. Vector có khá nhiều hạn chế như less thread-safe và chậm chạp hơn so với các Collection khác. ArrayList được khuyến cáo thay thế cho Vector. Cụ thể mình sẽ có một bài viết khác về vấn đề này.

Vậy nên, nếu làm việc với data model, bạn nên sử dụng AbstractTableModel và sử dụng ArrayList cho dữ liệu đầu vào.

Trong bài viết này, mình đã hướng dẫn cho các bạn cơ bản về cách hiển thị dữ liệu với JTable. Ở vài viết tiếp theo, chúng ta vẫn sẽ xoay quanh data model. Mình sẽ hướng dẫn các bạn override một số phương thức của TableModel để có thể chỉnh sửa dữ liệu trực tiếp trên các ô của bảng và làm thế nào để xử lý kết quả người dùng vừa mới cập nhật đó.

Happy Coding! 40 JTable trong Java: Cách sử dụng cơ bản

Download source code của bài viết

codeimba.com