Since Java 8, there are some standard options to do this in JDK:
Collection<E> in = ...
Object[] mapped = in.stream().map(e -> doMap(e)).toArray();
// or
List<E> mapped = in.stream().map(e -> doMap(e)).collect(Collectors.toList());
See java.util.Collection.stream() and java.util.stream.Collectors.toList().
Java: is there a map function? - Stack Overflow
Lambda expression java 8 map method - Stack Overflow
Pass Java 8 streaming map function as a parameter - Stack Overflow
java - what does java8 stream map do here? - Stack Overflow
Videos
Since Java 8, there are some standard options to do this in JDK:
Collection<E> in = ...
Object[] mapped = in.stream().map(e -> doMap(e)).toArray();
// or
List<E> mapped = in.stream().map(e -> doMap(e)).collect(Collectors.toList());
See java.util.Collection.stream() and java.util.stream.Collectors.toList().
There is no notion of a function in the JDK as of java 6.
Guava has a Function interface though and the
Collections2.transform(Collection<E>, Function<E,E2>)
method provides the functionality you require.
Example:
// example, converts a collection of integers to their
// hexadecimal string representations
final Collection<Integer> input = Arrays.asList(10, 20, 30, 40, 50);
final Collection<String> output =
Collections2.transform(input, new Function<Integer, String>(){
@Override
public String apply(final Integer input){
return Integer.toHexString(input.intValue());
}
});
System.out.println(output);
Output:
[a, 14, 1e, 28, 32]
These days, with Java 8, there is actually a map function, so I'd probably write the code in a more concise way:
Collection<String> hex = input.stream()
.map(Integer::toHexString)
.collect(Collectors::toList);
The function Function<? super T,? extends R> mapper of the map method basically represents any function taking one parameter and returning a value so in this specific case the lambda p -> new Student(p.getId(), p.getName()) is a function taking a Person p and returning a Student hence fits into that perfectly.
To look at it another way, the lambda is equivalent to:
.map(new Function<Person, Student>() {
@Override
public Student apply(Person p) {
return new Student(p.getId(), p.getName());
}
})
You can write like this Function<Person,Student> function = p -> new Student(p.getId(), p.getName())
so as you see it is represent a function.
personList.stream().filter(p -> p.getPersonType().equals("student"))
.map(function::apply) // p -> function.apply(p)
.collect(Collectors.toList());
You can do it with a simple function that accepts String and a Function<String, T> that will convert every string element using this function. The good news is that this function may return any type you want: Integer, Double, BigDecimal, String or any other type you want. In below example I use a method reference like:
Integer::valueOfto convert elements toIntegervaluesDouble::valueOfto convert elements toDoublevaluesString::valueOfto convert elements toStringvalues
Consider following example:
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ParsingStringTest {
public static void main(String[] args) {
String str = "1, , 3, 4, 5, , 7, sasd, aaa, 0";
List<Double> doubles = parse(str, Double::valueOf);
List<Integer> integers = parse(str, Integer::valueOf);
List<String> strings = parse(str, String::valueOf);
System.out.println(doubles);
System.out.println(integers);
System.out.println(strings);
Double[] array = doubles.toArray(new Double[doubles.size()]);
System.out.println(Arrays.toString(array));
}
public static <T> List<T> parse(String str, Function<String, T> parseFunction) {
return Arrays.stream(str.split(","))
.filter(s -> !s.isEmpty())
.map(s -> {
try {
return parseFunction.apply(s.trim());
} catch (Exception e) {}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}
Console output for following example is:
[1.0, 3.0, 4.0, 5.0, 7.0, 0.0]
[1, 3, 4, 5, 7, 0]
[1, , 3, 4, 5, , 7, sasd, aaa, 0]
[1.0, 3.0, 4.0, 5.0, 7.0, 0.0]
I hope it helps.
There is a way, but you wouldn't be working with primitives any more, because generics in Java doesn't support primitive types. Instead, you can use Integer and Double wrapper types:
public static <T> T[] convert(
String test,
Function<String, T> parser,
boolean condition,
T ifConditionTrue,
T ifConditionFalse,
IntFunction<T[]> arrayGenerator) {
return Arrays.stream(test.split(","))
.map(x -> {
if (StringUtils.isEmpty(x)) {
return condition ? ifConditionTrue : ifConditionFalse;
}
return parser.apply(x);
})
.toArray(arrayGenerator);
}
This method can be used as follows:
Integer[] ints = convert("1, ,3", Integer::parseInt, true, -1, 0, Integer[]::new);
strings.stream().map(s->map.put(s, s));
does nothing, since the stream pipeline is not processed until you execute a terminal operation. Therefore the Map remains empty.
Adding a terminal operation to the stream pipeline will cause map.put(s, s) to be executed for each element of the Stream required by the terminal operation (some terminal operations require just one element, while others require all elements of the Stream).
On the other hand, the second stream pipeline:
strings.stream().forEach(s->map.put(s, s));
ends with a terminal operation - forEach - which is executed for each element of the Stream.
That said, both snippets are misusing Streams. In order to populate a Collection or a Map based on the contents of the Stream, you should use collect(), which can create a Map or a Collection and populate it however you like. forEach and map have different purposes.
For example, to create a Map:
List<String> strings = Lists.newArrayList("1", "2");
Map<String, String> map = strings.stream()
.collect(Collectors.toMap(Function.identity(),
Function.identity()));
System.out.println(map);
The difference is this:
- The idea of
forEach()is to "work" on each element of the underlying collection (by having a side effect) whereas map()is about applying a method on each object and putting the result of that into a new stream
That is also the reason why your stream().map() doesn't result in something - because you throw away the new stream created by the map() call!
In that sense, the signatures of the two methods tell you that:
void forEach(BiConsumer<? super K,? super V> action)
Performs the given action for each entry in this map until all entries have been processed
versus
<R> Stream<R> map(Function<? super T,? extends R> mapper)
Returns a stream consisting of the results of applying the given function to the elements of this stream.
And for the record: only map() is a stream method - forEach() exists for both, streams and Collections/Iterables.