Nhập môn ngôn ngữ lập trình Java – Phần 5: Toán tử quan hệ và toán tử điều kiện, Câu lệnh if, switch


Vấn đề sẽ đề cập trong những bài viết này:

Java là một ngôn ngữ lập trình hướng đối tượng (Object-oriented Programming), nhưng đôi khi nó thật sự không đối tượng hoàn toàn (một số ý kiến cho rằng như thế). Vì thế, Loạt bài viết sau này tôi sẽ trình bài là phương pháp lập trình hướng đối tượng  (OOP) bằng ngôn ngữ Java.

Chú ý: Nhắc lại là đây là bài hướng dẫn cá nhân tôi, nên đôi lúc cách sử dụng câu chữ theo cảm tính, vì thế, có những từ ngữ không hoàn toàn chính xác và khoa học nhất. Đôi khi lại không theo trình tự nhất định. Tuy nhiên, đó là điều tôi nghĩ sẽ dễ hiểu nhất có thể.

Kiến thức thu được từ các bài viết:

Hiểu rỏ cấu trúc ngôn ngữ Java theo hướng đối tượng.

Vận dụng vào ví dụ hướng dẫn đi xuyên suốt bài viết.

Và một số vấn đề để lập trình tốt ngôn ngữ Java theo OOP.

Bạn cần nhớ rằng khi học Java hay một số ngôn ngữ khác, có rất nhiều từ ngữ thông dụng làm cho người học trở nên mơ hồ, rồi từ đó rất khó để nắm bắt được ngôn ngữ này. ví dụ như: SDK, JDK,  J2SE (J2SE SDK),IDE,… Và việc bạn cần làm là cố gắng hiểu được các từ đó, thông qua cụm từ tiếng Anh viết tắt của nó. Nếu gặp một từ như thế, bảng hãy tìm cụm từ tiếng Anh của nó và hiểu nó.

Phần này làm rõ một vài thứ như toán tử quan hệ và toán tử điều kiện, cách bạn có thể sử dụng câu lệnh if và switch. Tuy nhiên, phần này cũng giống như các phần khác không hướng dẫn hết tất cả mà chỉ là tổng quát một cấu trúc quan trọng của vấn đề đưa ra, rồi từ đó người học có thể tìm hiểu sâu hơn những phần học này, nhưng theo tôi sẽ dễ dàng hơn khi bạn đã nắm được kiến thức từ bài học.

Các toán tử quan hệ và toán tử điều kiện

Java cung cấp cho bạn một vài toán tử và câu lệnh điều khiển luồng để cho phép bạn ra quyết định trong mã lệnh của mình. Thông thường, một quyết định lựa chọn trong mã lệnh bắt đầu bằng một biểu thức logic (là biểu thức được đánh giá bằng hai giá trị đúng hoặc sai – true/false). Những biểu thức đó sử dụng các toán tử quan hệ, chúng so sánh một toán hạng hoặc một biểu thức với một với một toán hạng hay biểu thức khác, và các toán tử điều kiện nữa. Dưới đây là danh sách:

Toán tử Cách sử dụng Trả về true nếu…
> a > b a lớn hơn b
>= a >= b a lớn hơn hay bằng b
< a < b a nhỏ hơn b
<= a <= b a nhỏ hơn hay bằng b
== a == b a bằng b
! = a != b a không bằng b
&& a && b ab cả hai đều true, tính b có điều kiện
(nếu a là false thì không cần tính b nữa)
|| a || b a hoặc b là true, tính b có điều kiện
(nếu a là true thì không cần tính b nữa)
! ! a a là false
& a & b ab cả hai là true, luôn luôn tính b
| a | b a hoặc b là true, luôn luôn tính b
^ a ^ b ab là khác nhau (true nếu a là true và b là false,
hoặc ngược lại, nhưng không được đồng thời là true hoặc false)

Bạn phải hiểu rõ các toán tử, nó đóng vai trò quan trọng khi sử dụng câu lệnh if cũng như các câu lệnh khác: switch, vòng lặp for, while, do…while,… Và tất nhiên là cần hiểu về cách sử dụng biến sao cho hợp lệ.

Ghi nhớ về phạm vi của biến: Tất cả các biến trong Java điều có phạm vi (scope). Nếu biến nằm trong vùng phạm vi bạn có thể tương tác với nó tại đó và ngược lại. Phạm vi là gói gọn trong class, trong phương thức hay trong khối lệnh (khối lệnh được bao trong  hai dấu ngoặc nhọn mở  { và đóng } ). Từ phạm vi của biến mà người ta xác định đó là biến toàn cục hay biến vùng (tôi tạm gọi biến bị giới hạn trong phương thức hay khối lệnh là biến vùng).

Câu lệnh if else (if)

Else luôn luôn đi cùng if, nhưng if thì có thể có một, nhiều hoặc không có else nào.

Sử dụng điều kiện if

if (  boolean expression ) {
	 câu lệnh thực thi...
} [else if{
	 câu lệnh thực thi... 
}]
  ...........................
[else{
         câu lệnh thực thi...
}]

Khi có nhiều điều kiện cần giải quyết (n điều kiện), chúng ta dùng if để xử lý và kèm theo else if (điều kiện i) để kiểm tra điều kiện thứ i. Và cuối cùng là else thực thi điều kiện ngoài điều kiện đã kiểm tra trước đó.

ví dụ:

Trường hợp 1: If không kèm theo else (if)

public String walk(int steps) {
	if (steps > 100)
		return "I can't walk that far at once";//return thứ 1
	
	progress = progress + steps;
	return "Just took " + steps + " steps."; //return thứ 2
}

