2012-03-13 48 views
15

tôi có mã này:Một bộ đếm cuối cùng trong vòng lặp for?

List<Runnable> r = new ArrayList<>(); 
    for(int i = 0; i < 10; i++) { 
     r.add(new Runnable() { 

      @Override 
      public void run() { 
       System.out.println(i); 
      } 
     }); 
    } 

Nó rõ ràng là không biên dịch vì i sẽ cần phải được chính thức được sử dụng trong lớp nặc danh. Nhưng tôi không thể làm cho nó cuối cùng bởi vì nó không phải là. Bạn sẽ làm gì? Một giải pháp là để lặp lại nó nhưng tôi nghĩ rằng có thể có một cách tốt hơn:

List<Runnable> r = new ArrayList<>(); 
    for(int i = 0; i < 10; i++) { 
     final int i_final = i; 
     r.add(new Runnable() { 

      @Override 
      public void run() { 
       System.out.println(i_final); 
      } 
     }); 
    } 

EDIT chỉ để làm cho nó rõ ràng, tôi đã sử dụng một Runnable đây vì lợi ích của ví dụ, câu hỏi thực sự là khoảng ẩn danh các lớp học, có thể là bất cứ điều gì khác.

+4

Tôi không nghĩ có cách nào tốt hơn ... – thumbmunkeys

+0

Vì truy cập vòng lặp vì lý do rõ ràng không bao giờ có thể được thực hiện cuối cùng, tôi nghĩ cách tiếp cận sao chép giá trị vào biến cuối cùng là cách duy nhất để đi (nhưng tôi quan tâm đến các lựa chọn thay thế có thể bị thiếu). – ftr

Trả lời

16

Tôi nghĩ giải pháp của bạn là cách đơn giản nhất.

Một lựa chọn khác sẽ được cấu trúc lại việc tạo ra các lớp bên trong vào một chức năng nhà máy nào đó cho bạn, sau đó vòng lặp của bạn tự nó có thể là một cái gì đó sạch như:

List<Runnable> r = new ArrayList<>(); 
for(int i = 0; i < 10; i++) { 
    r.add(generateRunnablePrinter(i)); 
} 

Và chức năng nhà máy chỉ có thể tuyên bố thông số cuối cùng:

Tôi thích phương pháp này được tái cấu trúc vì nó giữ mã sạch hơn, tương đối tự mô tả và cũng ẩn đi tất cả hệ thống ống nước bên trong lớp.

Phân loại ngẫu nhiên: nếu bạn coi các lớp bên trong vô danh tương đương với các bao đóng, thì generateRunnablePrinter có hiệu quả là hàm bậc cao hơn. Ai nói bạn không thể lập trình chức năng trong Java :-)

+3

Tôi nghĩ rằng đây là cách sạch nhất cho đến nay. – assylias

2

Đây là những gì IntelliJ làm cho bạn như một sửa chữa. Sự khác biệt duy nhất là tôi sẽ làm

ExecutorService es = 
for(int i = 0; i < 10; i++) { 
    final int i_final = i; 
    es.execute(new Runnable() { 
1

thay thế (Ít hơn tối ưu): tạo ra một lớp nhỏ bên trong mà thực hiện Runnable:

class Printer implements Runnable { 
    private int index; 

    public Printer(int index) { 
     this.index = index; 
    } 

    public void run() { 
     System.out.println(index); 
    } 
} 

List<Runnable> r = new ArrayList<>(); 
for(int i = 0; i < 10; i++) { 
    r.add(new Printer(i)); 
} 
+0

Đủ công bằng - Không thể nói điều đó làm cho nó dễ đọc hơn! – assylias

+0

@assylias: Đúng vậy, không. Thông thường, tôi cũng sẽ sử dụng phiên bản ban đầu của bạn, vì mã trong phương thức chạy quá nhỏ ... – Tudor

+1

@assylias, các lớp không phải anon [nhưng được khai báo với thân phương thức] tốt hơn đáng kể trong các trường hợp rất quan trọng: biểu đồ lớp và ngăn xếp dấu vết. Tôi cố gắng tránh những người vô danh nếu tôi có thể giúp. – bestsss

0

Tôi sợ không có cách nào khác hơn là sao chép truy cập của bạn đến biến cuối cùng thứ hai và sử dụng biến đó trong lớp bên trong ẩn danh của bạn. Đây là một trong những "thiếu sót" của Java xung quanh chủ đề đóng cửa và một lợi thế được quảng cáo của các ngôn ngữ anh chị em như Groovy.

+1

Nó không thực sự là một thiếu: nó ngăn chặn người sử dụng từ làm một số loại lỗi. Nếu trình biên dịch Java không thực thi các biến như là cuối cùng, thì rất nhiều người có thể giả định (nhầm lẫn) rằng họ có thể cập nhật biến cục bộ và rằng "đóng cửa" sẽ thấy kết quả. Và bạn có thể đặt cược rằng điều đó sẽ gây ra rất nhiều lỗi và rất nhiều câu hỏi SO lẫn lộn! – mikera

0

Có vẻ ổn với tôi. Bạn muốn để sử dụng giá trị của biến vòng lặp bên trong lớp ẩn danh của bạn và biến vòng lặp rõ ràng không thể là cuối cùng (vì giá trị của nó thay đổi).

Tạo biến cục bộ cuối cùng mới là giải pháp tốt.

1

Giải pháp của bạn không tệ. Bạn có thể thực hiện các công cụ khác, như định nghĩa lớp con của riêng bạn là Runnable và khởi tạo nó bằng i trong hàm khởi tạo hoặc khối khởi tạo, nhưng trong trường hợp này, tôi nghĩ rằng nó sẽ chỉ thêm sự phức tạp mà không có lý do chính đáng.

BTW: Tôi cho rằng ví dụ của bạn là một ví dụ tổng hợp, trong thực tế, tạo Runnable mới chỉ để in một số nguyên dường như không phải là một ý tưởng hay.

Các vấn đề liên quan