Nên chọn kiểu viết code nào trong Java?
Số là bọn em đang làm bài tập. Đề bài cụ thể là: “Viết chương trình nhận vào một chuỗi bất kì và in ra chuỗi đó sau khi đã được viết hoa chữ cái đầu tiên mỗi từ. Nếu từ bắt đầu bằng kí tự đặc biệt thì từ đó không phải viết hoa kí tự nào. Không được dùng phương thức toUpperCase() có sẵn, hãy viết (các) phương thức chính để giải quyết vấn đề trên.”
Em viết như thế này:
public static boolean isInRange(char chr) {
return ((int) chr >= 'a' && (int) chr <= 'z');
}
public static char uppercaseAChar(char chr) {
if (isInRange(chr))
return (char) (chr - 32);
return chr;
}
public static String uppercaseEachWord(String str) {
if (str == null || str.length() == 0)
return str;
StringBuilder res = new StringBuilder();
res.append(uppercaseAChar(str.charAt(0)));
for (int i = 1; i < str.length(); i++) {
if (str.charAt(i - 1) == ' ') {
res.append(uppercaseAChar(str.charAt(i)));
} else
res.append(str.charAt(i));
}
return res.toString();
}
Còn bạn em viết như thế này:
private static String inHoaCacChuDauTungTu(String s2) {
char[] arr = s2.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (i == 0 && (int) arr[i] >= 97 && (int) arr[i] <= 122) {
arr[i] = (char) ((int) arr[i] - 32);
}
if ((int) arr[i] == 32) {
if (i < arr.length - 1 && (int) arr[i + 1] >= 97 && (int) arr[i + 1] <= 122)
arr[i + 1] = (char) ((int) arr[i + 1] - 32);
if (i == arr.length - 1)
break;
}
}
String s = new String(arr);
return s;
}
Thật sự thì khi test code của nó chạy nhanh hơn của em. Nhưng em thấy code của nó nhằng nhèo sao ấy, khó đọc quá. Theo các ACE, nên chọn cách viết code nào ạ? Có phải em chia ra thành các phương thức riêng lẻ nên nó bị chậm không? Mong các ACE giải đáp giúp. Em cảm ơn nhiều ạ!!!
Tùy , nếu chương trình chỉ chạy trên client thì nên để kiểu của bạn vì dễ maintain , nhưng nếu code một ứng dụng web có 1000 người dùng chẳng hạn , bạn nên để ý đến tốc độ và code kiểu thứ 2 , code phức tạp một chút , nhưng cố gắng comment thật dễ hiểu là ok . code đẹp nhiều khi không phải là dễ đọc đâu , code đẹp là chạy hiệu quả sau đó thì đơn giản nhất có thể .
Sao thầy em dạy StringBuilder nhanh hơn StringBuffer ạ?
em gà nhưng theo em biết thì đệ quy bao giờ cũng chạy chậm hơn vòng lặp
Code mình đâu có dùng đê quy đâu bạn.
vậy chắc gọi hàm thì chậm hơn
StringBuffer is synchronized, StringBuilder is not.
Không phải sync nên nó nhanh hơn đúng không ạ?
StringBuffer thuộc loại synchronized , giúp xử lý đa luồng , có bộ đệm tránh xung đột . nếu không làm về đa luồng thì đừng có dùng buffer , không lại nặng code ra .
Code của bạn , khi chương trình complie đường đi sẽ loằng ngằng hơn khối có for vì thế chậm hơn là đúng rồi .
Mình thấy cách viết code của bạn dễ đọc hơn + có lợi về lâu dài. Giả sử sau này làm việc theo nhóm, hoặc 1 năm sau bạn quay trở lại đọc 2 đoạn code bên dưới, bạn nghĩ đoạn nào đọc dễ hiểu hơn? Dự án thực tế thường kéo dài nhiều năm (1-2 năm dev, 5+ năm bảo trì), nên 1 đoạn code qua tay nhiều người là chuyện bình thường.
Bạn nói đoạn code thứ 2 chạy nhanh hơn, nhưng nhanh hơn có đáng kể không? Theo mình thấy thì cả 2 đoạn này đều là O(n) hết, nhanh hơn không đáng kể thì nên bỏ qua (premature optimization is the root of all evil). Mình nghĩ nguyên nhân code của bạn chậm hơn là do thao tác trực tiếp trên String chứ không phải char[]. Bạn thử thay char[] arr = str.toCharArray(); xem tốc độ có cải thiện không? Bạn có thể dùng VisualVM để benchmark code, thấy chỗ nào chậm thì optimize chỗ đó
Về phần StringBuffer & StringBuilder, trong trường hợp này mình nghĩ nên dùng StringBuilder, tại vì theo như code ở trên, dùng cái nào thì khi chạy cũng chỉ có 1 thread.
Về cách code sao cho đẹp, dễ đọc. Bạn có thể đọc Clean Code, sách này viết ví dụ bằng Java nhưng có thể ứng dụng qua các ngôn ngữ khác.
Java Virtual Machine, lúc compile còn có một bước optimize bytecode nữa, nên chưa hẳn gọi nhiều method sẽ lâu hơn. Mình không rõ vụ optimize lắm nên cũng không dám chém
cách 1 dễ đọc hơn.
cách 2 có 2 lần viết lại
arr[i] = (char) ((int) arr[i] - 32);
arr[i + 1] = (char) ((int) arr[i + 1] - 32);
và
(int) arr[i] >= 97 && (int) arr[i] <= 122
(int) arr[i + 1] >= 97 && (int) arr[i + 1] <= 122
nên tách thành 2 phương thức riêng chứ đừng copy paste thế này. Nếu copy paste thì khi debug phải tìm tất cả những chỗ đã copy paste mà sửa, rất vất vả. Nếu tách thành 1 phương thức riêng thì chỉ cần sửa phương thức này là xong.
ngoài ra
(int) arr[i] == 32
có lẽ nghiện C quá… mà C cũng ko bệnh thế này.
arr[i] == ' '
dễ đọc hơn sao lại cast thành int rồi so sánh với 32 làm gì. Tương tự với >= 97 và <= 122. Khỏi cần cast về int. Viếtarr[i] >= 'a' && arr[i] <= 'z'
và gọn vừa dễ đọc.ngoài ra nữa:
if (i == arr.length - 1) break;
ko cần thiết.
ngoài ra thì
viết luôn là
return new String(arr);
luôn cho gọn.Viết theo cách của bạn là được rồi. Đừng cho một cái hàm ôm đồm quá nhiều thứ, sau này phải chỉnh sửa thì rất khó khăn…
Đồng ý với cách viết nên tách hàm ra cho dễ đọc hơn. Hơn thế nữa, để cuộc sống dễ dàng hơn thì tôi bổ sung ý kiến chúng ta nên tránh harded code.
isInRange(char chr)
có thể thay bằngjava.lang.Character.isLetter(char ch)
sẽ bổ rẻ hơn.32
có thể thay bằng một constant, ví dụ:private static final int OFFSET = 'a' - 'A';
str.charAt(i - 1) == ' '
có thể thay bằngCharacter.isWhitespace(str.charAt(i - 1))
Bạn nghĩ sao?
Nếu nói là nên chọn kiểu nào thì hãy chọn kiểu này
=))))
Cảm ơn anh nhiều ạ! Code style chất quá. Em nhất định sẽ áp dụng.
Xin anh vui lòng giải thích thêm
thêm điều kiện là nếu kí tự đã in hoa rồi thì không làm gì cả.
Character.isUpperCase(characters[i])
Pattern- Regular Expressions
Cảm ơn anh, em lại được học thêm 1 thứ bổ ích.
Mình thì theo quan điểm không có đúng sai trong lập trình, nên cân bằng giữa tính hiệu quả và tính dễ đọc. Cách 1 của bạn dễ đọc, dễ maintain, tuy phải đánh đổi việc gọi function chéo nhau (tất nhiên sẽ chậm hơn) so với Cách 2 chạy nhanh hơn, nhưng sau maintain khó khăn. Nếu benchmark thì mình thấy cách 1 cũng không chậm hơn đáng kể, nhất là với các máy tính hiện nay, tốc độ CPU rất lớn, RAM khủng, … thì chắc vài micro micro… second ^^
Vấn đề viết code thế nào cho hiệu quả cũng là 1 chủ đề khá thú vị (người Nhật họ gọi là Coding Dojo, nghĩa là một đấu trường coding, ở đó họ tìm cách đạt 1 mục đích với nhiều cách thức khác nhau để tìm ra đường kiếm đẹp nhất và hiệu quả nhất. Riêng dân Nhật, cái gì cũng đẩy lên thành 1 thứ đạo, ví dụ riêng chuyện uống trà -> trà đạo)
Ví dụ bài toán FlipFlop khi chia hết cho 3, 5 và cả 3 và 5 (chia hết cho 15)
Cách 1
Cách 2:
Cách 3:
Cách 4:
Cách 5:
Cách 6:
Bạn thấy cách nào hiệu quả và tại sao?