điều kiện if ở đây kiểm tra steps > 100 hay không. Nếu lớn hơn, thực hiện điều kiện này (tức là return “I can’t walk that far at once”. Nếu steps nhỏ hơn 100 thì tính toán progress và trả về return thứ 2. Ở đây thực ra chúng ta có thể lồng else vào đây. (Xem trường hợp 2)

Trường hợp 2: Chỉ có một  if và một else

public String walk(int steps) {
	if (steps > 100){
		return "I can't walk that far at once";//return thứ 1
        }
	else{
        	progress = progress + steps;
	        return "Just took " + steps + " steps."; //return thứ 2
        }
}

Kết quả hoàn toàn giống trường hợp 1, tuy nhiên chỉ khi cần thiết thật sự chúng ta mới nên sử dụng cách này, vì trường hợp này làm code trở nên dài dòng khó hiểu. Dấu { và dấu } của if có thể bỏ bớt đi khi khối lệnh chỉ có một dòng như trong trường hợp này. Thay vì viết

if (steps > 100){
	return "I can't walk that far at once";//return thứ 1
}

ta có thể viết

if (steps > 100)
	return "I can't walk that far at once";//return thứ 1

Như vậy có thể lượt bớt đi những dòng thừa thải, điều này được gọi là gia vị cú pháp vô nghĩa.

Trường hợp 3: Cú pháp if có nhiều else…if.

if (steps > 100)
	return "I can't walk that far at once";
else if (steps > 50)
	return "That's almost too far";
else {
	progress = progress + steps;
	return "Just took " + steps + " steps.";
}

Và chúng ta có thể thêm nhiều else…if nữa nếu còn điều kiện xử lý. Tuy nhiên, nên viết ngắn gọn nhất có thể nhưng phải đảm bảo tính nhất quán của code khi viết (điều này sẽ đề cập ở phần cuối cùng).

Trường hợp khác của if

Có một dạng viết tắt của lệnh if trông hơi xấu, nhưng cùng đạt được mục đích, mặc dù dạng viết tắt này không cho phép có nhiều câu lệnh cả trong phần if lẫn trong phần else. Dó là dùng toán tử tam nguyên ?:. (Toán tử tam nguyên là toán tử có ba toán hạng). Chúng ta có thể viết lại câu lệnh if đơn giản theo cách sau:

return (steps > 100) ? "I can't walk that far" : "Just took " + steps + " steps.";

Nhược điểm của cách này: Làm cho câu lệnh trở nên khó hiểu và không thể viết được nếu câu lệnh quá nhiều điều kiện để xử lý.

Tôi đi chi tiết vào if để bạn (người mới nhập môn) có thể hiểu được cách dùng một câu lệnh (if), và sau đó khi tìm hiểu về câu lệnh khác: vòng lặp for, while sẽ không bị bỡ ngỡ và tôi cũng không trình bày chi tiết nữa.

Lệnh Switch

Nếu if kiểm tra điều kiện với số nguyên đơn lẻ(điều kiện truyền vào if là số nguyên) thì một câu lệnh khác cũng có thể giải quyết được vấn đề này. Đó là Switch. Như vậy, đây là sự khác nhau giữa if và switch. Switch chỉ xử lý điều kiện là một số nguyên đơn lẻ, nó không kiểm tra điều kiện bằng với một toán tử nào hết, chẳng hạn như ==, >, <,… Ngược lại if có thể làm được điều này. Như vậy switch giống như một câu lệnh chỉ xử lý được tập con cần giải quyết của if.

Sử dụng switch

switch ( integer expression ) {
	case 1:
		 statement(s) 
		[break;]
	case 2:
		 statement(s) 
		[break;]
	case n:
		 statement(s) 
		[break;]
	[default:
		 statement(s) 
		break;]
}

Không cần phân tích nhiều vào cú pháp khai báo switch, chúng ta đi đến một ví dụ điển hình sử dụng câu lệnh switch.

int month = 3;
switch (month) {
	case 1: System.out.println("January"); break;
	case 2: System.out.println("February"); break;
	case 3: System.out.println("March"); break;
	case 4: System.out.println("April"); break;
	case 5: System.out.println("May"); break;
	case 6: System.out.println("June"); break;
	case 7: System.out.println("July"); break;
	case 8: System.out.println("August"); break;
	case 9: System.out.println("September"); break;
	case 10: System.out.println("October"); break;
	case 11: System.out.println("November"); break;
	case 12: System.out.println("December"); break;
	default:  System.out.println("That's not a valid month number."); break;
}

Nhập vào một tháng (month) là tháng 3. Dùng switch kiểm tra và trả về kết quả. Nhắc lại, switch không kiểm tra một biểu thức logic như steps > 100 hay x == 3, chúng chỉ kiểm tra 1 số nguyên đơn lẻ.

Còn một (có thể hơn một) cách xử dụng switch khác, bạn hãy tự tìm hiểu về nó.

 

Phần tiếp theo: Nhập môn ngôn ngữ lập trình Java – Phần 6: Các câu lệnh vòng lặp for, while

Viết mã thú vị với các API FileNet P8 của IBM, Phần 1: Hello, Document!


Bắt đầu với chương trình FileNet P8 đầu tiên của bạn

Bill Carpenter, Kiến trúc sư phần mềm ECM, IBM

Tóm tắt:  Bài viết này giúp bạn khởi đầu bằng việc phát triển một ứng dụng đơn giản,HelloDocument, với FileNet® P8 Content API (API Nội dung FileNet P8) của IBM®. Thông qua một chuỗi các hoạt động đơn giản, hãy tìm hiểu cách sử dụng các mô hình mã hóa để thực hiện một loạt các hoạt động riêng của bạn. Các API P8 có thể mở rộng và để biết cách khởi đầu cần có một chút khéo léo với những người mới bắt đầu. Bài viết này cung cấp cho bạn sự khởi đầu đó: một định hướng và bệ phóng mà từ đó bạn có thể dễ dàng xây dựng các ứng dụng riêng của mình. Thậm chí nếu bạn đã quen với việc phát triển P8, chắc chắn bạn sẽ tìm thấy thông tin có ích trong bài viết này và các bài viết tiếp theo trong loạt bài này. Các bài viết trong sắp tới trong loạt bài này đi sâu hơn về các chủ đề cụ thể trong cả hai API quy trình và API nội dung.

Hãy làm quen với HelloDocument

Bài viết này cung cấp cho bạn một tổng quan về một ứng dụng FileNet P8 của IBM đầy đủ, độc lập. P8 là một nền tảng của IBM về Quản lý nội dung doanh nghiệp (ECM-Enterprise Content Management). Mặc dù hầu hết các chương trình P8 trong thế giới thực là một phần của một khung công tác lớn hơn như J2EE hay .Net, là một nhà phát triển, nhiều khả năng điểm bắt đầu có thể của bạn là một chương trình độc lập. Bằng cách sử dụng một chương trình độc lập, bạn có thể tập trung vào các chi tiết P8 mà không cần phải tập trung vào sự phức tạp của khung công tác lớn hơn.

Ứng dụng ví dụ HelloDocument thực hiện một số nhiệm vụ, một số trong đó bạn có thể không cần biết về nó, tuy nhiên, bạn có thể muốn làm một điều riêng biệt nào đó trong ứng dụng đó. Ngoài ra, bạn có thể sử dụng các kỹ thuật được minh họa trong mã này và mở rộng chúng để làm những việc phù hợp hơn với các trường hợp sử dụng của mình. Có lẽ cũng quan trọng không kém, một khi bạn có HelloDocument đang chạy, bạn có thể tự tin rằng môi trường của bạn được cấu hình đúng. Điều này cho phép bạn sau đó tập trung vào các chi tiết ứng dụng của mình mà không còn vương vấn nghi ngờ về môi trường của bạn nữa.

Để hiểu bài viết này, bạn cần có một sự hiểu biết cơ bản về Java™ và có thể làm theo các mô tả của mã nguồn Java. Bài viết này không mô tả tất cả các dòng mã của HelloDocument.java mà, thay vào đó, đi vào những điểm nổi bật để minh họa các quan điểm API của Máy nội dung (CE-Content Engine). Mã này có rất nhiều chú thích và nếu bạn thích phiêu lưu, bạn có thể bỏ qua bài viết này và đi ngay vào chính mã nguồn của nó (xem phần Tài nguyên).

HelloDocument được cấu trúc như một tệp nguồn Java duy nhất có 400-500 dòng. Thậm chí khi tính đến nhiều chú thích trong mã nguồn, vẫn còn rất nhiều dòng chỉ để làm quen. Có một số thứ trong HelloDocument.java mà bạn muốn di chuyển vào các lớp hoặc các tệp nguồn riêng biệt . Chúng được trình bày tất cả ở một chỗ duy nhất để cho bạn có thể chắc chắn là bạn có mọi thứ. Ví dụ, chuỗi đăng nhập Dịch vụ xác thực và ủy quyền Java (JAAS) đầy đủ, bao gồm một lớp bên trong xử lý các cuộc gọi lại, được bao gồm trong tệp nguồn HelloDocument.java. Điều đó chắc chắn sẽ là một sự lựa chọn khác thường với một ứng dụng thực tế. Lớp HelloDocument triển khai thực hiện giao diện PrivilegedAction và gói hầu hết logic nghiệp vụ của mình bên trong một phương thức chạy chỉ để dễ dàng minh họa mô hình đăng nhập JAAS rõ ràng. Logic nghiệp vụ cho HelloDocumenthóa ra không quá 50 -100 dòng.

Bài viết này được viết khi bản phát hành hiện tại trong lĩnh vực này đã là P8 4.0.1 và P8 4.5.0 đã đến cuối chu kỳ phát triển của nó. Mã này chạy được trong cả hai bản phát hành. (Bài viết này và các bài viết khác trong loạt bài này không dành nhiều thời gian cho các API từ P8 3.x. Trong một số trường hợp, các API này là hoàn toàn khác nhau). Vì các lớp API và các phương thức được dùng làm lõi cho các API, chúng rất ổn định. Nhiều khả năng là HelloDocument sẽ chạy mà không cần thay đổi gì trong một số chu kỳ phát hành P8 sắp tới. HelloDocument được viết bằng Java. Vì API của Content Java P8 khác với API của Content .Net P8 chủ yếu trong quy ước đặt tên và các lý do phụ khác, nên để viết lại HelloDocument bằng một ngôn ngữ .Net giống như C# sẽ chỉ là một việc chuyển chữ đơn giản. (Trong lĩnh vực xác thực có sự không giống nhau giữa hai API. Mặc dù bài viết này bàn về xác thực Java cho HelloDocument, nhưng việc thảo luận chung về xác thực nằm ngoài phạm vi của bài viết này.)

Vậy thì, HelloDocument thực sự làm cái gì? Nó tạo ra một tài liệu, tải nội dung từ một tệp lên, kiểm tra tệp và đặt tệp đó trong một thư mục. Sau đó nó đọc lại tệp đó và so sánh nội dung được tải về với nội dung tệp gốc. Theo tùy chọn, bạn có thể cấu hình ứng dụng để bỏ qua một phần của tệp trong quá trình tải về và so sánh. Mặc dù việc tạo và lưu các tài liệu thành tệp là phổ biến cho nhiều trường hợp sử dụng, nhưng lại không có các bước so sánh. Trong thực tế, bạn chưa bao giờ phải kiểm tra nội dung mà bạn đã tải lên. Các phần bổ xung trong khi tải về chỉ có nghĩa minh họa một số khía cạnh viết mã API. HelloDocument được thiết kế để cho bạn không phải làm bất kỳ thiết lập cụ thể nào trong Máy nội dung (CE) trước khi bạn chạy nó (ngoài việc bảo đảm chắc chắn rằng bạn có các quyền truy cập để tạo các thư mục và các tài liệu mới). Một khi bạn có nó đang chạy trong môi trường của mình, bạn có thể chạy nó nhiều lần mà không bị lỗi.

Cấu hình

Cấu hình nhúng

Một số các mục trong cấu hình điều khiển HelloDocument, chẳng hạn như URI (Uniform Resource Identifier-Trình nhận dạng tài nguyên thống nhất) của kết nối Máy nội dung (CE), là chung cho hầu hết các ứng dụng P8. Những mục khác là dành riêng cho ví dụ HelloDocument. Trong một ứng dụng thực tế, bạn sẽ gần như chắc chắn không mã hóa cứng các mục cấu hình này. Bạn sẽ sử dụng các đối số dòng lệnh, một tệp cấu hình hoặc một số cơ chế khác để tách cấu hình ra khỏi mã của chính ứng dụng. Để cho thuận tiện, HelloDocument định nghĩa tất cả các mục cấu hình đó như là các hằng số trong một lớp bên trong tĩnh tên làConfigInfo, được hiển thị dưới dạng viết tắt trong Liệt kê 1. Ở đây bạn thấy các tham chiếu tới ConfigInfo.SOME_VALUE rải rác trong mã đó, chúng đang tham chiếu đến các hằng số này.
Liệt kê 1. Lớp bên trong tĩnh ConfigInfo

private static final class ConfigInfo
{
    // . . .

    /**
     * This URI tells us how to find the CE and what protocol to use.
     */
    static String CE_URI = "http://myCEserver:7001/wsi/FNCEWS40DIME";
    /**
     * This ObjectStore must already exist.
     */
    static String OBJECT_STORE_NAME = "MyObjectStore";

    // . . .
}

Mỗi mục trong ConfigInfo có các chú thích giải thích cách sử dụng nó. Bạn nên xem xét từng mục và đặt nó tới một giá trị thích hợp cho môi trường của bạn.

ConfigInfo

Các mục cấu hình khác

Vì đây là một bài viết về cách viết mã, nó không đi sâu vào nhiều chi tiết về cách thiết lập đường dẫn lớp Java và các mục cấu hình bên ngoài khác của bạn. Tài liệu về nền tảng P8 mô tả cách thiết lập một môi trường khách không rõ ràng. Nó là khác với mỗi nhánh của máy chủ ứng dụng J2EE. Phần tương tự của tài liệu đó cũng mô tả cách cấu hình các giá trị cài đặt JAAS của bạn. Các ví dụ và các hướng dẫn trong phần còn lại của bài viết này dựa trên điều kiện mọi giá trị ấy được cấu hình đúng.

Nhận hay tìm nạp?

Một đối tượng Java trong API không phải là thứ giống hệt như một đối tượng trong một kho lưu trữ CE. Nó chỉ đại diện cho một tham chiếu đến đối tượng CE qua đó bạn có thể kiểm tra các giá trị đặc tính, chuyển hướng bằng cách đi theo các đặc tính do đối tượng định giá (các OVP) và thực hiện nhiều kiểu cập nhật. Sự phối hợp thực sự giữa đối tượng API và đối tượng CE xảy ra khi API thực hiện một chuyến đi khứ hồi (truyền dữ liệu khứ hồi) đến máy chủ. Số các chuyến đi khứ hồi đến máy chủ nhiều lần là yếu tố chi phối hiệu năng của một ứng dụng, vì vậy API cung cấp việc kiểm soát chặt chẽ hơn khi các chuyến đi khứ hồi thực sự xảy ra và dữ liệu nào truyền trên dây cho mỗi chuyến đi khứ hồi ấy. HelloDocument khá cẩn thận về giảm thiểu các chuyến đi khứ hồi, nhưng nó đặc biệt không lưu ý về việc giảm thiểu số lượng dữ liệu liên quan đến các yêu cầu hoặc các đáp ứng. Bạn có thể điều chỉnh các kích cỡ tải đó thông qua các bộ lọc đặc tính và các cơ chế khác. Các bộ lọc đặc tính này được thảo luận chi tiết hơn trong một bài viết sắp tới của loạt bài này. Bây giờ, tất cả mọi thứ mà bạn thực sự cần biết là API được thiết kế để làm việc mà nếu bạn không sử dụng các bộ lọc đặc tính thì cũng chẳng có gì bất ngờ cả. Một khi bạn có được một sự hiểu biết cơ bản về API, chắc chắn bạn sẽ muốn sử dụng các bộ lọc đặc tính vì chúng có thể cải thiện đáng kể hiệu năng, cả hai vừa bằng cách giảm kích cỡ tải trọng và vừa bằng cách kết hợp một số chuyến đi khứ hồi.

Khi bạn đang tạo một đối tượng Java, API có một quy ước có ích. Các tên của các phương thức factory (nhà máy) (và một số các kiểu phương thức khác) sử dụng tiền tố get (nhận) để biểu thị một hoạt động cục bộ và tiền tố fetch (tìm nạp) để biểu thị rằng một chuyến đi khứ hồi sẽ được thực hiện với máy chủ CE. (Cũng có một động từ thứ ba nữa: create (tạo) được sử dụng khi ý định của bạn không chỉ là tạo một đối tượng Java, mà còn là tạo một đối tượng CE mới trong một kho lưu trữ hoặc ở nơi nào đó khác). Trong biệt ngữ API, việc tạo một đối tượng Java mà không có một chuyến đi khứ hồi đến máy chủ được gọi là fetchless instantiation (tạo đối tượng không tìm nạp). Vì vậy, ví dụ, conn = Factory.Connection.getConnection(ConfigInfo.CE_URI) là cục bộ. Ở nhiều vị trí trong mã nguồn HelloDocument, một chú thích no R/T được sử dụng để nhấn mạnh đến việc tạo đối tượng không tìm nạp hoặc hoạt động khác mà một người nào đó có thể ngây thơ nghĩ rằng cần có một chuyến đi khứ hồi. Lưu ý rằng các phương thức get được sử dụng bất cứ nơi nào có thể.

Một điều kỳ lạ có thể xảy ra khi bạn sử dụng việc tạo đối tượng không tìm nạp. API tin rằng các đối tượng CE mà bạn tham chiếu thực sự tồn tại. Nếu bạn thích nó, bạn có thể nói dối hoàn toàn với API biết, mặc dù điều này thường không có ích. Sự tính toán này chỉ cần đến khi một chuyến đi khứ hồi xảy ra liên quan đến đối tượng đó. Tại thời điểm đó, máy chủ CE chấp nhận một cách có phương thức các tham chiếu đối tượng của bạn với các đối tượng CE thực tế. Đương nhiên, việc tạo ra một đối tượng CE là một trường hợp đặc biệt được xử lý theo cách bạn mong đợi. Có một số trường hợp khác (nằm ngoài phạm vi của bài viết này), ở đó có thể có ích để tham chiếu các đối tượng CE không tồn tại; chúng đơn thuần phải tồn tại vào lúc CE nghe về chúng.

Điểm mấu chốt là bạn có được một cải tiến hiệu năng bằng cách sử dụng việc tạo đối tượng không tìm nạp, nhưng các giá tương ứng phải trả là việc xử lý lỗi của ứng dụng của bạn có thể phải đối phó với việc thiếu các đối tượng ở giai đoạn sau. Trên thực tế, giá phải trả cho việc xử lý lỗi đó không quá nghiêm trọng.

Bắt đầu ObjectStore

Phương thức HelloDocument.run là nơi diễn ra logic nghiệp vụ chính từ trên xuống. Việc bắt đầu của phương thức này, cùng với biến cá thể cho một Connection (kết nối), minh họa một mô hình mã hóa rất phổ biến (xem Liệt kê 2). Không nghi ngờ gì, hầu hết các ứng dụng nội dung chỉ xử lý các đối tượng bên trong các kho lưu trữ CE và hầu hết trong số chúng chỉ xử lý một kho lưu trữ duy nhất.
Liệt kê 2. HelloDocument.run và bạn bè

/**
 * All interaction with the server will make use of this Connection object.
 * Connections are actually stateless, so you don't have to worry about
 * holding open some CE resource.
 *
 * no R/T
 */
private Connection conn = Factory.Connection.getConnection(ConfigInfo.CE_URI);
// ...
/**
 * This method contains the actual business logic.  Authentication has
 * already happened by the time we get here.
 */
public Object run()
{
    // Standard Connection -> Domain -> ObjectStore
    //no R/T
    Domain dom = Factory.Domain.getInstance(conn, null);
    //no R/T
    ObjectStore os = Factory.ObjectStore.getInstance(dom,
                                           ConfigInfo.OBJECT_STORE_NAME);

    String containmentName = createAndFileDocument(dom, os);

    File f = new File(ConfigInfo.LOCAL_FILE_NAME);
    long fileSize = f.length();
    System.out.println("Local content size is " + fileSize + " for file "
                                                    + ConfigInfo.LOCAL_FILE_NAME);
    long skipPoint = 0L;
    if (ConfigInfo.USE_SKIP)
    {
        long midPoint = fileSize / 2;
        // pick a random point in the second half of the content
        skipPoint =  midPoint + (long)Math.floor((Math.random() * midPoint));
    }
    System.out.println("Will skip to " + skipPoint + " of " + fileSize);

    readAndCompareContent(os, containmentName, skipPoint);
    return null;
}

Mô hình mã hóa để bắt đầu một ObjectStore như sau:

ObjectStore

  1. Nhận một đối tượng Connection.
  2. Nhận một đối tượng Domain.
  3. Nhận một đối tượng ObjectStore.

Một đối tượng Connection là một lớp khá nhẹ. Nó nói cho API cách kết nối với máy chủ CE. Vì các tương tác giữa API và máy chủ CE là không trạng thái theo quan điểm của máy chủ CE, nên đối tượng Connection không duy trì mở bất kỳ tài nguyên phía máy chủ đắt giá nào. Mục thông tin chính được duy trì trong đối tượng Connection là URI được sử dụng. API suy diễn cả hai phương thức để nối và định vị CE từ URI. Cụ thể là, bạn nên lưu ý đối tượng Connection không giữ thông tin người dùng. Có thể thiết lập các tham số cấu hình bổ sung cho một đối tượng Connection, nhưng cơ chế đó không được mô tả trong bài viết này.

Domain (miền) là một đối tượng giữ tài nguyên P8 ở mức ObjectStore hoặc trên mức này. Để tạo một đối tượng Domain của Java, bạn cần một đối tượng Connection và một tên miền. Hiện nay, một bản cài đặt P8 chỉ có một miền duy nhất, do đó, API cho phép bạn chuyển một giá trị bằng không cho tên miền vào phương thức Factory. Tên của miền được thiết lập trong thời gian cài đặt P8 và nếu có lúc nào bạn muốn tìm hiểu về nó, thì bạn có thể xem xét giá trị đặc tính Name của đối tượng Domain.

Một đối tượng ObjectStore biểu diễn một kho lưu trữ CE. Lưu ý rằng phương thức Factory để tạo ra một đối tượngObjectStore không lấy một đối tượng Connection. Thay vào đó, nó lấy một đối tượng Domain. (Thật đúng khi nói rằng một đối tượng Domain điều khiển một đối tượng ObjectStore, nhưng bài viết này không nói nhiều hơn về các mục đích này). Ở bên trong, API sử dụng cùng một đối tượng Connection cho đối tượng Domain và các đối tượng được tạo từ nó. Sau đó, khi chínhObjectStore được sử dụng để tạo các đối tượng, đối tượng Connection sẽ tự động được chuyển đi cùng với chúng trong các API.

Phần mã này cũng là một nơi thích hợp để lưu ý đến việc sử dụng các phương thức factory nói chung. API của CE có một số lượng lớn các lớp factory (nhà máy): ước chừng có một lớp factory cho mỗi lớp CE. Các lớp này được sắp xếp cho thuận tiện vào các lớp lồng nhau bên trong lớp com.filenet.api.core.Factory. Để tìm ra lớp factory cho bất kỳ lớp CE đặc biệt nào, hãy tìm kiếm bên trong Factory một lớp bên trong có tên là Document (Tài liệu) hoặc Folder (Thư mục) hoặc bất cứ lớp CE nào mà bạn đang tìm kiếm. Trong phạm vi lớp bên trong ấy, bạn sẽ tìm thấy chỉ có một ít phương thức thích hợp để khởi tạo các đối tượng Java cho lớp CE đó. Thật dễ dàng để tìm ra những tham số nào dành cho các phương thức nhà máy này. Các phương thức nhà máy là an toàn-kiểu theo nghĩa là chúng trả về các kiểu cụ thể. Ví dụ, các phương thức Factory.Folder mỗi phương thức trả về một đối tượng kiểu Folder. Ý tưởng đằng sau các phương thức nhà máy và an toàn-kiểu nói chung là để giảm các khả năng mắc lỗi lập trình. Vì bạn không phải phải ép kiểu, có nhiều khả năng là trình biên dịch sẽ bắt được bất kỳ vấn đề nào. Điều đó thích hợp hơn cho việc kiểm tra-kiểu thời gian chạy.

Có một họ các phương thức khác, nhỏ hơn (không được sử dụng nhiều trong HelloDocument) đó là không an toàn-kiểu. Trong biệt ngữ API, đây là các phương thức tiện nghi (commodity methods). Một ví dụ là phương thức ObjectStore.getObject, có thể trả về các đối tượng của hầu như bất kỳ lớp CE độc lập nào. Ý định của phương thức tiện nghi là để sử dụng trong các mô hình mã hóa ứng dụng cụ thể xử lý nhiều kiểu theo một mẫu chung. Thường không có nhiều lý do về việc sử dụng các phương thức tiện nghi khi bạn đang xử lý các kiểu cụ thể được biết trước.

Tạo một cá thể Document mới

Tập hợp các dòng đầu tiên bên trong phương thức HelloDocument.createAndFileDocument đặt nền móng cho việc tạo ra một tài liệu mới có nội dung (xem Liệt kê 3). Ở cuối các dòng mã đó, cá thể Document Java được chuẩn bị với hầu hết các hành động mà bạn muốn có, nhưng cá thể Document của CE vẫn chưa được tạo ra (vì bạn vẫn chưa thực hiện chuyến đi khứ hồi cần thiết tới máy chủ).
Liệt kê 3. Bên trong HelloDocument.createAndFileDocument, Phần 1

//no R/T
ContentTransfer ct = Factory.ContentTransfer.createInstance();
ct.setCaptureSource(fis);
// optional
ct.set_RetrievalName(ConfigInfo.LOCAL_FILE_NAME);
// optional
ct.set_ContentType("application/octet-stream");

ContentElementList cel = Factory.ContentElement.createList();
cel.add(ct);

//no R/T
Document doc = Factory.Document.createInstance(os, null);
//not required
doc.getProperties().putValue("DocumentTitle", ConfigInfo.DOCUMENT_TITLE);
doc.set_ContentElements(cel);
//no R/T
doc.checkin(AutoClassify.DO_NOT_AUTO_CLASSIFY, CheckinType.MAJOR_VERSION);

Chuỗi các hoạt động trong Liệt kê 3 có vẻ hơi khó hiểu cho đến khi bạn bắt đầu biết mô hình đối tượng CE, đặc biệt là mối quan hệ giữa một cá thể Document và nội dung của nó. Một đoạn nội dung duy nhất (ví dụ, một bảng tính hoặc một tài liệu văn bản) nằm trong một đối tượng gọi là một content element (phần tử nội dung). Cụ thể hơn, vì nội dung được lưu trữ trong kho lưu trữ với Document, nên bạn sử dụng lớp con của phần tử nội dung gọi là ContentTransfer. (Lớp con khác, ContentReference, được sử dụng khi các bit thực tế được lưu trữ ở một nơi khác). Một Document có thể có số lượng phần tử nội dung bất kỳ và vì chúng là các đối tượng phụ thuộc theo biệt ngữ của CE (chúng không thể tồn tại một mình; chúng cần một Document chứa đựng), đặc tính Document ContentElements là kiểu ContentElementList.

Bây giờ, hy vọng rằng, mọi thứ rõ ràng hơn một chút. Bạn sử dụng các phương thức factory để tạo ra một đối tượngContentTransfer, một đối tượng ContentElementList, và một đối tượng Document. Bạn thêm đối tượng ContentTransfervào đối tượng ContentElementList, rồi bạn thiết lập giá trị đặc tính ContentElements của Document từ ContentElementList. Có một chút linh hoạt về trình tự làm những việc này, vì thế bạn có thể sắp xếp lại chúng trong ứng dụng riêng của mình sao cho có ý nghĩa hơn.

Mã này là một minh chứng tốt về việc sử dụng các phương thức người truy cập (accessor) của đặc tính an toàn-kiểu. Ví dụ, khi đặt tên truy tìm cho các phần tử nội dung (một đặc tính tùy chọn dùng như là một tên tệp gợi ý cho các ứng dụng sau đó tải về nội dung), bạn gọi ct.set_RetrievalName(ConfigInfo.LOCAL_FILE_NAME). Phương thức đó chỉ chấp nhận một đối số chuỗi ký tự, do đó, sẽ có một lỗi thời gian-biên dịch nếu bạn cố sử dụng một số nguyên. Phương thức getter tương ứng,ContentTransfer.get_RetrievalName, cũng an toàn-kiểu và trả về một giá trị chuỗi ký tự. Quy ước đặt tên API Java của set_và get_ (với một dấu gạch dưới) có tác dụng như một tín hiệu để báo cho bạn biết bạn đang xử lý một đặc tính theo nghĩa kho lưu trữ CE chứ không chỉ đơn thuần là một trường đối tượng Java điển hình. Mỗi đặc tính do hệ thống định nghĩa trên mỗi lớp CE có các phương thức người truy cập an toàn-kiểu. Đối với các đặc tính vốn dĩ chỉ đọc, không có phương thức setter an toàn-kiểu nào.

Thiết lập về đặc tính DocumentTitle trông hơi khác một chút so với các cuộc gọi phương thức setter khác:doc.getProperties().putValue("DocumentTitle", ConfigInfo.DOCUMENT_TITLE). Điều gì đang xảy ra ở đây? Nhiều người không nhận ra rằng DocumentTitle không phải là một đặc tính do hệ thống định nghĩa (theo quan điểm máy chủ CE, ở đó có một đặc tính do hệ thống định nghĩa là một đặc tính mà máy chủ CE tạo một giá trị cho nó hoặc nó có ảnh hưởng đến hành vi của máy chủ CE hoặc cả hai). Thay vào đó, DocumentTitle được định nghĩa thông qua một AddOn lúc tạo ObjectStore và bạn ít khi thấy một ObjectStore không có đặc tính DocumentTitle.Tuy nhiên, vì nó không phải là một đặc tính do hệ thống định nghĩa, không có phương thức người truy cập an toàn-kiểu nào cho nó trong các API. Thay vào đó, bạn phải thiết lập giá trị của nó thông qua một phương thức tiện nghi.

Phương thức Document.getProperties trả về một đối tượng Properties (Các đặc tính) biểu diễn các giá trị đặc tính được lưu trữ trong bộ nhớ nhanh cục bộ cho Document này và lớp Properties chứa các phương thức tiện nghi để nhận và thiết lập các giá trị đặc tính. Trong bất kỳ ứng dụng thực tế nào, bạn chắc chắn sẽ xử lý các thuộc tính tùy chỉnh, vì vậy bạn nên chắc chắn rằng bạn hiểu mô hình để truy cập giá trị đặc tính tiện nghi.

Như đã đề cập ở trên, kể cả sau khi gọi phương thức checkin (đăng nhập), Document vẫn chưa được tạo ra trong kho lưu trữ CE. Thay vào đó, nó được cho là có một hoặc nhiều hành động đang treo. Một hành động đang treo là việc gắn thẻ bên trong một đối tượng với một hoạt động cần được thực hiện trên máy chủ. (Có các phương tiện trong API để xem xét các hành động đang treo, nhưng bạn sẽ có thể chẳng bao giờ cần phải làm điều đó). Khi bạn gọi là phương thức factory để tạo đối tượng Documentcủa Java, nó sẽ tự động được gắn thẻ cho mình với hành động đang treo Create (Tạo). Khi bạn đã gọi phương thức checkin, nó thêm hành động đang treo Checkin. Đôi khi mọi người ngạc nhiên khi nhận thấy rằng đối với tất cả các lớp trong toàn bộ API, chỉ có mười tám kiểu hành động đang treo. Con số này là quá thấp vì các hoạt động trong CE thực sự bao gồm các hoạt động thông thường CRUD (tạo, lấy ra, cập nhật, xóa) trên các đối tượng và các đặc tính. Việc cập nhật một giá trị đặc tính, bất kể đặc tính hoặc lớp có liên quan, luôn được thực hiện thông qua một hành động đang treo Update (Cập nhật) hoặc như là một phụ trợ cho một số loại hành động đang treo khác. Bạn có thể nghĩ về các hành động đang treo như là các tập lệnh cho các máy chủ CE; chúng ra lệnh cho máy chủ CE phải làm gì với một đối tượng khi nó đến ở phía máy chủ.

Bây giờ hãy xem xét kỹ hơn một chút nữa về cuộc gọi phương thức checkin:doc.checkin(AutoClassify.DO_NOT_AUTO_CLASSIFY, CheckinType.MAJOR_VERSION). Nó nhận hai đối số được định nghĩa trong các lớp hằng số riêng. Các lớp hằng số này với các giá trị tham số được mã hoá bằng một mô hình bảng liệt kê an toàn-kiểu. Vì ban đầu API đã được viết cho một môi trường 1.4 của Java và vẫn có thể hoạt động trong môi trường này, nên không có sẵn các enum (bảng liệt kê) của ngôn ngữ Java. Các enum an toàn-kiểu bảo đảm an toàn-kiểu của chúng bằng cách buộc bạn sử dụng các hằng số từ một danh sách các lựa chọn thích hợp. Ví dụ, trình biên dịch Java không cho phép bạn vô tình đảo ngược thứ tự của hai đối số cho phương thức checkin. Nó sẽ dẫn đến một lỗi thời gian biên dịch thay vì một lỗi thời gian chạy. Nếu thiếu an toàn kiểu này, bạn có thể nhận được hành vi không đúng và không có báo lỗi.

Về đầu trang

Lưu Document thành tệp

Lúc này, bài viết này quay lại việc tạo Folder, nhưng bây giờ chúng ta hãy xem cách lưu Document thành tệp vào Folder đó. Có các phương thức trong API có tên là Folder.file and Folder.unfile. Nhiều người đều ngạc nhiên rằng các phương thức này thực sự là các phương thức của trình trợ giúp chứ không phải nguyên tắc cơ bản với các API. Chắc chắn, quan niệm về việc lưu dữ liệu thành tệp trong các thư mục là một tính năng CE cơ bản, nhưng hành động lưu dữ liệu thành tệp thực sự là việc tạo ra một đối tượng quan hệ để liên kết Folder và thùng chứa với nhau. Dù vì bất cứ lý do nào, thì ý tưởng này cùng mang lại cho nhiều người mới bắt đầu một lý do để tạm dừng, vì vậy Liệt kê 4 cho thấy cách lưu Document thành tệp mà không cần gọi phương thức Folder.file.
Liệt kê 4. Bên trong HelloDocument.createAndFileDocument, Phần 2

Folder folder = instantiateFolder(os);
//no R/T
DynamicReferentialContainmentRelationship rcr =
    Factory.DynamicReferentialContainmentRelationship.createInstance(os, null,
                       AutoUniqueName.AUTO_UNIQUE,
                       DefineSecurityParentage.DO_NOT_DEFINE_SECURITY_PARENTAGE);
rcr.set_Tail(folder);
rcr.set_Head(doc);
rcr.set_ContainmentName(ConfigInfo.CONTAINMENT_NAME);

Lớp DynamicReferentialContainmentRelationship (DRCR) có một tên dài, nhưng việc tạo ra nó lại dễ dàng. Nó liên kết một thư mục với một tài liệu được chứa trong đó. Nếu bạn nghĩ về một hình ảnh đồ họa của mối quan hệ đó như là một mũi tên trỏ từ Folder tới Document, bạn có thể thấy lý do tại sao OVP của mối quan hệ đó liên kết với Folder có tên là Tail và OVP của mối quan hệ đó liên kết với Document có tên là Head.

DRCR là động vì đặc tính Head của nó được cập nhật tự động khi Document đích được tạo phiên bản. Để tạo DRCR, hãy gọi phương thức factory thích hợp, phương thức này tạo ra một cá thể Java với một hành động đang treo Create rồi thiết lập một vài thuộc tính hệ thống. Trong trường hợp này, hãy sử dụng AutoUniqueName.AUTO_UNIQUE để ra lệnh cho máy chủ CE chỉnh sửa tên thùng chứa trong trường hợp có xung đột (các tên thùng chứa phải là duy nhất trong một Folder cụ thể). Một cách thay thế khác dành cho hoạt động có lỗi với một ngoại lệ.

DRCR là lớp con tạo được, vì vậy một ngày nào đó bạn có thể thấy thật có ích để tạo ra một lớp con và thêm một số đặc tính siêu dữ liệu riêng của bạn. Hãy nhớ rằng DRCR vẫn chưa được tạo ra trong kho lưu trữ CE (và cả Document đích cũng vậy).

Lưu vào kho lưu trữ

Cuối cùng, bây giờ là lúc để thực sự viết các thứ vào kho lưu trữ CE. Để gọi phương thức lưu trữ trên Document và DRCR sẽ là chuyện đơn giản, nhưng để cho phù hợp với chủ đích giảm thiểu các chuyến đi khứ hồi, hãy lưu lại cả hai thông qua mộtUpdatingBatch (xem Liệt kê 5).
Liệt kê 5. Bên trong HelloDocument.createAndFileDocument, Phần 3

UpdatingBatch ub = UpdatingBatch.createUpdatingBatchInstance(dom,
                                                           RefreshMode.REFRESH);
ub.add(doc, null);
ub.add(rcr, null);
System.out.println("Doing updates via UpdatingBatch");
ub.updateBatch();

Việc sử dụng một UpdatingBatch theo khái niệm là đơn giản nếu bạn nghĩ về nó như một cái thùng để mang những thứ này đến máy chủ CE. Bạn tạo cá thể UpdatingBatch, thêm các đối tượng vào nó, rồi gọi phương thức updateBatch để gửi tất cả mọi thứ đến máy chủ. Tất nhiên, việc được lưu trong kho lưu trữ CE chỉ có nghĩa là thêm các đối tượng có thay đổi. Bên cạnh việc giảm thiểu các chuyến đi khứ hồi, UpdatingBatch cũng có đặc tính quan trọng khác. Mọi thứ trong một UpdatingBatch xảy ra như là một giao dịch nguyên tử trên máy chủ. Hoặc là tất cả thành công hay tất cả thất bại. Điều đó không quan trọng vớiHelloDocument, nhưng thật bình thường để tìm các trường hợp sử dụng thực sự cần có hành vi giao dịch đó. UpdatingBatchlà một cách tốt để có được điều này với chi phí hiệu năng hợp lý.

Khi chúng ta đã tạo ra UpdatingBatch, chúng ta đã cung cấp một đối số để nói cho API trả về các cá thể đối tượng được làm mới từ một chuyến đi khứ hồi đến máy chủ. Thông thường, bạn sẽ không cần phải làm mới các đối tượng (hoặc bạn sẽ sử dụng các bộ lọc đặc tính để hạn chế kích cỡ của việc làm mới), nhưng trong trường hợp này chúng ta đã muốn sử dụng tên thùng chứa để minh họa cho một cái gì đó khác trong HelloDocument. Vì chúng ta đã ra lệnh cho máy chủ tự động chọn một tên thùng chứa duy nhất, nó có thể là khác với một tên mà chúng ta đã sử dụng với DRCR. Giá trị đặc tính được làm mới cho chúng ta biết máy chủ CE thực tế đã sử dụng cái gì.

Tạo Folder

Chúng ta đã bỏ qua việc tạo đối tượng Folder, do đó, bây giờ chúng ta hãy quay lại điều đó. Liệt kê 6 cho thấy HelloDocument.instatiateFolder.
Liệt kê 6. HelloDocument.instantiateFolder

private Folder instantiateFolder(ObjectStore os)
{
    Folder folder = null;
    try
    {
        //no R/T
        folder = Factory.Folder.createInstance(os, null);
        //no R/T
        Folder rootFolder = Factory.Folder.getInstance(os, null, "/");
        folder.set_Parent(rootFolder);
        folder.set_FolderName(ConfigInfo.FOLDER_NAME);
        //R/T
        folder.save(RefreshMode.NO_REFRESH);
    }
    catch (EngineRuntimeException ere)
    {
        // Create failed.  See if it's because the folder exists.
        ExceptionCode code = ere.getExceptionCode();
        if (code != ExceptionCode.E_NOT_UNIQUE)
        {
            throw ere;
        }
        System.out.println("Folder already exists: /" + ConfigInfo.FOLDER_NAME);
        //no R/T
        folder = Factory.Folder.getInstance(os, null, "/" + ConfigInfo.FOLDER_NAME);
    }
    return folder;
}

Việc thực hiện phương thức instantiateFolder hơi nhân tạo một chút vì chúng ta muốn làm cho việc chạy HelloDocumentnhiều lần không có sự cố và không cần bất kỳ sự thiết lập sẵn nào. Lựa chọn mà chúng ta đã làm là cố gắng để tạo ra Folder và quay trở lại việc tạo không tìm nạp nếu điều đó thất bại. Bạn có thể không làm điều đó trong một ứng dụng thực tế bởi vì cách làm này hầu như luôn không hiệu quả. Một cách làm khác là bạn thực sự có thể thực hiện tìm nạp Folder và quay lại để tạo nó nếu nó chưa tồn tại. Cách làm này vẫn đòi hỏi một chuyến đi khứ hồi để kiểm tra sự tồn tại của Folder (mà ứng dụng của bạn có thể biết nó tồn tại trong phần lớn thời gian). Vì vậy, có lẽ giải pháp tốt nhất, về mặt hiệu năng, là tạo Folder theo cách không tìm nạp với giả định rằng nó đã tồn tại trong kho lưu trữ. Điều đó có nghĩa là bạn sẽ cần phải điều chỉnh việc xử lý lỗi trong đoạn mã tiếp sau tính đến khả năng là nó thực sự không tồn tại. (Chúng ta không muốn làm hỗn loạn ví dụ này với sự phức tạp trong mã xử lý lỗi.)

Đọc nội dung

Bài viết này không dành nhiều thời gian mô tả việc đọc nội dung từ kho lưu trữ do hầu hết logic chỉ là việc xử lý luồng theo kiểu Java. Thay vào đó, chúng ta sẽ chỉ làm nổi bật một vài điểm bắt đầu với Liệt kê 7.
Liệt kê 7. Bên trong HelloDocument.readAndCompareContent

String fullPath = "/" + ConfigInfo.FOLDER_NAME + "/" + containmentName;
System.out.println("Document: " + fullPath);
//no R/T
Document doc = Factory.Document.getInstance(os, null, fullPath);
//R/T
doc.refresh(new String[] {PropertyNames.CONTENT_ELEMENTS});
InputStream str = doc.accessContentStream(0);

Chỉ cần cho thấy có thể làm được việc này, một đường dẫn đầy đủ tới Document được xây dựng từ các giá trị cấu hình và tên thùng chứa thực sự được trả về từ máy chủ CE. Đúng là bạn có thể dễ dàng nhận được giá trị mã định danh ID cho Documentđược tạo ra từ việc làm mới và sử dụng ID đó để tạo Document. (Sử dụng ID hiệu quả hơn một chút so với sử dụng đường dẫn vì dù thế nào đi nữa máy chủ CE phải chuyển đổi đường dẫn thành một ID.)

Document này được tạo không tìm nạp thông qua một phương thức nhà máy và sau đó một phương thức làm mới được gọi ngay để thu được giá trị của đặc tính ContentElements. Trong trường hợp này, nó được thực hiện chủ yếu để hiển thị cuộc gọi làm mới. Việc tạo Document thông qua một fetchInstance (cá thể tìm nạp) tạo ra hiệu quả hiệu năng như nhau, nhất là khi một bộ lọc đặc tính thích hợp được sử dụng để hạn chế dữ liệu đã tìm nạp. Phương thức Document.accessContentStream là một phương thức thuận tiện để gọi accessContentStream trên đối tượng phụ thuộc ContentTransfer thích hợp.

Về đầu trang

Xác thực

Phần này quay lại một đoạn trước đây của HelloDocument đã được che đi. Mặc dù bài viết này không đi sâu vào chi tiết về xác thực, nhưng nó mô tả mã xác thực trong HelloDocument đang làm cái gì.

Trong mô hình CE, việc xác thực hoàn toàn được giao cho JAAS. Điều đó có nghĩa rằng bạn không bao giờ thực sự đăng nhập vào API của CE hoặc CE. Thay vào đó, API của CE trông đợi bạn đã thực hiện một chuỗi đăng nhập JAAS trước khi bạn thực hiện bất kỳ cuộc gọi CE nào. Một lợi thế của cách tiếp cận này là API của CE không cần mã hoá vào trong nó các phương thức khác nhau mà bạn có thể sử dụng để xác thực. Với kiến trúc cắm được của JAAS, bạn có thể sử dụng các lược đồ mã định danh người dùng/mật khẩu truyền thống, các trình đọc dấu vân tay, các thiết bị xác thực cầm tay và nhiều kỹ thuật khác. Bất kể bạn xác thực thế nào, mã ứng dụng CE API của bạn vẫn giữ nguyên.

Xác thực với các phương thức trình trợ giúp API của CE

Hãy xem Liệt kê 8 và lưu ý mã liên quan đến xác thực mức cao nhất từ HelloDocument.main. Bài viết quay lại chủ đề về phương thức loginAndRun, nhưng bây giờ hãy xem mệnh đề else.

Lớp UserContext API của CE có một vài phương thức tiện lợi liên quan đến xác thực. Các phương thức này được cung cấp chỉ để làm cho nó dễ dàng thực hiện xác thực trong một hệ thống di sản bị hạn chế theo một lược đồ xác thực bằng mã định danh người dùng/mật khẩu truyền thống. Sử dụng phương thức UserContext.createSubject để tạo ra một cá thể của mộtSubject của JAAS. Đối tượng UserContext cũng có thể duy trì một ngăn xếp của các Subject của JAAS, ở đó Subject ở đỉnh ngăn xếp thực sự được sử dụng cho các chuyến đi khứ hồi của CE. Các phương thức UserContext.pushSubject vàpopSubject triển khai thực hiện một mô hình ngăn xếp tiêu chuẩn. Chính ngăn xếp được lưu trong bộ lưu trữ luồng nội bộ, có nghĩa là nó được gắn với một luồng thực hiện cụ thể. Lưu ý rằng cuộc gọi popSubject ở bên trong một khối finally để bảo đảm rằng nó được gọi dù có bất kỳ điều gì khác xảy ra. Điều đó rất quan trọng. Mặc dù nó không thành vấn đề lắm với ứng dụngHelloDocument độc lập, nhưng nó lại quan trọng trong các ứng dụng J2EE ở đó nhóm luồng thường được sử dụng cho các yêu cầu dịch vụ. Bạn không bao giờ biết được bạn sẽ chấm dứt việc dùng lại mã ở đâu, vì thế bạn nên có thói quen mã hóa nó một cách chính xác. Bạn muốn xóa sạch ngữ cảnh xác thực cho một luồng sau khi bạn đã thực hiện được cuộc gọi CE.
Liệt kê 8. Các phương thức xác thực HelloDocument 

public static void main(String[] args) throws LoginException
{
    System.out.println("CE is at " + ConfigInfo.CE_URI);
    System.out.println("ObjectStore is " + ConfigInfo.OBJECT_STORE_NAME);
    HelloDocument fd = new HelloDocument();
    if (ConfigInfo.USE_EXPLICIT_JAAS_LOGIN)
    {
        loginAndRun(fd, ConfigInfo.USERID, ConfigInfo.PASSWORD);
    }
    else
    {
        // This is the standard Subject push/pop model for the helper methods.
        Subject subject = UserContext.createSubject(fd.conn, ConfigInfo.USERID,
                                  ConfigInfo.PASSWORD, ConfigInfo.JAAS_STANZA_NAME);
        UserContext.get().pushSubject(subject);
        try
        {
            fd.run();
        }
        finally
        {
            UserContext.get().popSubject();
        }
    }
}

Xác thực JAAS chuẩn

Điều gì sẽ xảy ra nếu bạn không sử dụng UserContext.pushSubject để kích hoạt một Subject để sử dụng trong chuyến đi khứ hồi của CE? Trong trường hợp đó, đặc tính API của CE tìm kiếm một Subject của JAAS ở xung quanh . Thuật ngữ ở xung quanh ở đây có nghĩa là một Subject đã được liên kết với luồng bằng các cơ chế JAAS chuẩn. Ví dụ, trong một ứng dụng web bạn có thể tiến hành đăng nhập vào thùng chứa trang web J2EE. Trong HelloDocument, việc đăng nhập được thực hiện một cách rõ ràng như là một phần của phương thức loginAndRun.
Liệt kê 9. loginAndRun

private static final void loginAndRun(HelloDocument fd, String userid,
                                              String password) throws LoginException
{
    LoginContext lc = new LoginContext(ConfigInfo.JAAS_STANZA_NAME,
                                new HelloDocument.CallbackHandler(userid, password));
    lc.login();
    Subject subject = lc.getSubject();
    Subject.doAs(subject, fd);
}

Như bạn thấy trong Liệt kê 9, phương thức loginAndRun khá đơn giản. Nó triển khai thực hiện một chuỗi đăng nhập JAAS chuẩn, mặc dù liệt kê này không cho thấy việc thực hiện lớp bên trong HelloDocument.CallbackHandler vì nó cũng là lộ phí JAAS chuẩn. Thật không may, có một mánh khóe lừa dối trong sự đơn giản này. Việc gọi phương thức Subject.doAs ở dòng cuối cùng của Liệt kê 9 hóa ra là đặc trưng riêng cho từng máy chủ ứng dụng J2EE. Nó là một chi tiết không được giải quyết đầy đủ trong các đặc tả J2EE, do đó, mỗi nhà cung cấp đã phải triển khai thực hiện nó khi họ thấy phù hợp. Có khả năng là các đặc tả J2EE cuối cùng sẽ giải quyết điều này để cho bạn sẽ không luôn cần có logic đặc trưng của nhà cung cấp trong các cuộc gọi đăng nhập của bạn. Tất nhiên, với một máy khách J2EE đúng nghĩa thay vì một máy khách không rõ, nhiều khả năng hơn là bạn sẽ thực hiện xác thực của mình với một thùng chứa J2EE và để cho thùng chứa xử lý các chi tiết.

Kết luận

Bài viết này dẫn bạn qua toàn bộ ứng dụng HelloDocument. Bạn đã thấy cách kết nối với một ObjectStore, cách tạoObjectStore, cách tạo FolderDocument và các kiểu đối tượng khác, cách đọc và thiết lập các giá trị đặc tính và cách tải lên và tải về nội dung. Mặc dù những thứ này cùng với nhau vẫn chỉ tạo ra một ứng dụng khá đơn giản, nhưng chúng đưa vào các mô hình mã hóa có thể được dùng cho rất nhiều thứ.

Nếu bạn vừa mới bắt đầu viết mã P8, bạn có thể sử dụng HelloDocument như là một điểm khởi đầu. Tệp mã nguồn hoàn chỉnh có sẵn để tải về thông qua một liên kết đi kèm với bài viết này. Bạn có thể thử nghiệm bằng cách thay đổi nó để thử những điều khác nhau. Trong thực tế, nếu bạn có suy nghĩ về một ứng dụng nhỏ mà bạn muốn làm ra nhanh chóng, bạn sẽ không phải là người đầu tiên xây dựng nó trên một bản sao đã sửa đổi của HelloDocument.java. Hãy thử xem!

Chúc vui vẻ và theo sát với nhiều bài viết hơn trong loạt bài này!

Tải về

Mô tả Tên Kích thước Phương thức tải
Java source code for this article HelloDocument.zip 6KB HTTP
Nguồn: IBM.COM

Nhập môn ngôn ngữ lập trình Java – Phần 4: Sử dụng chuỗi, Toán tử số học và toán tử gán


Vấn đề sẽ đề cập trong những bài viết này:

Java là một ngôn ngữ lập trình hướng đối tượng (Object-oriented Programming), nhưng đôi khi nó thật sự không đối tượng hoàn toàn (một số ý kiến cho rằng như thế). Vì thế, Loạt bài viết sau này tôi sẽ trình bài là phương pháp lập trình hướng đối tượng  (OOP) bằng ngôn ngữ Java.

Chú ý: Nhắc lại là đây là bài hướng dẫn cá nhân tôi, nên đôi lúc cách sử dụng câu chữ theo cảm tính, vì thế, có những từ ngữ không hoàn toàn chính xác và khoa học nhất. Đôi khi lại không theo trình tự nhất định. Tuy nhiên, đó là điều tôi nghĩ sẽ dễ hiểu nhất có thể.

Kiến thức thu được từ các bài viết:

Hiểu rỏ cấu trúc ngôn ngữ Java theo hướng đối tượng.

Vận dụng vào ví dụ hướng dẫn đi xuyên suốt bài viết.

Và một số vấn đề để lập trình tốt ngôn ngữ Java theo OOP.

Bạn cần nhớ rằng khi học Java hay một số ngôn ngữ khác, có rất nhiều từ ngữ thông dụng làm cho người học trở nên mơ hồ, rồi từ đó rất khó để nắm bắt được ngôn ngữ này. ví dụ như: SDK, JDK,  J2SE (J2SE SDK),IDE,… Và việc bạn cần làm là cố gắng hiểu được các từ đó, thông qua cụm từ tiếng Anh viết tắt của nó. Nếu gặp một từ như thế, bảng hãy tìm cụm từ tiếng Anh của nó và hiểu nó.

Phần này giúp bạn hiểu rỏ toán tử số học và toán tử gán để qua đó vận dụng vào các câu lệnh if, for, while,… sẽ học ở phần sau. Từ những phần rời rạc này, chúng ta tập hợp lại thành một cấu trúc Java hoàn chỉnh, áp dụng vào dự án cần thực hiện. Cách sử dụng chuỗi cực kỳ quan trọng, nó có thể đi xuyên suốt dự án của bạn.

Sử dụng chuỗi (String)

Nhắc lại về  kiểu chuỗi String và kiểu ký tự char: char là kiểu dữ liệu chứa một ký tự như “c”, “b”,… String là kiểu chuỗi chứa nhiều ký tự.

Có nhiều cách khai báo kiểu chuỗi trong Java, sau đây là hai cách khai báo:

String greeting = "hello";//Hoặc có thể không gán trực tiếp chuỗi "hello" vào.
String greeting = new String("hello");

Vì chuỗi trong ngôn ngữ Java là đối tượng hạng nhất, bạn có thể dùng new để khai báo chuỗi. String có nhiều phương thức có sẵn và ta có thể làm nhiều điều hữu ích với String mà không cần phương thức.

Nối chuỗi: Ta có thể dùng dấu ” + ” để nối chuỗi với nhau, cách khác, bạn có thể dùng phương thức concat() có sẵn để nối chuỗi.

Cách dùng dấu ” + ” để nối chuỗi

System.out.println("Name: " + myAdult.getName());

Cách dùng concat() để nối chuỗi

System.out.println("Name: ".concat(myAdult.getName()));

Mã lệnh này trông hơi lạ, ta hãy duyệt qua một chút, từ trái sang phải:

  • System là đối tượng có sẵn cho phép bạn tương tác với nhiều thứ trong môi trường hệ thống (bao gồm cả một vài khả năng của chính nền tảng Java)
  • outbiến lớp của System, nghĩa là nó có thể truy cập được mà không cần phải có một cá thể của System. Nó đại diện cho màn hình.
  • println() là phương thức của out nhận tham số kiểu String, in nó ra màn hình, và tiếp ngay sau là một ký tự xuống dòng để bắt đầu một dòng mới.
  • "Name: " là một chuỗi trực kiện. Nền tảng Java coi chuỗi trực kiện này là một cá thể String, bởi vậy chúng ta có thể gọi phương thức trực tiếp trên nó.
  • concat() là một phương thức của cá thể String, nhận tham số kiểu String và nối nó với chính cá thể String mà bạn đã gọi phương thức của nó.
  • myAdult là một cá thể Adult của ta.
  • getName() là phương thức truy cập biến cá thể name.

Sử dụng chuỗi làm sao cho thuần thục và linh động vào code giúp bạn giải quyết nhiều vấn đề nhanh chóng.

Một ví dụ khác sử dụng chuỗi

Ban đầu ta khai báo biến cá thể name (protected String name) cho class Adult. Nhưng thực tế thì Adult cần có một firstname và lastname. Vậy ta sẽ định nghĩa lại, thay vì khai báo biến name ta khai báo firstName và lastName.

protected String firstName;
protected String lastName;

Và định nghĩa lại hàm getName của chúng ta như sau:

public String getName(){
      return firstName +" "+ lastName;
//Nối firstName và lastName băng toán tử +. ở giữa là khoảng chắn.
}
Hoặc
public String getName(){
      return firstName.concat(" ").concat(lastName);    
}//Dùng concat() để nối

Toán tử: Toán tử số học và toán tử gán

Các toán tử số học như: cộng (+), trừ (-), nhân (*), chia (/),…

Các toán tử gán: bằng (=), hay (==), hay khác (!=),…

Một ví dụ để hiểu về toán tử, các ví dụ trong các phần luôn mạch lạc với nhau, ví dụ sau nối ví dụ trước. Nên nhớ như vậy bạn sẽ không bỡ ngỡ.

Ban đầu ta đã khởi tạo 1 class myAdult, bây giờ cho class myAdult vừa tạo một hành vi, ở đây là hành vi đi progress.

public int progress = 0;

Như vậy, với việc dùng dấu ” = ” (toán tử gán) ta đã có biến progress = 0

Tiếp tục tạo một phương thức, đi walk() với tham số truyền vào là số bước chân (steps), trả về số bước chân của myAdult.

public int progress = 0;
public String walk(int steps){
       progress = progress + steps;
       return "Just took " + progress + "steps";
}

 

Toán tử ” + ” dùng để cộng hai biến progress với steps, gán cho progress. Như vậy, lúc này, progress sẽ bằng chính nó cộng thêm steps. Một cách khác để làm điều này

public String walk(int steps){
       progress += steps;
       return "Just took " + progress + "steps";
}

Dùng toán tử  ” += ” để cộng progress + steps. Cách này sẽ ngắn gọn hơn câu lệnh rất nhiều. Tôi cũng thích sử dụng cách này hơn.

Bảng dưới đây là danh sách và mô tả ngắn gọn của các toán tử số học và toán tử gán thường gặp nhất trong Java (lưu ý rằng một số toán tử số học là nhị phân), có hai toán hạng, và một số khác là đơn nguyên, có một toán hạng).

