2015-05-24 14 views
12

Tôi sẽ giới thiệu về MongoDB cho java. Có một số mã ví dụ để lấy tất cả các tài liệu trong một bộ sưu tập. Các mã hoạt động, nhưng tôi tìm thấy nó một chút ... clunky vì thiếu một từ tốt hơn. Tôi tự hỏi nếu có một lý do cụ thể mà làm cho nó cần thiết. Ví dụ đưa ra là:Cú pháp Java với MongoDB

FindIterable<Document> iterable = db.getCollection("restaurants").find(); 
iterable.forEach(new Block<Document>() { 
    @Override 
    public void apply(final Document document) { 
     System.out.println(document); 
    } 
}); 

Có một số lý do một trường hợp Block phải được tạo ra trong mỗi lần lặp của forEach trong ví dụ trên? Tại sao không một chút gì đó đơn giản hơn như:

FindIterable<Document> iterable = db.getCollection("restaurants").find(); 
for (Document document : iterable) { 
    System.out.println(document); 
} 
+0

kiểm tra kiểm tra bài viết này, nó giải thích làm thế nào bạn có thể có được giải pháp mà bạn muốn, https: // nhóm .google.com/forum/#! topic/mongodb-user/pcVX84PPwM0 – faljbour

+0

@faljbour - Điều này không trả lời được câu hỏi của tôi. Chuỗi đó là về thay đổi API từ phiên bản Mongo này sang phiên bản khác. Cụ thể, nó không thảo luận về sự khởi tạo của cá thể 'Block' trong vòng lặp forEach. – Hal50000

+1

@ Hal50000 Tôi nghĩ rằng chỉ có một đối tượng của một lớp vô danh thực hiện khối được tạo ra làm tham số cho phương thức iterable.forEach(). – Hongfei

Trả lời

23

Trong khi bạn chắc chắn có thể sử dụng hình thức mà bạn đề nghị:

for (Document document : col.find()) { 
    // do something 
} 

nó giới thiệu một vấn đề khi cơ thể của vòng lặp for ném một ngoại lệ: nếu điều này xảy ra con trỏ sẽ không được đóng lại. Các thành ngữ thích hợp để bảo vệ chống lại đó là sử dụng MongoCursor (mà thực hiện có thể đóng) một cách rõ ràng:

try (MongoCursor<Document> cursor = col.find().iterator()) { 
    while (cursor.hasNext()) { 
     System.out.println(cursor.next()); 
    } 
} 

Phương pháp foreach chỉ là một chút đường cú pháp để tránh sự cần thiết của mã ứng dụng phải lo lắng về việc phải đóng con trỏ bằng tay như thế này.

Nếu bạn không muốn tạo ra một khối mới cho mỗi lần lặp, bạn có thể cấu trúc mã của bạn kéo ra sự sáng tạo vô danh bên trong lớp, ví dụ:

Block<Document> block = new Block<Document>() { 
    @Override 
    public void apply(final Document document) { 
     System.out.println(document); 
    } 
}; 
col.find().forEach(block); 

Tất nhiên đó là thậm chí clunkier, vì vậy nếu bạn có thể sử dụng Java 8, bạn có thể thay thế toàn bộ điều với một lambda:

col.find().forEach((Block<Document>) document -> { 
    System.out.println(document); 
}); 

hoặc trong trường hợp này chỉ đơn giản là:

col.find().forEach((Block<Document>) System.out::println); 

lambda metafactory sẽ đảm bảo rằng không có đối tượng không cần thiết nào được tạo.

+0

Cảm ơn bạn đã trả lời chi tiết. Vấn đề là, tôi vẫn chưa rõ ràng về mục đích instantiating một 'Block ' và sau đó sử dụng phương thức 'apply (...)' của nó. Có mối quan hệ nào giữa 'Cursor' và' Block' không? – Hal50000

+2

Bất kỳ kiểu 'MongoIterable' nào - giống như những gì được trả về từ' find() 'cung cấp các phương thức trợ giúp có thể được sử dụng khi lặp lại. Đây là 'forEach',' into', 'map' và dĩ nhiên' iterator'. Phương thức 'forEach' lấy một' Block' bao gồm logic mà bạn muốn thực hiện cho mọi tài liệu. Bên trong, nó sẽ lặp lại 'MongoCursor' cho bạn và đảm bảo rằng nó được đóng một cách chính xác. – Ross

+0

@Ross -thanks. Điều đó đã giải quyết nó rất nhiều - Vì vậy, trong một ví dụ thế giới thực, có thể có một số logic phức tạp hơn so với chỉ 'System.out.println (...)' bên trong áp dụng (...) – Hal50000

3

Tôi tự hỏi cùng một câu hỏi và tôi thấy khá dễ dàng mã sau đây để xử lý tình huống đó:

List<Document> restaurants = db.getCollection("restaurants").find().into(new ArrayList<Document>()); 

for (Document restaurant : restaurants) { 
    System.out.println(restaurant); 
} 
+0

Câu hỏi đặt ra là: con trỏ có tự động đóng trong trường hợp ngoại lệ khi sử dụng 'vào()' không? –

+0

Điều này sẽ sao chép toàn bộ tập hợp kết quả thành một bộ sưu tập trong bộ nhớ. Tùy thuộc vào kích thước của kết quả, điều đó có thể không thực tế hoặc thậm chí là không thể. forEach() và công ty mặt khác xử lý từng mục một, hoạt động cho các kết quả có kích thước tùy ý. – jschreiner

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