You could use the map() feature of the stream to convert each User instance in your list to a UserWithAge instance.
List<User> userList = ... // your list
List<UserWithAge> usersWithAgeList = userList.stream()
.map(user -> {
// create UserWithAge instance and copy user name
UserWithAge userWithAge = new UserWithAge();
userWithAge.setName(user.getName());
userWithAge.setAge(27);
return userWithAge;
})
.collect(Collectors.toList()); // return the UserWithAge's as a list
Answer from Floern on Stack OverflowYou could use the map() feature of the stream to convert each User instance in your list to a UserWithAge instance.
List<User> userList = ... // your list
List<UserWithAge> usersWithAgeList = userList.stream()
.map(user -> {
// create UserWithAge instance and copy user name
UserWithAge userWithAge = new UserWithAge();
userWithAge.setName(user.getName());
userWithAge.setAge(27);
return userWithAge;
})
.collect(Collectors.toList()); // return the UserWithAge's as a list
While you could do this, You should not do like this.
List<UserWithAge> userWithAgeList = new ArrayList<UserWithAge>();
userList.stream().forEach(user -> {
UserWithAge userWithAge = new UserWithAge();
userWithAge.setName(user.getName());
userWithAge.setAge(27);
userWithAgeList.add(userWithAge);
});
You can use anyMatch to find the first element matching one of your conditions and terminate. Use side effects for calling the processing methods :
boolean found =
names.stream()
.anyMatch (name -> {
if (name.equals(a)) {
doSomething();
return true;
} else if (name.equals(b)) {
doSomethingElse ();
return true;
} else if (name.equals(c)) {
doSomethingElseElse ();
return true;
} else {
return false;
}
}
);
Pretty ugly, but does what you asked in a single iteration.
The answer by Eran is definitely the straightforward way of performing the search. However, I would like to propose a slightly different approach:
private static final Map<String, Runnable> stringToRunnable = new HashMap<>();
{
stringToRunnable.put("a", this::doSomething);
stringToRunnable.put("b", this::doSomethingElse);
stringToRunnable.put("c", this::doSomethingElseElse);
}
public static void main(String[] args) {
List<String> names = Arrays.asList("1", "2", "b", "a");
names.stream()
.filter(stringToRunnable::containsKey)
.findFirst()
.ifPresent(name -> stringToRunnable.get(name).run());
}
private void doSomethingElseElse() {
}
private void doSomethingElse() {
}
public void doSomething() {
}
The part that does the job is the code below, but I added it to a main() function assuming a, b, and c are strings. However, the idea would work with any datatype.
names.stream()
.filter(stringToRunnable::containsKey)
.findFirst()
.ifPresent(name -> stringToRunnable.get(name).run());
The idea is to keep a map of keys and Runnables. By having Runnable as value it is possible to define a void method reference without parameters. The stream first filters away all values not present in the map, then finds the first hit, and executes its method if found.
public static void main(String... args) {
List<String> list1 = Arrays.asList("Hello", "World!");
List<String> list2 = Arrays.asList("Hi", "there");
List<String> list3 = Arrays.asList("Help Me");
List<String> list4 = concat(list1, list2, list3); //you can add as many lists as you like here
System.out.println(list4);
}
private static List<String> concat(List<String>... lists) {
return Stream.of(lists)
.flatMap(List::stream)
.collect(Collectors.toList());
}
Output
[Hello, World!, Hi, there, Help Me]
Try this create a multiple dimension array out of List, from there you can use stream too
Customdto[][] listArray = new Customdto[][]{ l1.toArray(new Customdto[]{})
, l2.toArray(new Customdto[]{}), l3.toArray(new Customdto[]{})};
int size = listArray[0].length > listArray[1].length && listArray[0].length > listArray[2].length ?listArray[0].length
:(listArray[1].length > listArray[2].length ? listArray[1].length:listArray[2].length);
for(int i = 0; i <size;i++)
{
if(listArray[0].length >i && listArray[1].length >i && listArray[2].length >i &&
listArray[0][i].equals(listArray[1][i])
&& listArray[1][i].getCalendarDate().equals(listArray[2][i].getCalendarDate()))
{
l4.add(listArray[1][i]);
}else
{
l4.add(null);
}
}
Tried with Below Input
List<Customdto> l1 = new ArrayList<Customdto>();
List<Customdto> l2 = new ArrayList<Customdto>();
List<Customdto> l3 = new ArrayList<Customdto>();
List<Customdto> l4 = new ArrayList<Customdto>();
l1.add(new Customdto(1));
l1.add(new Customdto(2));
l1.add(new Customdto(3));
l1.add(new Customdto(4));
l2.add(new Customdto(1));
l2.add(new Customdto(2));
l2.add(new Customdto(3));
l3.add(new Customdto(1));
l3.add(new Customdto(2));
Output is
[Customdto [id=1], Customdto [id=2], null, null]
Instead of using a forEach just use streams from the beginning:
List<PersonWrapper> wrapperList = jrList.stream()
.flatMap(jr -> seniorList.stream()
.filter(sr -> jr.getName().equals(sr.getName()))
.map(sr -> new PersonWrapper(jr, sr))
)
.collect(Collectors.toList());
By using flatMap you can flatten a stream of streams (Stream<Stream<PersonWrapper>>) into a single stream (Stream<PersonWrapper>)
If you can't instantiate wrapperList by yourself or really need to append to it. You can alter above snippet to following:
List<PersonWrapper> wrapperList = new ArrayList<>();
jrList.stream()
.flatMap(jr -> seniorList.stream()
.filter(sr -> jr.getName().equals(sr.getName()))
.map(sr -> new PersonWrapper(jr, sr))
)
.forEach(wrapperList::add);
While Lino's answer is certainly correct. I would argue that if a given person object in jrList can only ever have one corresponding match in seniorList maximum, in other words, if it's a 1-1 relationship then you can improve upon the solution given by Lino by finding the first match as follows:
List<PersonWrapper> resultSet = jrList.stream()
.map(p -> seniorList.stream()
.filter(sr -> p.getName().equals(sr.getName()))
.findFirst()
.map(q -> new PersonWrapper(p, q))
.get())
.collect(Collectors.toList());
or if there is no guarantee that each person in jrList will have a corresponding match in seniorList then change the above query to:
List<PersonWrapper> resultSet = jrList.stream()
.map(p -> seniorList.stream()
.filter(sr -> p.getName().equals(sr.getName()))
.findFirst()
.map(q -> new PersonWrapper(p, q))
.orElse(null))
.filter(Objects::nonNull)
.collect(Collectors.toList());
The difference is that now instead of calling get() on the result of findFirst() we provide a default with orElse in case findFirst cannot find the corresponding value and then we filter the null values out in the subsequent intermediate operation as they are not needed.
There are multiple ways you could change your snippet here to use Java-8 Streams. Here an overview of a few straight out of my head.
List<IDWrapper> list = IntStream.range( 0, 20 ).mapToObj( IDWrapper::new ).collect( Collectors.toList() );
List<String> details = list.stream().map( IDWrapper::getId ).map( this::getDetails ).collect( Collectors.toList() );
List<String> details2 = list.stream().map( item -> item.getId() ).map( id -> getDetails( id ) ).collect( Collectors.toList() );
List<String> details3 = list.stream().map( item -> getDetails( item.getId() ) ).collect( Collectors.toList() );
Let's break them down and explain their differences a bite more.
1.
List<String> details = list.stream().map( IDWrapper::getId ).map( this::getDetails ).collect( Collectors.toList() );
This one uses MethodReferences to pass the desired functions down the Stream#map(Function) method. It can be read as 'map the items, which are IDWrapper-Objects and do it by calling IDWrapper#getId() on every object and put the resulting items (integer values in this case) back into the stream'. Afterwards another call to Stream#map(Function) is done but this time the object to operate on is 'this' (my dummy class i created for the example) and call the #getDetails(int) method on this class.
2.
List<String> details2 = list.stream().map( item -> item.getId() ).map( id -> getDetails( id ) ).collect( Collectors.toList() );
This one is quite simply equal to 1. but using usual lambda expression to achieve the same.
3.
List<String> details3 = list.stream().map( item -> getDetails( item.getId() ) ).collect( Collectors.toList() );
In this case we're defining the function as a lamda and simply chaining the method class.
As mentioned before there are lots of other possibilities, but here are an education few. Hope I could help you understanding streams a little bit better.
Something like:
Map<String,Integer> m =
list.stream()
.collect(Collectors.toMap(e -> e.getUser, // key extractor
e -> getDetail(e.getId()).getBody().getData() // value extractor
)
);
----EDIT----
Ho ho... This is exactly Holger's comment. Give credit where credit is due.