Toán tử Cách dùng Mô tả
+ a + b Cộng ab
+ +a Nâng a lên thành kiểu int nếu a là kiểu byte, short, hoặc char
- a - b Lấy a trừ đi b
- -a Âm a
* a * b Nhân a với b
/ a / b Chia a cho b
% a % b Trả lại phần dư của phép chia a cho b
(nói cách khác, đây là toán tử modulus)
++ a++ Tăng a thêm 1 đơn vị; tính giá trị của a trước khi tăng
++ ++a Tăng a thêm 1 đơn vị; tính giá trị của a sau khi tăng
-- a-- Giảm a đi 1 đơn vị; tính giá trị của a trước khi tăng
-- --a Giảm a đi 1 đơn vị; tính giá trị của a sau khi tăng
+= a += b Giống như a = a + b
-= a -= b Giống như a = a - b
*= a *= b Giống như a = a * b
%= a %= b Giống như a = a % b

Chúng ta cũng đã biết một số thứ khác được gọi là toán tử trong ngôn ngữ Java. Ví dụ, dấu chấm . phân định tên của các gói và lời gọi phương thức; cặp ngoặc đơn ( params ) để phân định danh sách các tham số phân cách bằng dấu phẩy của một phương thức; và new, khi theo sau nó là tên của hàm tạo, để khởi tạo một cá thể.

