recorrer - Fusionando dos Lista de objetos en java 8
listas java (4)
Por ejemplo:
public class Parent {
public int no;
public String name;
@Override
public int hashCode() {
return (no << 4) ^ name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Parent))
return false;
Parent o = (Parent)obj;
return this.no == o.no && this.name.equals(o.name);
}
}
Tengo un Java clase Parent
con 20 atributos (attrib1, attrib2 .. attrib20)
y sus getters y setters correspondientes. También tengo dos listas de objetos principales: list1
y list2
.
Ahora quiero fusionar ambas listas y evitar objetos duplicados basados en attrib1
y attrib2
.
Usando Java 8:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.distinct()
.collect(Collectors.toList());
Pero, ¿en qué lugar debo especificar los atributos? ¿Debo anular hashCode
e equals
método?
Si desea implementar equals
y hashCode
, el lugar para hacerlo está dentro de la clase Parent
. Dentro de esa clase agrega los métodos como
@Override
public int hashCode() {
return Objects.hash(getAttrib1(), getAttrib2(), getAttrib3(),
// …
getAttrib19(), getAttrib20());
}
@Override
public boolean equals(Object obj) {
if(this==obj) return true;
if(!(obj instanceof Parent)) return false;
Parent p=(Parent) obj;
return Objects.equals(getAttrib1(), p.getAttrib1())
&& Objects.equals(getAttrib2(), p.getAttrib2())
&& Objects.equals(getAttrib3(), p.getAttrib3())
// …
&& Objects.equals(getAttrib19(), p.getAttrib19())
&& Objects.equals(getAttrib20(), p.getAttrib20());
}
Si hiciste esto, distinct()
invocado en un Stream<Parent>
automáticamente hará lo correcto.
Si no quiere (o no puede) cambiar la clase Parent
, no existe un mecanismo de delegación para la igualdad, pero puede recurrir a ordenar ya que tiene un mecanismo de delegación:
Comparator<Parent> c=Comparator.comparing(Parent::getAttrib1)
.thenComparing(Parent::getAttrib2)
.thenComparing(Parent::getAttrib3)
// …
.thenComparing(Parent::getAttrib19)
.thenComparing(Parent::getAttrib20);
Esto define un orden basado en las propiedades. Requiere que los tipos de los atributos en sí sean comparables. Si tiene esa definición, puede usarla para implementar el equivalente de distinct()
, basado en ese Comparator
:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.filter(new TreeSet<>(c)::add)
.collect(Collectors.toList());
También hay una variante segura para subprocesos, en caso de que quiera usarla con flujos paralelos:
List<Parent> result = Stream.concat(list1.stream(), list2.stream())
.filter(new ConcurrentSkipListSet<>(c)::add)
.collect(Collectors.toList());
Si desea sobrescribir .equals(…)
y .hashCode()
, debe hacerlo en la clase Parent
. Tenga en cuenta que esto puede causar que otros usos de Parent
fallen. La solución vinculada de Alexis C. es más conservadora.
hashCode
métodos equals
y hashCode
en la clase Parent
para evitar duplicados de las listas. Esto le dará el resultado exacto de lo que quiere.