I have this class:
public class StructUserType extends UserType {
MembersList membersList = new MembersList();
public List<Member> getMembers() {
return Collections.unmodifiableList(membersList.members);
}
static class MembersList {
List<Member> members = new ArrayList<>();
}
public static class Member implements Identifiable {
private Integer id;
public Integer getId() {
return id;
}
}
}
And I have a List object:
List<SmbpUserType> userTypes = new ArrayList<>();
I want find Member which is equal to a certain id. I tried as follows:
Integer id = 1;
userTypes.stream()
.filter(StructUserType.class::isInstance)
.map(StructUserType.class::cast)
.forEach(structUserType -> {
structUserType.getMembers()
.stream()
.filter(m -> m.getId() == id)
.findFirst().orElse(null);
});
I want, when the filter in the internal stream runs and finds the first member, to return the parent element that this member contains, those UserType.
Analog in the classical style:
for (UserType userType : userTypes) {
if (userType instanceof StructUserType) {
List<StructUserType.Member> members = ((StructUserType) userType).getMembers();
for (StructUserType.Member member : members) {
if (member.getId() == id) {
return userType;
}
}
}
}
return null;
Replace forEach with filter, to find StructUserType instances that satisfy the condition of the inner stream pipeline. Then get the first element of the Stream, if such exists.
return
userTypes.stream()
.filter(StructUserType.class::isInstance)
.map(StructUserType.class::cast)
.filter(st -> st.getMembers()
.stream()
.anyMatch(m -> m.getId().equals(id)))
.findFirst()
.orElse(null);
Instead of forEach you can use a filter for the nested Stream.
At last you can return the first match or collect all matches
...
.filter(structUser -> structUser.getMembers()
.stream()
.anyMatch(member -> member.getId().equals(id))
)
...
Related
I want to group different objects types based on same content of fields incomeCode, endDate and codeRef on both classes. I omitted many fields on both classes that make each object unique for simplicity.
public class Exon {
private Long id;
private IncomeCode incomeCode;
private LocalDate endDate;
String codeRef;
}
public class Sup {
private Long id;
private IncomeCode incomeCode;
private LocalDate startDate;
private LocalDate endDate;
String codeRef;
}
Exons example:
id
incomdeCode
endDate
codeRef
1
45
01/01/2021
4
2
21
01/01/2022
5
3
33
01/01/2023
2
4
45
01/01/2021
4
Sups example:
id
incomdeCode
endDate
codeRef
1
45
01/01/2021
4
2
21
01/01/2022
5
3
33
01/01/2023
2
Desired result :
List : { {exon1, exon4, sup1}, {exon2, sup2}, {exon3, sup3} }
My attempt :
public Map<Object, List<Exon>> getExons() {
Map<Object, List<Exon>> result = getSource1.stream()
.flatMap(lp -> lp.getExons().stream())
.collect(Collectors.groupingBy(e -> new KeyGroup(e.getIncomeCode(), e.getEndDate(), e.getCodeRef())
));
return result;
}
public Map<Object, List<Sup>> getSups() {
Map<Object, List<Sup>> result = getSource2.stream()
.flatMap(lp -> lp.getSups().stream())
.collect(Collectors.groupingBy(e -> new
KeyGroup(e.getIncomeCode(), e.getEndDate(), e.getCodeRef())));
return result;
}
Map<Object, List<Exon>> exonList = getExons();
Map<Object, List<Sup>> supList = getSups();
Map<Object, List<List<?>>> objMap = new HashMap<>();
exonList.forEach((k, v) -> {
if (objMap.containsKey(o)) {
objMap.get(o).add(v);
} else {
List<List<?>> eList = new ArrayList<>();
eList.add(v);
objMap.put(o, eList);
}
});
supList.forEach((o, v) -> {
if (objMap.containsKey(o)) {
objMap.get(o).add(v);
} else {
List<List<?>> eList = new ArrayList<>();
eList.add(v);
objMap.put(o, eList);
}
});
As it has been pointed out in the comments, if you need to mix different type of objects your resulting List will be a List<List<Object>>.
To group them by like that, you could use the collect() terminal operation in conjunction with a Collectors.groupingBy() which could group the objects with a key built ad-hoc with the desired fields (incomeCode, endDate and codeRef). After building the Map, you could retrieve its values, i.e. a Collection with the lists of objects, and give them in input to the Conversion Constructor of a List implementation.
List<List<Object>> listRes = new ArrayList<>(Stream.concat(listExon.stream(), listSup.stream())
.collect(Collectors.groupingBy(obj -> {
if (obj instanceof Exon) {
Exon exon = (Exon) obj;
return String.format("%s-%s-%s", exon.getIncomeCode(), exon.getEndDate(), exon.getCodeRef());
}
Sup sup = (Sup) obj;
return String.format("%s-%s-%s", sup.getIncomeCode(), sup.getEndDate(), sup.getCodeRef());
})).values());
Here there is also a link to test the code above:
https://ideone.com/OSTItQ
How about something like this. You can make another subclass and group your different class item on this map
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Solution
{
public void sol()
{
List<Exon> exons = new ArrayList<>();
List<Sup> sups = new ArrayList<>();
List<ClassWithNeededFields> list1 = exons.stream()
.map(item -> new ClassWithNeededFields(item.getIncomeCode(), "neededField"))
.collect(Collectors.toList());
List<ClassWithNeededFields> list2 = sups.stream()
.map(item -> new ClassWithNeededFields(item.getIncomeCode(), "neededField"))
.collect(Collectors.toList());
list1.addAll(list2);
Map<IncomeCode, List<ClassWithNeededFields>> map2 = list1.stream()
.map(item -> new ClassWithNeededFields(item.getIncomeCode(), "neededField"))
.collect(Collectors.groupingBy(ClassWithNeededFields::getIncomeCode));
}
public class Exon
{
private IncomeCode incomeCode;
public IncomeCode getIncomeCode()
{
return null;
}
}
public class Sup
{
private IncomeCode incomeCode;
public IncomeCode getIncomeCode()
{
return null;
}
}
public class IncomeCode
{
}
public class ClassWithNeededFields
{
private IncomeCode incomeCode;
private String otherField;
// The other needed fields. ...
public ClassWithNeededFields(IncomeCode incomeCode, String otherField /* The other needed fields. ... */)
{
}
public IncomeCode getIncomeCode()
{
return this.incomeCode;
}
}
}
I have to filter a list, based on the value of an attribute. I also have to filter a nested list, based on one of its attributes, and likewise for another nested list. I wondered how this might be possible in a stream.
Example:
I want to filter a List of Foo's, retaining only those where Foo.type = "fooType".
Within these retained Foo's, I wish to filter a list of Bar's on Bar.type = "barType", retaining only those which satisfy the given condition.
I then want to filter the list of NestedAttribute's on NestedAttribute.id = "attributeID", only retaining those which match this condition.
I want to return the list of foo's, from this.
void test() {
List<Foo> listOfFoos;
for(Foo foo : listOfFoos) {
if(foo.getType().equalsIgnoreCase("fooType")) {
// If foo matches condition, retain it
for(Bar bar : foo.getBars()) {
if(bar.getType().equalsIgnoreCase("barType")) {
// If Bar matches condition, retain this Bar
for(NestedAttribute attribute : bar.getNestedAttributes()) {
if(attribute.getId().equalsIgnoreCase("attributeID")) {
// retain this attribute and return it.
}
}
} else {
// remove bar from the list
foo.getBars().remove(bar);
}
}
}else {
// remove Foo from list
listOfFoos.remove(foo);
}
}
}
#Getter
#Setter
class Foo {
String type;
List<Bar> bars;
}
#Getter
#Setter
class Bar {
String type;
List<NestedAttribute> nestedAttributes;
}
#Getter
#Setter
class NestedAttribute {
String id;
}
I have tried this:
listOfFoos = listOfFoos.stream()
.filter(foo -> foo.getType().equalsIgnoreCase("fooType"))
.flatMap(foo -> foo.getBars().stream()
.filter(bar -> bar.getType().equalsIgnoreCase("barType"))
.flatMap(bar -> bar.getNestedAttributes().stream()
.filter(nested -> nested.getId().equalsIgnoreCase("attributeID"))
)
).collect(Collectors.toList());
You can do this with the stream filter lambda expression, but the resultant cohesion will unfortunately not be great:
listOfFoos.stream()
.filter(foo ->
(foo.getType().equalsIgnoreCase("fooType") && (foo.getBars().stream()
.filter((bar -> (bar.getType().equalsIgnoreCase("barType") && (bar.getNestedAttributes().stream()
.filter(nestedAttribute -> nestedAttribute.getId().equalsIgnoreCase("attributeID"))
).count() > 0)))
).count() > 0))
.collect(Collectors.toList());
I am certain you can accomplish this with streams but I don't believe that it lends itself to that very well. The problem is that streams along with map replaces the existing element with a new one, perhaps of different type.
But it is necessary to maintain access to previously constructed types to build the hierarchy. mapMulti would be a possibility but it could get cluttered (More so than below).
The following creates a new hierarchy without any deletions (removal in a random access list can be expensive since either a linear search is required or a repeated copying of values) and adds those instances which contain the type you want. At each conditional, a new instance is created. At those times, the previous list is updated to reflect the just created instance.
After generating some variable data, this seems to work as I understand the goal.
static List<Foo> test(List<Foo> listOfFoos) {
List<Foo> newFooList = new ArrayList<>();
for (Foo foo : listOfFoos) {
if (foo.getType().equalsIgnoreCase("fooType")) {
Foo newFoo = new Foo(foo.getType(), new ArrayList<>());
newFooList.add(newFoo);
for (Bar bar : foo.getBars()) {
if (bar.getType().equalsIgnoreCase("barType")) {
Bar newBar = new Bar(bar.getType(), new ArrayList<>());
newFoo.getBars.add(newBar);
for (NestedAttribute attribute : bar
.getNestedAttributes()) {
if (attribute.getId().equalsIgnoreCase(
"attributeID")) {
newBar.getNestedAttributes().add(attribute);
}
}
}
}
}
}
return newFooList;
}
You can try this option. It's not fluent statement but three fluent one.
Function<Bar, List<NestedAttribute>> filterAttributes
= bar -> bar.getNestedAttributes()
.stream()
.filter(a -> "attributeId".equals(a.getId()))
.collect(Collectors.toList());
Function<Foo, List<Bar>> filterBarsAndAttributes
= foo -> foo.getBars()
.stream()
.filter(b -> "barType".equals(b.getType()))
.peek(b -> b.setNestedAttributes(filterAttributes.apply(b)))
.collect(Collectors.toList());
listOfFoos.stream()
.forEach(f -> f.setBars(filterBarsAndAttributes.apply(f)));
This is what you're looking for
public static List<Foo> filterList(List<Foo> list, String fooType, String barType, String attrID) {
return list.stream()
.filter(foo -> foo.getType().equalsIgnoreCase(fooType))
.peek(foo -> foo.getBars().removeIf(bar -> !bar.getType().equalsIgnoreCase(barType)))
.peek(foo -> foo.getBars().forEach(bar -> bar.getNestedAttributes().removeIf(attr -> !attr.getId().equalsIgnoreCase(attrID))))
.collect(Collectors.toList());
}
EDIT: Added classes implementation with toString for test print
public class Main {
public static void main(String[] args) {
ArrayList barListAttrs = new ArrayList();
barListAttrs.add(new NestedAttribute("testAttr1"));
barListAttrs.add(new NestedAttribute("id"));
barListAttrs.add(new NestedAttribute("testAttr2"));
ArrayList fooListBars = new ArrayList();
fooListBars.add(new Bar("bar", barListAttrs));
fooListBars.add(new Bar("testBar1", new ArrayList<>()));
List<Foo> listFoo = new ArrayList<>();
listFoo.add(new Foo("testFoo1", new ArrayList<>()));
listFoo.add(new Foo("foo", fooListBars));
for (Foo f : listFoo) {
System.out.println(f);
}
List<Foo> list2 = filterList(listFoo, "foo", "bar", "id");
System.out.println("\n\n---------------- RESULT ----------------\n");
for (Foo f : list2) {
System.out.println(f);
}
}
}
class Foo {
String type;
List<Bar> bars;
public Foo(String type, List<Bar> bars) {
this.type = type;
this.bars = bars;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Bar> getBars() {
return bars;
}
public void setBars(List<Bar> bars) {
this.bars = bars;
}
#Override
public String toString() {
StringBuilder str = new StringBuilder(type);
str.append(" [");
for (Bar b : bars) {
str.append(b.toString());
str.append(" ");
}
str.append("]");
return str.toString();
}
}
class Bar {
String type;
List<NestedAttribute> nestedAttributes;
public Bar(String type, List<NestedAttribute> nestedAttributes) {
this.type = type;
this.nestedAttributes = nestedAttributes;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<NestedAttribute> getNestedAttributes() {
return nestedAttributes;
}
public void setNestedAttributes(List<NestedAttribute> nestedAttributes) {
this.nestedAttributes = nestedAttributes;
}
#Override
public String toString() {
StringBuilder str = new StringBuilder(type);
str.append(" [");
for (NestedAttribute na : nestedAttributes) {
str.append(na.toString());
str.append(" ");
}
str.append("]");
return str.toString();
}
}
class NestedAttribute {
String id;
public NestedAttribute(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public String toString() {
return id;
}
}
I assumed you wanted all the "fooType" foos, with only the "barType" bars and "attributeID" nestedAttibutes within.
Then something like:
List<Foo> selected = listOfFoos.stream()
// keep the "footType" foos
.filter(foo -> foo.getType().equalsIgnoreCase("fooType"))
// map each foo to itself
.map(foo -> {
// ... but sneakily remove the non-"barType" bars
foo.getBars().removeIf(bar -> !bar.getType().equalsIgnoreCase("barType"))
return foo;
}
// map each foo to itself again
.map(foo -> {
// iterate over the bars
foo.getBars().forEach(bar ->
// remove the non-"attributeID" nested attributes
bar.getNestedAttributes().removeIf(nested -> !nested.getId().equalsIgnoreCase("attributeID"))
);
return foo;
}
.collect(Collectors.toList());
Note that this is actually modifying the nested collections, instead of just creating a stream. To obtain filtered nested collections would require either doing it like this, or creating new nested collections.
I have class like
public class RoleAccess {
private String roleId;
private List<String> apiIdList;
public String getRoleId() {
return roleId;
}
public void setRoleId(String roleId) {
this.roleId = roleId;
}
public List<String> getApiIdList() {
return apiIdList;
}
public void setApiIdList(List<String> apiIdList) {
this.apiIdList = apiIdList;
}
}
I want to create a new list which will add all apiIdlist from roleaccess
List<String> apiIdList = new ArrayList<>();
for (RoleAccess roleAccess : roleAccessList) {
if (roleAccess.getApiIdList() != null) {
apiIdList.addAll(roleAccess.getApiIdList());
}
}
How can we do with stream api or which is best solution to do this?
I checked normal object list to list but I want to list of object and inner list to list
I tried this
List<String> apiIdList = roleAccessList.stream()
.map(RoleAccess::getApiIdList)
.collect(ArrayList::new, List::addAll, List::addAll);
Use flatMap instead of map:
List<String> apiIdList = roleAccessList.stream()
.flatMap(e -> e.getApiIdList().stream())
.collect(Collectors.toList());
Please take a look on the link for more info about flatMap.
List<String> apiIdList = roleAccessList.stream()
.map(RoleAccess::getApiIdList)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.collect(Collectors.toList());
One of the missing features in the Streams API is the "partition by" transformation, for example as defined in Clojure. Say I want to reproduce Hibernate's fetch join: I want to issue a single SQL SELECT statement to receive this kind of objects from the result:
class Family {
String surname;
List<String> members;
}
I issue:
SELECT f.name, m.name
FROM Family f JOIN Member m on m.family_id = f.id
ORDER BY f.name
and I retrieve a flat stream of (f.name, m.name) records. Now I need to transform it into a stream of Family objects, with a list of its members inside. Assume I already have a Stream<ResultRow>; now I need to transform it into a Stream<List<ResultRow>> and then act upon that with a mapping transformation which turns it into a Stream<Family>.
The semantics of the transformation are as follows: keep collecting the stream into a List for as long as the provided discriminator function keeps returning the same value; as soon as the value changes, emit the List as an element of the output stream and start collecting a new List.
I hope to be able to write this kind of code (I already have the resultStream method):
Stream<ResultRow> dbStream = resultStream(queryBuilder.createQuery(
"SELECT f.name, m.name"
+ " FROM Family f JOIN Member m on m.family_id = f.id"
+ " ORDER BY f.name"));
Stream<List<ResultRow> partitioned = partitionBy(r -> r.string(0), dbStream);
Stream<Family> = partitioned.map(rs -> {
Family f = new Family(rs.get(0).string(0));
f.members = rs.stream().map(r -> r.string(1)).collect(toList());
return f;
});
Needless to say, I expect the resulting stream to stay lazy (non-materialized) as I want to be able to process a result set of any size without hitting any O(n) memory limits. Without this crucial requirement I would be happy with the provided groupingBy collector.
The solution requires us to define a custom Spliterator which can be used to construct the partitioned stream. We shall need to access the input stream through its own spliterator and wrap it into ours. The output stream is then constructed from our custom spliterator.
The following Spliterator will turn any Stream<E> into a Stream<List<E>> provided a Function<E, ?> as the discriminator function. Note that the input stream must be ordered for this operation to make sense.
import java.util.*;
import java.util.Spliterators.AbstractSpliterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.Comparator.naturalOrder;
public class PartitionBySpliterator<E> extends AbstractSpliterator<List<E>> {
private final Spliterator<E> spliterator;
private final Function<? super E, ?> partitionBy;
private HoldingConsumer<E> holder;
private Comparator<List<E>> comparator;
public PartitionBySpliterator(
Spliterator<E> toWrap,
Function<? super E, ?> partitionBy
) {
super(Long.MAX_VALUE, toWrap.characteristics() & ~SIZED | NONNULL);
this.spliterator = toWrap;
this.partitionBy = partitionBy;
}
public static <E> Stream<List<E>> partitionBy(
Function<E, ?> partitionBy, Stream<E> in
) {
return StreamSupport.stream(
new PartitionBySpliterator<>(in.spliterator(), partitionBy), false);
}
#Override
public boolean tryAdvance(Consumer<? super List<E>> action) {
final HoldingConsumer<E> h;
if (holder == null) {
h = new HoldingConsumer<>();
if (!spliterator.tryAdvance(h)) {
return false;
}
holder = h;
} else {
h = holder;
}
final ArrayList<E> partition = new ArrayList<>();
final Object partitionKey = partitionBy.apply(h.value);
boolean didAdvance;
do {
partition.add(h.value);
}
while ((didAdvance = spliterator.tryAdvance(h))
&& Objects.equals(partitionBy.apply(h.value), partitionKey));
if (!didAdvance) {
holder = null;
}
action.accept(partition);
return true;
}
static final class HoldingConsumer<T> implements Consumer<T> {
T value;
#Override
public void accept(T value) {
this.value = value;
}
}
#Override
public Comparator<? super List<E>> getComparator() {
final Comparator<List<E>> c = this.comparator;
return c != null ? c : (this.comparator = comparator());
}
private Comparator<List<E>> comparator() {
#SuppressWarnings({"unchecked", "rawtypes"})
final Comparator<? super E> innerComparator =
Optional.ofNullable(spliterator.getComparator())
.orElse((Comparator) naturalOrder());
return (left, right) -> {
final int c = innerComparator.compare(left.get(0), right.get(0));
return c != 0 ? c : innerComparator.compare(
left.get(left.size() - 1), right.get(right.size() - 1));
};
}
}
For those of you who just want to partition a stream, there are mappers and collectors for that.
class Person {
String surname;
String forename;
public Person(String surname, String forename) {
this.surname = surname;
this.forename = forename;
}
#Override
public String toString() {
return forename;
}
}
class Family {
String surname;
List<Person> members;
public Family(String surname, List<Person> members) {
this.surname = surname;
this.members = members;
}
#Override
public String toString() {
return "Family{" + "surname=" + surname + ", members=" + members + '}';
}
}
private void test() {
String[][] data = {
{"Kray", "Ronald"},
{"Kray", "Reginald"},
{"Dors", "Diana"},};
// Their families.
Stream<Family> families = Arrays.stream(data)
// Build people
.map(a -> new Person(a[0], a[1]))
// Collect into a Map<String,List<Person>> as families
.collect(Collectors.groupingBy(p -> p.surname))
// Convert them to families.
.entrySet().stream()
.map(p -> new Family(p.getKey(), p.getValue()));
families.forEach(f -> System.out.println(f));
}
It can be done by collapse with StreamEx
StreamEx.of(queryBuilder.createQuery(
"SELECT f.name, m.name"
+ " FROM Family f JOIN Member m on m.family_id = f.id"
+ " ORDER BY f.name"))
.collapse((a, b) -> a.string(0).equals(b.string(0)), Collectors.toList())
.map(l -> new Family(l.get(0).string(0), StreamEx.of(l).map(r -> r.string(1)).toList()))
.forEach(System.out::println);
How can I find an object, Carnet, in a ArrayList<Carnet> knowing its property codeIsin.
List<Carnet> listCarnet = carnetEJB.findAll();
public class Carnet {
private String codeTitre;
private String nomTitre;
private String codeIsin;
// Setters and getters
}
In Java8 you can use streams:
public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsIn) {
return listCarnet.stream().filter(carnet -> codeIsIn.equals(carnet.getCodeIsin())).findFirst().orElse(null);
}
Additionally, in case you have many different objects (not only Carnet) or you want to find it by different properties (not only by cideIsin), you could build an utility class, to ecapsulate this logic in it:
public final class FindUtils {
public static <T> T findByProperty(Collection<T> col, Predicate<T> filter) {
return col.stream().filter(filter).findFirst().orElse(null);
}
}
public final class CarnetUtils {
public static Carnet findByCodeTitre(Collection<Carnet> listCarnet, String codeTitre) {
return FindUtils.findByProperty(listCarnet, carnet -> codeTitre.equals(carnet.getCodeTitre()));
}
public static Carnet findByNomTitre(Collection<Carnet> listCarnet, String nomTitre) {
return FindUtils.findByProperty(listCarnet, carnet -> nomTitre.equals(carnet.getNomTitre()));
}
public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsin) {
return FindUtils.findByProperty(listCarnet, carnet -> codeIsin.equals(carnet.getCodeIsin()));
}
}
You can't without an iteration.
Option 1
Carnet findCarnet(String codeIsIn) {
for(Carnet carnet : listCarnet) {
if(carnet.getCodeIsIn().equals(codeIsIn)) {
return carnet;
}
}
return null;
}
Option 2
Override the equals() method of Carnet.
Option 3
Storing your List as a Map instead, using codeIsIn as the key:
HashMap<String, Carnet> carnets = new HashMap<>();
// setting map
Carnet carnet = carnets.get(codeIsIn);
If you use Java 8 and if it is possible that your search returns null, you could try using the Optional class.
To find a carnet:
private final Optional<Carnet> findCarnet(Collection<Carnet> yourList, String codeIsin){
// This stream will simply return any carnet that matches the filter. It will be wrapped in a Optional object.
// If no carnets are matched, an "Optional.empty" item will be returned
return yourList.stream().filter(c -> c.getCodeIsin().equals(codeIsin)).findAny();
}
Now a usage for it:
public void yourMethod(String codeIsin){
List<Carnet> listCarnet = carnetEJB.findAll();
Optional<Carnet> carnetFound = findCarnet(listCarnet, codeIsin);
if(carnetFound.isPresent()){
// You use this ".get()" method to actually get your carnet from the Optional object
doSomething(carnetFound.get());
}
else{
doSomethingElse();
}
}
To find an object in an ArrayList by the property, We can use a function like this:
To find all the objects with a specific codeIsIn:
public static List<Item> findBycodeIsin(Collection<Carnet> listCarnet, String codeIsIn) {
return items.stream().filter(item -> codeIsIn.equals(item.getCodeIsIn()))
.collect(Collectors.toList());
}
To find a Single item (If the codeIsIn is unique for each object):
public static Carnet findByCodeIsIn(Collection<Carnet> listCarnet, String codeIsIn) {
return listCarnet.stream().filter(carnet-> codeIsIn.equals(carnet.getCodeIsIn()))
.findFirst().orElse(null);
}
Here is a solution using Guava
private User findUserByName(List<User> userList, final String name) {
Optional<User> userOptional =
FluentIterable.from(userList).firstMatch(new Predicate<User>() {
#Override
public boolean apply(#Nullable User input) {
return input.getName().equals(name);
}
});
return userOptional.isPresent() ? userOptional.get() : null; // return user if found otherwise return null if user name don't exist in user list
}
Here is another solution using Guava in Java 8 that returns the matched element if one exists in the list. If more than one elements are matched then the collector throws an IllegalArgumentException. A null is returned if there is no match.
Carnet carnet = listCarnet.stream()
.filter(c -> c.getCodeIsin().equals(wantedCodeIsin))
.collect(MoreCollectors.toOptional())
.orElse(null);
Following with Oleg answer, if you want to find ALL objects in a List filtered by a property, you could do something like:
//Search into a generic list ALL items with a generic property
public final class SearchTools {
public static <T> List<T> findByProperty(Collection<T> col, Predicate<T> filter) {
List<T> filteredList = (List<T>) col.stream().filter(filter).collect(Collectors.toList());
return filteredList;
}
//Search in the list "listItems" ALL items of type "Item" with the specific property "iD_item=itemID"
public static final class ItemTools {
public static List<Item> findByItemID(Collection<Item> listItems, String itemID) {
return SearchTools.findByProperty(listItems, item -> itemID.equals(item.getiD_Item()));
}
}
}
and similarly if you want to filter ALL items in a HashMap with a certain Property
//Search into a MAP ALL items with a given property
public final class SearchTools {
public static <T> HashMap<String,T> filterByProperty(HashMap<String,T> completeMap, Predicate<? super Map.Entry<String,T>> filter) {
HashMap<String,T> filteredList = (HashMap<String,T>) completeMap.entrySet().stream()
.filter(filter)
.collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue()));
return filteredList;
}
//Search into the MAP ALL items with specific properties
public static final class ItemTools {
public static HashMap<String,Item> filterByParentID(HashMap<String,Item> mapItems, String parentID) {
return SearchTools.filterByProperty(mapItems, mapItem -> parentID.equals(mapItem.getValue().getiD_Parent()));
}
public static HashMap<String,Item> filterBySciName(HashMap<String,Item> mapItems, String sciName) {
return SearchTools.filterByProperty(mapItems, mapItem -> sciName.equals(mapItem.getValue().getSciName()));
}
}
For finding objects which are meaningfully equal, you need to override equals and hashcode methods for the class. You can find a good tutorial here.
http://www.thejavageek.com/2013/06/28/significance-of-equals-and-hashcode/