Phần tiếp theo: Nhập môn ngôn ngữ lập trình Java – Phần 5: Toán tử quan hệ và toán tử điều kiện, Câu lệnh if, switch

Nhập môn ngôn ngữ lập trình Java – Phần 3: Biến, phương thức


Vấn đề sẽ đề cập trong những bài viết này:

Java là một ngôn ngữ lập trình hướng đối tượng (Object-oriented Programming), nhưng đôi khi nó thật sự không đối tượng hoàn toàn (một số ý kiến cho rằng như thế). Vì thế, Loạt bài viết sau này tôi sẽ trình bài là phương pháp lập trình hướng đối tượng  (OOP) bằng ngôn ngữ Java.

Chú ý: Nhắc lại là đây là bài hướng dẫn cá nhân tôi, nên đôi lúc cách sử dụng câu chữ theo cảm tính, vì thế, có những từ ngữ không hoàn toàn chính xác và khoa học nhất. Đôi khi lại không theo trình tự nhất định. Tuy nhiên, đó là điều tôi nghĩ sẽ dễ hiểu nhất có thể.

Kiến thức thu được từ các bài viết:

Hiểu rỏ cấu trúc ngôn ngữ Java theo hướng đối tượng.

Vận dụng vào ví dụ hướng dẫn đi xuyên suốt bài viết.

