I have a class
class Foo{ String name; // setter, getter }
which just has a default constructor.
Then, I am trying to create a List of Foo
from some string:
Arrays.stream(fooString.split(",")) .map(name -> { Foo x = new Foo(); x.setName(name); return x; }).collect(Collectors.toList()));
Since there is no constructor which takes a name, I can't simply use a method reference. Of course, I could extract those three lines, with the constructor call and the setter, into a method but is there any better or concise way to do that? (without changing Foo
, which is a generated file)
Java 8 Stream's map method is intermediate operation and consumes single element forom input Stream and produces single element to output Stream. It simply used to convert Stream of one type to another. Let's see method signature of Stream's map method.
A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. The features of Java stream are – A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.
Converting only the Value of the Map<Key, Value> into Stream: This can be done with the help of Map. values() method which returns a Set view of the values contained in this map. In Java 8, this returned set can be easily converted into a Stream of key-value pairs using Set. stream() method.
With Java 8, Collection interface has two methods to generate a Stream. stream() − Returns a sequential stream considering collection as its source. parallelStream() − Returns a parallel Stream considering collection as its source.
If this happens repeatedly, you may create a generic utility method handling the problem of constructing an object given one property value:
public static <T,V> Function<V,T> create( Supplier<? extends T> constructor, BiConsumer<? super T, ? super V> setter) { return v -> { T t=constructor.get(); setter.accept(t, v); return t; }; }
Then you may use it like:
List<Foo> l = Arrays.stream(fooString.split(",")) .map(create(Foo::new, Foo::setName)).collect(Collectors.toList());
Note how this isn’t specific to Foo
nor its setName
method:
List<List<String>> l = Arrays.stream(fooString.split(",")) .map(create(ArrayList<String>::new, List::add)).collect(Collectors.toList());
By the way, if fooString
gets very large and/or may contain lots of elements (after splitting), it might be more efficient to use Pattern.compile(",").splitAsStream(fooString)
instead of Arrays.stream(fooString.split(","))
.
No, there is no better way.
The only alternative is, like you said in your question, to create a factory for Foo
objects:
public class FooFactory { public static Foo fromName(String name) { Foo foo = new Foo(); foo.setName(name); return foo; } }
and use it like this:
Arrays.stream(fooString.split(",")).map(FooFactory::fromName).collect(toList());
If there are a lot of names to split, you can use Pattern.compile(",").splitAsStream(fooString)
(and store the compiled pattern in a constant to avoid recreation) instead of Arrays.stream(fooString.split(","))
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With