Chọn kiểu for-loop nào và khi nào trong Java?
Trong Java có ba phương pháp (hình thức) duyệt với vòng lặp (loop) đó là for-loops (loop thông thường), for-each loops, và Java 8 lambda for-each loops. Java 8 giới thiệu một dạng khác của vòng lặp for. Có phải mỗi khi có phương pháp mới ra đời thì nó tốt hơn phương pháp cũ? Trường hợp này thì câu ...
Trong Java có ba phương pháp (hình thức) duyệt với vòng lặp (loop) đó là for-loops (loop thông thường), for-each loops, và Java 8 lambda for-each loops. Java 8 giới thiệu một dạng khác của vòng lặp for. Có phải mỗi khi có phương pháp mới ra đời thì nó tốt hơn phương pháp cũ? Trường hợp này thì câu trả lời là không phải vậy. Mỗi phương pháp lặp có cái hay riêng của nó, có nghĩa là bạn phải dành chút thời gian suy nghĩ xem là nên dùng phương pháp nào. Vậy thì bạn chọn sử dụng kiểu nào, và khi nào thì chọn nó?
Normal For loop
Giờ đây nhìn vòng lặp này ta thấy nó thật xấu xí và muốn tránh xa nó. Dù sao xin bạn nán lại một chút để tôi nói lại vòng lặp 'cổ điển' này, về những gì mà nó làm được. Vòng lặp này sử dụng một bộ đếm để duyệt qua các phần tử của tập hợp (list, array...). Cách giải thích đơn giản nhất có lẽ là thông qua ví dụ.
List<Integer> list = Arrays.asList(1,2,3,4,5,6); for(int index=0; index<list.size(); index++) { System.out.println("I have read the number: " + list.get(index)); } int[] array = new int[]{ 1,2,3,4,5,6}; for(int index=0; index<array.length; index++) { System.out.println("I have read the number: " + array[index]); }
Ở ví dụ trên cho thấy cách duyệt từng phần tử của list và array là tăng dần giá trị đếm index lên 1 và truy xuất giá trị của các phần tử thông qua vị trí 'index' của chúng trong danh sách `list.get(index), array[index]'. Vậy lợi ích của việc sử dụng vòng lặp 'cổ điển' này là gì? Đó là nó cho phép bạn có nhiều xử lý hơn với việc truy xuất các phần tử danh sách. Nếu bạn muốn bạn có thể truy xuất phần tử thứ index - 1 một cách dễ dàng, điều mà bạn không thể làm được với hai phương pháp lặp kia. Hãy nhớ kiểm soát trường hợp index = 0, nếu không bạn có thể sẽ nhận được exception IndexOutOfBoundsException. Việc kiểm soát này cũng có mặt xấu của nó, khi mà bạn phải xử lý các phần tử một cách thủ công, nó sẽ khiến code trở thành một đống lọn xộn. Những vấn đề này bạn sẽ không gặp phải khi dùng 2 phương pháp kia.
For-Each Loop
Tên gọi của vòng lặp này đã mô tả tương đối tốt chức năng của nó. Với mỗi phần tử của tập hợp, thực hiện tác vụ nào đó với nó. Không cần biến đếm tăng dần để duyệt danh sách, vì nó đã được thực hiện ngầm. Chỉ cần định nghĩa tên và kiểu dữ liệu cho đối tượng bạn muốn lấy ra, vậy là mọi thứ đã sẵn sàng.
List<Integer> list = Arrays.asList(1,2,3,4,5,6); for(int number : list) { System.out.println("I have read the number:" + number); } int[] array = new int[]{ 1,2,3,4,5,6}; for(int number : array) { System.out.println("I have read the number: " + number); } Set<Integer> set = new HashSet<>(Arrays.asList(1,2,3,4,5,6)); for(int number : set) { System.out.println("I have read the number: " + number); }
Đoạn code này trông thật đơn giản và tốt hơn nhiều đoạn code xấu xí bên trên. Dù sao thì, vòng lặp sẽ duyệt qua tất cả các phần tử, qua mỗi vòng lặp, nó cung cấp giá trị của từng phần tử tập hợp. Thứ tự xuất hiện của các phần tử này theo đúng thứ tự của chúng trong tập hợp. Một lợi thế khác của vòng lặp For-each là nó có thể duyệt qua các phần tử của Set, mặc dù tự nó không có hàm get().
Java 8 For-Each Loop
Đây là loại vòng lặp mới được thêm vào khi release Java 8. Nó có mọi tính năng của vòng lặp Normal For-each, nhưng sử dụng biểu thức lambda để thể hiện các xử lý với từng phần tử mà nó duyệt qua, trừ việc nó không sử dụng được với Array. Hãy xem ví dụ dưới đây:
List<Integer> list = Arrays.asList(1,2,3,4,5,6); list.forEach(number -> System.out.println("I have read the number:" + number));
Kiểu vòng lặp này có thể sử dụng thay vòng lặp For-each thông thường, về mặt tính năng, chúng hoàn toàn giống nhau, chỉ khác ở cú pháp. Dạng viết này ngắn gọn hơn, cho phép thể hiện vòng lặp trên 1 dòng nếu phép xử lý phần tử đủ ngắn. Khi cần xử lý nhiều hơn với mỗi phần tử, lựa chọn vòng lặp này hay Normal for-each là như nhau, bởi vì đã không còn lợi thế về rút ngắn code.
Vậy thì, bạn nên sử dụng vòng lặp nào? Nếu bạn cần kiểm soát toàn bộ các phần tử đọc ra, hoặc thêm/bớt phần tử trong danh sách, thì Normal For-loop là lựa chọn tốt. Còn nếu bạn đơn giản cần thực hiện vài câu lệnh với phần tử mà không cần thêm hay bớt, thì cả Normal For-each và Java 8 For-each đều đáp ứng tốt; quyết định sử dụng loại nào là tùy vào bạn. Cá nhân tôi, khi chỉ thực hiện một vài câu lệnh ngắn, tôi sẽ dùng Java 8 For-each, nhưng khi cần thực hiện nhiều câu lệnh trong vòng lặp, thì Normal For-each sẽ thích hợp hơn.