2016-10-20 1 views
2

Ich versuche, einen berechneten Wert aus einem Attribut zu gruppieren. Der berechnete Wert ist optional - ein wenig mehr klar zu sein, seine ist ein vereinfachtes Beispiel:Java 8 Streams gruppieren nach einem optionalen Attribut

class Foo: 
    int id; 
    Group group; 
    .. some other stuff 

class Group: 
    String groupId; 
    ... (some other stuff) 

class SomeName: 
    String someAttribute; 

class Converter: 
    public Optional<SomeName> getSomenameFromGroup(Group) 

Ich kann nicht die Methoden in Converter ändern, da es mir nicht gehören.

Ich habe eine Liste von Foo, die ich nach SomeName "someAttribute" filtern möchte.

Zum Beispiel, ich habe so etwas wie dies:

Map<String, List<Foo>> fooBySomeName = 
    fooList.stream().collect(Collectors 
    .groupingBy(foo -> { 
     Optional<SomeName> name = 
      converter.getSomenameFromGroup(foo.getGroup.getGroupId()); 
     return name.isPresent() ? name.get().someAttribute() : ""; 
    })); 

Aber die Sache ist, ich will nicht alles in meiner Karte, wenn der Name in der groupingBy Anweisung nicht vorhanden ist. Ich hatte so etwas wie diese:

fooBySomeNames.remove("") 

die ich denke, kann alles von der Karte entfernen, die von diesem Schlüssel gruppiert wurden, aber gibt es eine saubere oder mehr richtigen Weg, dies in der groupingBy Aussage zu tun?

Antwort

3

Sie können Einträge mit einem Filter wie folgt entfernen.

Map<String, List<Foo>> fooBySomeName = fooList.stream() 
    .filter(foo -> fooToSomeAttribute(foo).isPresent()) 
    .collect(Collectors.groupingBy(foo -> fooToSomeAttribute(foo).get())); 

private static Optional<String> fooToSomeAttribute(Foo foo) 
{ 
    return Optional.ofNullable(foo) 
     .map(Foo::getGroup) 
     .flatMap(new Converter()::getSomenameFromGroup) 
     .map(SomeName::getSomeAttribute); 
} 

Oder mit einem Paar Objekt können Sie doppelte Berechnung von someAttribute für jeden Foo vermeiden:

Map<String, List<Foo>> fooBySomeName = fooList.stream() 
    .filter(Objects::nonNull) 
    .map(FooAndSomeAttribute::new) 
    .filter(pair -> pair.getSomeAttribute().isPresent()) 
    .collect(Collectors.groupingBy(
     pair -> pair.getSomeAttribute().get(), 
     Collectors.mapping(
      FooAndSomeAttribute::getFoo, 
      Collectors.toList()))); 

private static class FooAndSomeAttribute 
{ 
    private final Foo foo; 
    private final Optional<String> someAttribute; 

    public FooAndSomeAttribute(Foo foo) 
    { 
     this.foo = foo; 
     this.someAttribute = Optional.ofNullable(foo) 
      .map(Foo::getGroup) 
      .flatMap(new Converter()::getSomenameFromGroup) 
      .map(SomeName::getSomeAttribute); 
    } 

    public Foo getFoo() 
    { 
     return foo; 
    } 

    public Optional<String> getSomeAttribute() 
    { 
     return someAttribute; 
    } 
}