Reputation: 63
i have class A {int sNo; String name;}
with valid constructor.
i need to trim name and sort on the basis of name using stream API.
public class Test1 {
public static void main(String[] args) {
ArrayList<A> l = new ArrayList();
l.add(new A(1, " 1name "));
l.add(new A(7, " 3name "));
l.add(new A(6, ""));
l.add(new A(5, " 2name "));
l.add(new A(4, " 5name "));
l.add(new A(2, ""));
List<String> i = l.stream()
.filter(s -> !s.name.isEmpty())
.map(s -> s.name.trim())
.sorted()
.collect(Collectors.toList());
System.out.println(i);
}
}
it is returning only name in sorted order
[, 1name, 2name, 3name, 5name]
but i need entire object.
i know s -> s.name.trim()
is the reason its storing name only,
how can apply operation on particular filed but store entire object.
Upvotes: 3
Views: 2066
Reputation: 374
Just for fun, not because it's particularly nice or even recommended. One could accomplish that also with anonymous Objects:
List<A> i = l.stream()
.filter(s -> !s.name.isEmpty())
.map(s -> new Object() {A a = s; String name = s.name.trim();})
.sorted(Comparator.comparing(o -> o.name))
.map(o -> o.a)
.collect(Collectors.toList());
Not every compiler will be happy about this (javac
will), but it's valid Java code.
Upvotes: 2
Reputation: 124646
it is returning only name in sorted order [...] but i need entire object.
The .map(s -> s.name.trim())
step transforms your stream of A
into a stream of String
. That's why you're left with strings, instead of entire objects.
If you want a sorted list of objects, then the result should be in a List<A>
and not in a List<String>
.
To sort a list of objects by a field, you can pass a Comparator
to sorted
.
List<A> result = l.stream()
.filter(s -> !s.name.isEmpty())
.map(s -> new A(s.sNo, s.name.trim()))
.sorted(Comparator.comparing(a -> a.name))
.collect(Collectors.toList());
If you don't want to create a new A
with the trimmed name,
but want to modify the original object (though I seriously doubt that),
you can replace the map
step with peek
and modify the object:
.peek(s -> s.name = s.name.trim())
However, note that as @Mustafa pointed out, peek
is intended only for debugging. And in fact if you want to modify the underlying objects, it would be better to that in a step separate from the filtering and sorting,
as it is a logically unrelated step anyway (it looks like data cleaning).
That step can be implemented using forEach
.
If you don't actually need to trim the name (thanks @Andreas for the hint),
only for the purpose of sorting,
then you can drop the map
step entirely,
and write the sorted
step like this:
.sorted(Comparator.comparing(a -> a.name.trim()))
Upvotes: 1
Reputation: 16224
When you use the map
function you are converting all your objects into strings, so instead of map, use for each to transform the strings inside the object but not returning a lists of strings :
class A {
int sNo;
String name;
public int getName(){ return name}
public void setName(String name){ this.name = name;}
}
i.forEach(s -> s.setName(s.getName().trim()));
List<A> i = l.stream()
.filter(s -> !s.name.isEmpty())
.sorted(Comparator.comparing(a -> a.name))
.collect(Collectors.toList());
Upvotes: 1