2016-02-19 35 views
6

Mam listę obiektów, gdzie każdy obiekt, który zwraca List<String>. Jak mogę użyć strumieni Java 8, aby uzyskać jeden List<String>?Java 8 uzyskać wszystkie elementy na liście

Contact klasa ma następującą metodę;

public List<String> getSharedFriendsIds() { 
    return sharedFriendsIds; 
} 

I mam

List<Contact> contactsList; 

Co starałem się

List<String> sharedContacts = contactsList.stream() 
    .map(Contact::getSharedFriendsIds) 
    .sequential() 
    .collect(Collectors.toList()); 

Ale powyżej linii nie wraca List<String> ale raczej List<List<String>> który nie jest to, co chcę.

+0

Słowo "I" jest zawsze pisane wielką literą po angielsku. Tak samo jest z początkiem każdego zdania. Jeśli publikujesz z telefonu komórkowego, większość nowoczesnych telefonów komórkowych naprawi te błędy, jeśli je odpowiednio skonfigurujesz. –

+2

Dlaczego potrzebujesz '.sequential()'? –

Odpowiedz

9

Należy użyć .flatMap(), aby utworzyć pojedynczą listę z poszczególnych list zawartych w każdym obiekcie Contact na głównej liście contactsList.

List<String> sharedContacts = contactsList.stream() 
     .filter(contacts -> contacts.getSharedFriendsIds() != null) 
     .flatMap(contacts -> contacts.getSharedFriendsIds().stream()) 
     .sorted().collect(Collectors.toList()); 

Sprawdź zaktualizowany fragment powyżej z dodatkowym .filter dla przypadku, gdy istnieją jakiekolwiek obiekty z sharedFriendsIds == null na liście. Również użyłeś .sequential dla logiki sortowania, jak sądzę, powinieneś użyć metody .sorted, ponieważ sekwencja jest dla użycia nie-równoległego, która jest już domyślną konfiguracją.

+1

@tsingh Lepiej jest, aby 'getSharedFriendsIds()' zwracał pusty strumień zamiast 'null'. –

+2

Dwa razy nazywasz 'getSharedFriendsIds()'. Można tego łatwo uniknąć, wykonując najpierw '.map (Contact :: getSharedFriendsIds)', przed krokiem '.filter'. Można nawet przymusić filtr i krok mapy płaskiej, np. '.map (Contact :: getSharedFriendsIds) .flatMap (list-> list! = null? list.stream(): null)', ale to tylko kwestia gustu ... – Holger

+0

Całkowicie się zgadzam, ale chciałem tylko zachować bieżące wykorzystanie 'flatmap', ponieważ ma wysoką czytelność dla autora pytania, dlatego nie refaktoryzowałem się dalej. Dzięki za porady @StuartMarks & @Holger –

3

Wzór Znalazłem bardzo przydatna jest do niech klasy nadrzędnej (w tym przypadku klasa Contact) tworzenie i powrócić strumienie dzieci obiektów (w tym przypadku przyjaciół akcji IDS):

public class Contact { 

    private List<String> sharedFriendsIds; 

    public Stream<String> sharedFriendsIds() { 
     return sharedFriendsIds == null ? Stream.empty() : sharedFriendsIds.stream(); 
    } 

    public List<String> getSharedFriendsIds() { 
     return sharedFriendsIds; 
    } 
} 

Konwencja to nazwa metody, która zwraca strumień jako przesyłany atrybut. Ta metoda zawiera już kontrolę zerową.

Potem coraz wspólnych znajomych Identyfikatory dla wszystkich kontaktów jest znacznie prostsze:

List<String> sharedContacts = contactsList.stream() 
    .flatMap(Contact::sharedFriendsIds) 
    .collect(Collectors.toList()); 

Trzeba użyć flatMap() w celu spłaszczyć elementy listy dzieci do jednej listy, w przeciwnym razie” d uzyskać listę strumieni.

Uwaga 1: nie trzeba używać sequential(), ponieważ użycie stream() na liście kontaktów już zwraca strumień sekwencyjny.

Uwaga 2: jeśli chcesz ostateczna lista mają być sortowane, należy użyć sorted() na potoku:

List<String> sharedContacts = contactsList.stream() 
    .flatMap(Contact::sharedFriendsIds) 
    .sorted() 
    .collect(Collectors.toList()); 
+1

To jest dobry sposób na wyczyszczenie bałaganu notacji lambda, myślałem o tym, ale takie metody byłyby używane tylko przez tę logikę, a to było trochę przesadzone, jeśli takie mapowanie było częste. zgodziłbym się z tym. Myślę też, że chciał sortować wynikową listę, sekwencyjne użycie było błędem z jego strony. –

+1

@bureaquete No cóż, możesz zobaczyć metodę stream jako getter. Zazwyczaj zawsze piszesz gettery, bez względu na to, czy używasz ich w swojej logice, czy nie. Zgadzam się z sekwencyjną() a sortowaną() rzeczą, uważam też, że OP chciał posortowaną listę. –

4

Nie ma powodów, by używać .sequential() tutaj, strumienie są sekwencyjne domyślnie.

List<String> sharedContacts = contactsList.stream() 
     .map(Contact::getSharedFriendsIds) 
     .filter(Objects::nonNull) 
     .flatMap(Collection::stream) 
     .collect(Collectors.toList()); 

W porządku naturalnym;

List<String> sharedContacts = contactsList.stream() 
     .map(Contact::getSharedFriendsIds) 
     .filter(Objects::nonNull) 
     .flatMap(Collection::stream) 
     .sorted() 
     .collect(Collectors.toList()); 
Powiązane problemy