Và một số vấn đề để lập trình tốt ngôn ngữ Java theo OOP.

Bạn cần nhớ rằng khi học Java hay một số ngôn ngữ khác, có rất nhiều từ ngữ thông dụng làm cho người học trở nên mơ hồ, rồi từ đó rất khó để nắm bắt được ngôn ngữ này. ví dụ như: SDK, JDK,  J2SE (J2SE SDK),IDE,… Và việc bạn cần làm là cố gắng hiểu được các từ đó, thông qua cụm từ tiếng Anh viết tắt của nó. Nếu gặp một từ như thế, bảng hãy tìm cụm từ tiếng Anh của nó và hiểu nó.

Phần này sẽ trình bày về biến và phương thức và phương thức main() trong Java.

Biến

Khai báo: (hai cách: Khai báo không gán dữ liệu và khai báo biến gán dữ liệu).

accessSpecifier dataType variableName1,  [variableName2],  [variableName3],...;
Khai báo biến không gán dữ liệu vào

Hoặc:

accessSpecifier dataType variableName1 = data; Khai báo biến gán dữ liệu vào.

Trong đó: accessSpecifier: protected, public là dạng có thể truy cập của biến.

dataType: Kiểu dữ liệu, như int, float, char,…

variableName1, variableName2, variableName3,… là tên biến khai báo, ở đây có thể khai báo một hay nhiều biến  cùng lúc, mỗi biến cách nhau dấu phẩy. Cuối khai báo có dấu chấm phẩy ” ; “. Dấu chấm phẩy ” ; ” sử dụng khi kết thúc dòng lệnh.

