Given i want to filter a List of Key-Value objects.
My (Document)-Object from the example below looks like this
{
"attributeEntityList" : [
{key: 'key1', value: 'somevalue1'},
{key: 'key2', value: 'somevalue2'},
{key: 'key3', value: 'somevalue3'}
]
}
When I pass in a list of the following keys
["key1", "key2", "key3"]
, I expect my function to return the whole given List of attributes.When I pass in a list of the following keys
["key1", "key2"]
, I expect my function to return a list of Attributes with the given key-names.When I pass in a list of the following keys
["key1", "key2", "faultyKey"]
, I expect my function to return an Empty list.
My imperative-style solution looks like this and it works okay:
private List<AttributeEntity> getAttributeEntities(List<String> keys, Document value) {
final List<AttributeEntity> documentAttributeList = value.getAttributeEntityList();
final List<AttributeEntity> resultList = new ArrayList<>();
for(String configKey: keys){
boolean keyInAttribute = false;
for(AttributeEntity documentAttribute : documentAttributeList){
if(configKey.equals(documentAttribute.getAttribute_key())){
keyInAttribute = true;
resultList.add(documentAttribute);
break;
}
}
if(!keyInAttribute){
resultList.clear();
break;
}
}
return resultList;
}
For education and fun (and maybe better scaling) I'd like to know how to convert this piece of Code into a solution using the new Java 8 streaming-api.
This is what I came up with, converting my pre-Java8-code to Java8.
To my eyes it looks much more concise and it's shorter. But it does not, what I expect it to do :/
I'm realy struggling implementing the third bulletpoint of my requirements. It always returns all (found) Attributes, even when i pass in a not existant key.
private List<AttributeEntity> getAttributeEntities(List<String> keys, Document value) {
final List<AttributeEntity> documentAttributeList = value.getAttributeList();
return documentAttributeList.stream()
.filter(attribute ->
keys.contains(attribute.getAttribute_key())
).collect(Collectors.toList());
}
I'm thinking of implementing my own custom Collector. Since my Collector should only return the List, when the collected results contain each given key at least once.
Any other Idea on how to achieve that?
This solution passes my tests. But it feel's like i'm putting the cart before the horse.
It's neither concise nor short or elegant any more.
private List<AttributeEntity> getAttributeEntities(List<String> keys, Document value) {
final List<AttributeEntity> documentAttributeList = value.getAttributeList();
return documentAttributeList.stream()
.filter(attribute ->
keys.contains(attribute.getAttribute_key())
)
.collect(Collectors.collectingAndThen(Collectors.toList(), new Function<List<AttributeEntity>, List<AttributeEntity>>() {
@Override
public List<AttributeEntity> apply(List<AttributeEntity> o) {
System.out.println("in finisher code");
if (keys.stream().allMatch(key -> {
return o.stream().filter(attrbiute -> attrbiute.getAttribute_key().equals(key)).findAny().isPresent();
})) {
return o;
} else {
return new ArrayList<AttributeEntity>();
}
}
}));
}