3

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.

1
  • thanks @janos for your reply , yes its working fine but i have a small doubt. s -> new A(s.sNo, s.name.trim())) is not scalable , i mean in this example class A containing 2 variables only so its ok to call its constructor, but if class A has lets say 20-30 variables then it is not wise to call constructor with all same values and just i updated 1, is there any work around?? Commented Nov 7, 2017 at 6:18

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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());

4 Comments

What do you believe forEach(s -> s.name.trim()) does? I mean, other than use up the CPU?
@Andreas you're right, forgot to set the value to update the object state
s doesn't have a setName() method. Or, if it does, it likely also has a getName() method.
@Andreas of course of course, forgot to add that important detail too, I updated again. Thanks a lot
1

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()))

4 Comments

You could just do sorted(Comparator.comparing(a -> a.name.trim())). Sure, it's not good for performance, but it works and eliminates the need for map().
@Andreas I was under the impression that OP actually wants to trim the string, not only sort on the trimmed value. But your idea is more likely, thanks, I updated my answer.
Creating new objects is better, otherwise the use of forEach is recommended over peek. According to the documentation, peek is only meant for debugging.
thanks @janos for your reply , yes its working fine but i have a small doubt. s -> new A(s.sNo, s.name.trim())) is not scalable , i mean in this example class A containing 2 variables only so its ok to call its constructor, but if class A has lets say 20-30 variables then it is not wise to call constructor with all same values and just i updated 1, is there any work around??

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.