Chú ý: Dòng lệnh kết thúc khi có dấu ” ; “, khác một dòng trong văn bản. Nó có thể có một hoặc nhiều dòng văn bản.

Biến có biến thông thường, khai báo cho một hàm hoặc biến chung (ở đây là biến lớp).

Quy ước biến lớp: Viết bằng chữ IN HOA, mỗi từ trong một biến cách bằng gạch dưới ” _ “, kèm phía trước là từ khóa static.

accessSpecifier static [final] dataType variableName1, variableName2, variableName3,…;

ví dụ: protected static final int ONE_DOLLAR_BILL = 1;

final là có nghĩa không có từ nào thay thế biến ONE_DOLLAR_BILL (nó trở thành hằng số).

ví dụ:

package intro.core;

public class Adult {
	protected int age;
	protected String name;
	protected String race;
	protected String gender;
}
Có 4 biến được tạo ra: age kiểu int, các biến còn lại kiểu String.
String: là một kiểu chuỗi ký tự thuộc lớp Java.lang.
Phân biệt với char: kiểu ký tự chứa một ký tự đơn lẻ trong unicode. như "a", "b"

Phương thức

Nắm được phương thức có sẵn, tạo phương thức mới, vận dụng trong dự án. Ở đây sẽ không đề cập nhiều đến phương thức có sẵn. Bạn phải tự tìm hiểu. Hay hay dở của lập trình viên nằm ở đây.

