2015-05-24 19 views
12

Przechodzę przez wprowadzenie do MongoDB dla java. Istnieje przykładowy kod do pobierania wszystkich dokumentów z kolekcji. Kod działa, ale uważam, że jest trochę ... niepewny z braku lepszego słowa. Zastanawiam się, czy jest jakiś konkretny powód, który sprawia, że ​​jest to konieczne. Podany przykład jest:Składnia Java z MongoDB

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

Czy istnieje jakiś powód instancja Block musi być tworzone w każdej iteracji forEach w powyższym przykładzie? Dlaczego nie coś trochę bardziej proste jak:

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

odjazdu ten post, to wyjaśnia, w jaki sposób można uzyskać rozwiązanie, które chcesz, https: // grupy .google.com/forum/#! topic/mongodb-user/pcVX84PPwM0 – faljbour

+0

@faljbour - To nie odpowiada na moje pytanie. Ten wątek dotyczy zmian API z jednej wersji Mongo na inną. Mianowicie, nie omawia ona instancji instancji 'Block' w pętli forEach. – Hal50000

+1

@ Hal50000 Myślę, że istnieje tylko jeden obiekt anonimowej klasy implementującej blok , który jest tworzony jako parametr metody iterable.forEach(). – Hongfei

Odpowiedz

23

Choć z pewnością można użyć formularza, który zasugerował:

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

wprowadza problem, gdy ciało pętli for zgłasza wyjątek: jeśli tak się stanie, kursor nie zostanie zamknięty. Prawidłowe idiom, aby ustrzec się przed że jest użycie MongoCursor (która implementuje zamykane) wyraźnie:

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

Metoda forEach jest tylko trochę cukru składniowej aby uniknąć konieczności kodu aplikacji martwić konieczności zamykania kursor ręcznie w ten sposób.

Jeśli nie chcesz, aby utworzyć nowy blok dla każdej iteracji można byłaby kod wyciągnąć anonimowy wewnętrzną utworzenie klasy, np:

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

Oczywiście to jeszcze clunkier, więc jeśli są w stanie używać Javy 8, można wymienić całość z lambda:

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

lub w tym przypadku prościej:

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

Dzięki lambda metafactory nie zostaną utworzone niepotrzebne obiekty.

+0

Dzięki za szczegółową odpowiedź. Chodzi o to, że nadal nie jestem pewien, co należy zrobić, aby utworzyć blok "", a następnie użyć jego metody 'apply (...)'. Czy istnieje związek między 'Cursor' i' Block'? – Hal50000

+2

Dowolny typ "MongoIterable" - podobnie jak to, co jest zwracane z 'find()' zapewnia metody pomocnicze, które mogą być używane podczas iteracji. Są to 'forEach',' into', 'map' i oczywiście' iterator'. Metoda 'forEach' przyjmuje" blok ", który obejmuje logikę, którą chcesz wykonać dla każdego dokumentu. Wewnętrznie wykona iterację 'MongoCursor' i upewni się, że jest poprawnie zamknięta. – Ross

+0

@Ross-podziękowania. To wiele wyjaśniło - więc w rzeczywistym świecie może być trochę bardziej skomplikowana logika niż tylko zastosowanie 'System.out.println (...)' wewnątrz (...) – Hal50000

3

zadałem sobie to samo pytanie i znalazłem dość łatwe następujący kod do obsługi tej sytuacji:

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

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

Pytanie brzmi: czy kursor jest automatycznie zamykany w przypadku wyjątku podczas używania 'do()'? –

+0

Powoduje skopiowanie całego zestawu wyników do kolekcji w pamięci. W zależności od wielkości wyniku może to być niepraktyczne, a nawet niemożliwe. forEach() i firma z drugiej strony przetwarzają wpisy jeden po drugim, który działa dla zestawu wyników o arbitralnym rozmiarze. – jschreiner