9
I have a collection of elements that I’m going through in a stream
. Suppose it is to take the highest value element (integer) given a classification (string). This class is enough to exemplify my case:
class Elemento {
final String classificacao;
final int valor;
Elemento(String classificacao, int valor) {
this.classificacao = classificacao;
this.valor = valor;
}
// getters, para permitir um uso mais funcional
}
I need to take, for the elements of the same "classification", the higher "value".
My first strategy was to group in a map <String, List<Elemento>>
to, on its values, catch the biggest Elemento
:
Collection<Elemento> elementos = ...; // povoa os valores
elementos.stream()
.collect(Collectors.groupingBy(Elemento::getClassificacao))
.values().stream()
.map(l -> l.stream().max(Elemento::getValor).orElse(null))
.filter(Objects::nonNull)
...; // mais
Is there any way to do this without using this intermediate list map?
The real case
In fact, the particular case is to take the most specific method within a collection of bridge methods, because there have been cases of "name conflicts" when implementing generic method of a generic interface. In my real case, I have it to extract my elements:
private static int determineSuperclass(Method ma, Method mb) {
Class<?> ra = ma.getReturnType();
Class<?> rb = mb.getReturnType();
if (ra.equals(rb)) {
return 0;
} else if (ra.isAssignableFrom(rb)) {
return -1;
} else if (rb.isAssignableFrom(ra)) {
return +1;
} else {
return 0;
}
}
// ...
Class<T> inputClazz = ...; // povoa inputClazz
Stream.of(inputClazz.getMethods())
.filter(m -> m.getParameterCount() == 0)
.filter(m -> m.getName().startsWith("get"))
.filter(m -> !Void.class.equals(m.getReturnType()))
.filter(m -> Modifier.isPublic(m.getModifiers()))
.filter(m -> !Modifier.isStatic(m.getModifiers()))
.collect(Collectors.groupingBy(Method::getName))
.values().stream()
.map(l -> l.stream().max(MyClass::determineSuperclass).orElse(null))
.filter(Objects::nonNull)
...; // faço minha própria coleção
In my case, the problem was when I implemented a generic interface. In this case, the interface was:
interface HasKey<K> {
K getKey();
}
And the "problem" even happens in anonymous classes, like:
HasKey<Integer> abc = new HasKey<Integer> {
@Override
public Integer getKey() {
return 1;
}
};
When it’s called abc.getClass().getMethods()
, two methods called getKey()
:
public java.lang.Object myPackage.MyClass$1.getKey())
public java.lang.Integer myPackage.MyClass$1.getKey())
But my intention remains as, from a stream
, take the "largest" element of a given "subgroup", only without using the intermediate list map explicitly.
To be honest, I still don’t like it =/ It seems more functional, but I still need to make a call to
Map.values()
inside the lambda. Therefore, it still has an explicit finger of theMap
. Maybe a collector of its own will solve it? But, yes, the use ofMap
...– Jefferson Quesado
@Jeffersonquesado All right, I didn’t really like my solution either :-) Maybe a collector himself is the way (I just didn’t suggest it because, honestly, I never needed to create one - if there’s time I try and update the answer). But inside this collector you would have to use an algorithm that doesn’t create the map, otherwise it won’t do anything either :-)
– hkotsubo
Yeah, but at least you won’t need a list map... I think my biggest nuisance is this, I just don’t know how to really express it within the context
– Jefferson Quesado
I edited the question to make it clear that it is list map that bothers me. Thank you for helping me see more correctly my question
– Jefferson Quesado
@Jeffersonquesado I updated the answer. How is the first time I use the method
collect
with 3 parameters, may not be the best solution, but at least I was able to delete the list map– hkotsubo
There is an error in solution 2 (
.collect
with 3 arguments). TheputAll
will eventually cause some maximum to be overwritten. It must have a new default method ofMap
as aputIf
or something similar– Jefferson Quesado
@Jeffersonquesado Yes, it lacked to test better... Well, when I can I tidy up (maybe I can see this hj, but most likely it’s only tomorrow), thanks for warning :-) But what about the third solution? I think she already treats duplicate entries better (but I haven’t tested them yet)
– hkotsubo
the third seems right =]
– Jefferson Quesado
@Jeffersonquesado I did some tests but they were not very conclusive, I could not reproduce the error that you mention, but if you said that is wrong I believe :-) - Anyway, I thought better to remove the solution 2 and leave only the 3, that from the tests I’ve done it seems to work better anyway.
– hkotsubo