Theo tôi có hai điều tối quan trọng làm nên một lập trình viên giỏi: Thứ nhất là tư duy lập trình. Thứ hai là biết vận dụng các phương thức có sẵn hay tạo ra một phương thức mới vận dụng vào dự án của bạn. Kết hợp hai điều này một cách linh động làm sao cho bạn điều khiển ngôn ngữ lập trình vào mục đích mình muốn chứ không để ngôn ngữ lập trình điều khiển bạn theo cách có chạy. Nếu vế thứ hai xảy ra, tức là bạn chưa phải là một lập trình viên giỏi.Bạn buộc phải thay đổi để làm cho dự án của bạn chạy được, làm cho ngôn ngữ lập trình hiểu bạn, mặc dù điều đó là không mong muốn.

Khai báo phương thức:

Cách 1: Phương thức không có tham số truyền vào
Cách 2: Phương thức có tham số truyền vào
Phương thức có trả về giá trị và không trả về giá trị 
(dùng void hay kiểu dữ liệu trả về)
accessSpecifier dataType | void  methodName([dataType1 variableName1], 
[dataType1 variableName1],...){
        // Bên trong phương thức
}
-accessSpecifier là hình thức truy cập phương thức, public, protected.
-dataType | void. Nếu là có trả về giá trị thì dùng dataType (kiểu trả về), Nếu
không thì sử dụng void.
-methodName là tên phương thức khởi tạo
-dataType1, dataType2 là kiểu dữ kiệu của variableName1 (biến 1), variableName2 
(tham số 2) hay nhiều hơn. Có thể truyền vào một hay nhiều tham số hoặc không 
truyền tham số nào vào cả.

ví dụ:

package intro.core;
public class Adult {
	protected int age;
	protected String name;
	protected String race;
	protected String gender;

        public int getAge(){
              return age;
        }
        public void setAge(int anAge){
              age = anAge;
        }
}
Phương thức getAge() để trả về tuổi (kiểu int) của class Adult
Phương thức setAge() dùng để gán cho tuổi Adult vào và không cần trả về kết quả.
Sẽ hiểu rỏ hơn khi có phương thức main().

Phương thức main()

Nên có phương thức main() và duy nhất một main() cho dự án.

Phương thức main() là một phương thức nằm trong JRE (Java Runtime Environment), đặc biệt có thể đưa vào bất cứ một class nào nhưng không phải mọi lớp đều cần main(). Chỉ duy nhất một phương thức main() cho dự án.

Khai báo phương thức main():

public static void main(String[] args){
              //Bên trong main
        }
Tại sao main() lại có static, vì đó là phương thức lớp, vấn đề này sẽ bàn đến sau.

ví dụ: Tạo các phương thức getAge(), setAge(), getName(), setName(), getRace(), setRace(), getGender(), setGender() và xuất ra màn hình các thông số được gán ra nhờ vào main().

package intro.core;
public class Adult {
	protected int age;
	protected String name;
	protected String race;
	protected String gender;
        public int getAge(){
             return age;
        }
        public void setAge(int anAge){
              age = anAge;
        }
        public String getName(){
              return name;
        }
        public void setName(String aName){
              name = aName;
        }
        public String getRace(){
              return race;
        }
        public void setRace(String aRace){
              race = aRace;
        }
        public String getGender(){
              return gender;
        }
        public void setGender(String aGender){
              gender = aGender;
        }
        public static void main(String[] args){
              Adult myAdult = new Adult();
              myAdult.setAge(18);
              myAdult.setName("TanDoan");
              myAdult.setRace("VietNam");
              myAdult.setGender("Male");
       
              System.out.println("Age: " +myAdult.getAge());
              System.out.println("Name: " +myAdult.getName());
              System.out.println("Race: " +myAdult.getRace());
              System.out.println("Gender: " + myAdult.getGender());
        }
}

Như vậy là hàm main() như là chương trình tổng hợp lại tất cả những thứ rời rạc: biến, phương thức, class… của bạn. Nó là những gì chúng ta mong muốn.

 

Phần tiếp theo: Nhập môn ngôn ngữ lập trình Java – Phần 4: Các toán tử số học và toán tử gán, sử dụng chuỗi

Nhập môn ngôn ngữ lập trình Java – Phần 2: Từ khóa, kiểu dữ liệu nguyên thủy, class, chú thích


Vấn đề sẽ đề cập trong những bài viết này:

Java là một ngôn ngữ lập trình hướng đối tượng (Object-oriented Programming), nhưng đôi khi nó thật sự không đối tượng hoàn toàn (một số ý kiến cho rằng như thế). Vì thế, Loạt bài viết sau này tôi sẽ trình bài là phương pháp lập trình hướng đối tượng  (OOP) bằng ngôn ngữ Java.

Chú ý: Nhắc lại là đây là bài hướng dẫn cá nhân tôi, nên đôi lúc cách sử dụng câu chữ theo cảm tính, vì thế, có những từ ngữ không hoàn toàn chính xác và khoa học nhất. Đôi khi lại không theo trình tự nhất định. Tuy nhiên, đó là điều tôi nghĩ sẽ dễ hiểu nhất có thể.

Kiến thức thu được từ các bài viết:

Hiểu rỏ cấu trúc ngôn ngữ Java theo hướng đối tượng.

Vận dụng vào ví dụ hướng dẫn đi xuyên suốt bài viết.

Và một số vấn đề để lập trình tốt ngôn ngữ Java theo OOP.

Bạn cần nhớ rằng khi học Java hay một số ngôn ngữ khác, có rất nhiều từ ngữ thông dụng làm cho người học trở nên mơ hồ, rồi từ đó rất khó để nắm bắt được ngôn ngữ này. ví dụ như: SDK, JDK,  J2SE (J2SE SDK),IDE,… Và việc bạn cần làm là cố gắng hiểu được các từ đó, thông qua cụm từ tiếng Anh viết tắt của nó. Nếu gặp một từ như thế, bảng hãytìm cụm từ tiếng Anh của nó và hiểu nó.

Phần này trình bày: Từ khóa, kiểu dữ liệu nguyên thủy, class, chú thích

Cấu trúc Java theo hướng đối tượng

Một ngôn ngữ lập trình bao gồm các thành phần cơ bản: biến, phương thức (hàm – có thể sử dụng từ hàm là không hoàn toàn chính xác) tự định nghĩa và phương thức có sẵn, từ khóa,  ghi chú, các kiểu dữ liệu,…

Java hướng đối tượng cần nắm: kiểu dữ liệu, biến, phương thức, từ khóa, ghi chú, toán tử và một hàm main() để chạy chương trình java (còn một số vấn đề nữa). Ở đây khi đề cập tới vấn đề nào tức là hiểu bao gồm cả khai báo như thế nào, sử dụng (gọi) như thế nào và tất cả vấn đề liên quan. ví dụ: đề cập đến biến: tức là khai báo biến, sử dụng biến, thao tác nó.

Java phân biệt chữ thường và chữ hoa (như C, C++,…).

Từ khóa

Cần lưu ý từ khóa của Java để biết cách sử dụng chúng. Tuy nhiên, chúng ta không cần nhất thiết phải nhớ chúng, Eclipse sẽ tô đậm khi chúng xuất hiện trong code.

bstract boolean break byte
case catch char class
const continue char class
default do double else
extends false final finally
float for goto if
implements import int instanceof
interface long int native
new null package private
protected public package private
static strictfp super switch
synchronized short super this
throw throws true try
transient return void volatile
while assert true false
null

Kiểu dữ liệu nguyên thủy

 Có 9 kiểu dữ liệu nguyên thủy thường thấy. Gọi là kiểu dữ liệu nguyên thủy là để phân biệt với loại kiểu dữ liệu khác, sẽ đề cập đến phần sau.

Type Size Default value Example
boolean N/A false true
byte 8 bits 0 2
char 16 bits 'u/0000' 'a'
short 16 bits 0 12
int 32 bits 0 123
long 64 bits 0 9999999
float 32 bits with a decimal point 0.0 123.45
double 64 bits with a decimal point 0.0 999999999.99999999

Lớp (Class)

Học lập trình hướng đối tượng thì phải nắm chắc về class. Biết khai báo chúng và sử dụng chúng thuần thục. Khi sử dụng class thường xuyên dùng dấu ” . ” (có thể gọi dấu ” . ” là một toán tử. Chúng ta chỉ đề cập đến class tự định nghĩa, vì class có sẵn thì phải tìm hiểu nó. Class tự định nghĩa khai báo và sử dụng như thế nào mới là vấn đề cần bàn tới.

vd: myHouse.MERCEDES_CAR: Ở đây class myHouse truy vấn đến biến MERCEDES_CAR nhờ toán tử ” . “.  Biến MERCEDES_CAR là một biến lớp (biến chung).

Bài này lấy ví dụ dựa theo bài viết Nhập môn lập trình Java của Roy Miller, IBM developerworks.

Như đã trình bày, Trước khi khai báo class chúng ta tạo ra một package trước để gói các class của chúng ta. Sau khi tạo package và tạo class (Chữ C+ màu xanh) thì mặc nhiên Eclipse tự động tạo dòng package intro.core (với intro là tên package).

Khai báo class:

accessSpecifier class className {
      //Tham số và phương thức truyền vào bên trong
}
Trong đó: accessSpecifier: protected, public là dạng có thể truy cập của class.

ví dụ:

package intro.core;//package được chèn vào đầu tiên trong file class

public class Adult {
}

Chú thích

Như các ngôn ngữ lập trình khác, Java cũng có quy tắc để cho người lập trình thêm vào những dòng chú thích để làm rõ nghĩa của code khó hiểu.

Chú thích một dòng: dùng dấu //

Chú thích nhiều dòng:  Dùng /* khi bắt đâu và kết thúc với */

vd:  /* Chú thích ở đây */

Chú thích javadoc: Trình biên dịch bỏ qua không biên dịch, nhưng javadoc sẽ sử dụng chúng. Bắt đầu với /** và kết thúc */

Javadoc: đi kèm với bản Java SDK, sinh ra tài liệu HTML.

Tóm tắt:

Từ phần 2 trở về sau chúng ta đi vào cấu trúc ngôn ngữ lập trình Java theo hướng đối tượng (OOP). Tức là nắm nội dung thứ nhất: Hiểu rỏ cấu trúc ngôn ngữ Java theo hướng đối tượng. Phần 2 trình bày nội dung: từ khóa, kiểu dữ liệu nguyên thủy, class (quan trọng), chú thích trong Java.

Phần tiếp theo: Nhập môn ngôn ngữ lập trình Java – Phần 3:  Biến, phương thức

Nhập môn ngôn ngữ lập trình Java phần 1: Nền tảng (Java SDK) và Công cụ (Eclipse) lập trình Java


Vấn đề sẽ đề cập trong những bài viết này:

Java là một ngôn ngữ lập trình hướng đối tượng (Object-oriented Programming), nhưng đôi khi nó thật sự không đối tượng hoàn toàn (một số ý kiến cho rằng như thế). Vì thế, Loạt bài viết sau này tôi sẽ trình bài là phương pháp lập trình hướng đối tượng  (OOP) bằng ngôn ngữ Java.

Chú ý: Nhắc lại là đây là bài hướng dẫn cá nhân tôi, nên đôi lúc cách sử dụng câu chữ theo cảm tính, vì thế, có những từ ngữ không hoàn toàn chính xác và khoa học nhất. Đôi khi lại không theo trình tự nhất định. Tuy nhiên, đó là điều tôi nghĩ sẽ dễ hiểu nhất có thể.

Kiến thức thu được từ các bài viết:

Hiểu rỏ cấu trúc ngôn ngữ Java theo hướng đối tượng.

Vận dụng vào ví dụ hướng dẫn đi xuyên suốt bài viết.

Và một số vấn đề để lập trình tốt ngôn ngữ Java theo OOP.

Bạn cần nhớ rằng khi học Java hay một số ngôn ngữ khác, có rất nhiều từ ngữ thông dụng làm cho người học trở nên mơ hồ, rồi từ đó rất khó để nắm bắt được ngôn ngữ này. ví dụ như: SDK, JDK,  J2SE (J2SE SDK),IDE,… Và việc bạn cần làm là cố gắng hiểu được các từ đó, thông qua cụm từ tiếng Anh viết tắt của nó. Nếu gặp một từ như thế, bảng hãytìm cụm từ tiếng Anh của nó và hiểu nó.

Phần này sẽ trình bày hướng dẫn cài đặt nền tảng Java SDK và công cụ lập trình Eclipse

Công cụ và nền tảng

Java giúp lập trình viên có thể viết chương trình chạy trong bất cứ nền tảng nào, ý tưởng gói gọn trong cụm từ “Viết một lần, chạy bất cứ đâu” (Write once, run anywhere).

  • Cài đặt Java SDK (Software Development Kit):

    Bộ ngôn ngữ phát triển phần mềm Java. Java SDK hay JDK (Java Development Kit) theo cách hiểu của tôi là như nhau. Đó là Bộ phát triển ngôn ngữ dành cho Java. Nó cung cấp máy ảo và API để hỗ trợ lập trình Java.
    Hiểu nôm na, đó là nền tảng để bạn lập trình, và cần thêm một công cụ nữa là có thể code.
    Download Java SDK từ trang chủ công nghệ Java.
    Chọn Java SE -> Chọn Java SE download ->Chọn phiên bản hệ điều hành để download về. Cài đặt lên trên máy tính, nên chọn đường dẫn có tên thích hợp nằm trên thư mục gốc của ổ cứng. vd: C:\Java\jdk1.8.0_91

  • Cài đặt Eclipse

    (Eclipse là IDE (Integrated Development Environment – môi trường phát triển tích hợp) để phát triển ứng dụng (ở đây là ngôn ngữ Java).
    Download từ trang chủ Eclipse. Lựa chọn phiên bản phù hợp hệ điều hành, download về và cài đặt. Nên chọn đường dẫn ở thư mục gốc của máy tính. Việc cần làm sau khi cài đặt là thiết lập Eclipse IDE.Tóm lại: Cần Java SDK + IDE (Sử dụng Eclipse) để có thể phát triển ứng dụng Java.

Làm quen với phần mềm Eclipse

Việc cần làm sau khi có tất cả những thứ để có thể lập trình là nắm được cách sử dụng Eclipse như thế nào.

Sử dụng Eclipse như thế nào cho lập trình (nên làm):

Bước 1: Bạn nên tạo một dự án(Project) để lập trình (không chỉ riêng Java, các ngôn ngữ khác cũng thế). File ->new Java Project (hoặc Project), đặt tên cho project cần tạo.

Bước 2: Đã có Project rồi, tiếp theo nên tạo một Package (gói). New-> Package. Mục đích là làm cho code sau này mạch lạc hơn khi có nhiều gói (package) trong một dự án (project).

Bước 3: Tạo một file class (đuôi .java) để có thể viết code.Bạn có thể tạo 1 file class từnew->class. Tuy nhiên, như thế thì file này sẽ nằm ngoài package của chúng ta, tốt nhất nên tạo file class từ biểu tượng C+ màu xanh  ctrên thanh công cụ dự án.

cc

Tóm tắt: Cài đặt nền tảng (Java SDK) và công cụ lập trình (Eclipse), tạo ra được dự án Java (Java project ), các gói (package) và các lớp (class) từ công cụ Eclipse).

Phần tiếp theo: Nhập môn ngôn ngữ lập trình Java – Phần 2: Từ khóa, kiểu dữ liệu nguyên thủy, class, chú thích

 

Một số vấn đề về lập trình


Sau khoảng thời gian lập trình và nghiên cứu về ngôn ngữ lập trình, tôi nhận thấy rằng các tài liệu lập trình (Tiếng Việt) luôn có một sự lằng nhằng nhất định nào đó. Nó thường khiến cho ngôn ngữ lập trình đã mơ hồ càng làm thêm mơ hồ thêm, càng làm cho người mới học trở nên quá trừu tượng một vấn đề. Việc này làm cho người lập trình không xác định được hướng đi đúng đắn để học và làm.

Riêng tôi, học ngôn ngứ lập trình cũng giống như học một ngôn ngữ thông thường, luôn cần hiểu rỏ

  1. Cấu trúc của một ngôn ngữ lập trình.
  2. Rồi từ đó đi vào chuyên sâu vào ngôn ngữ lập trình (nnlt) nào mình cần học.
  3. Thuần thục và vận dụng vào bài toán cần giải quyết.

Sau đây tôi sẽ bắt đầu update những bài hướng dẫn (theo cách hiểu của bản thân) để nói về ngôn ngữ lập trình hướng đối tượng Java. (Sử dụng công cụ IDE Eclipse)