I was trying to write a mkString
function in Java8, a la Scala's useful mkString
and ran into 2 issues that I could use some help on:
I am unable to make the first argument of mkString
a generic Collection reference like Collection<Object> c
and have invokers call with ANY type of collection.
Unable to reference the returned result of reduce()
in-line to access the result's length to remove the extra leading separator.
Here's the code :
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(mkString(numbers, ","));
}
public static String mkString(Collection<Integer> c, String sep) {
return c.stream()
.map(e -> String.valueOf(e))
.reduce("", (a, b) -> a + sep + b)
.substring(1, <<>>.length);
}
In Java, reducing is a terminal operation that aggregates a stream into a type or a primitive type. Java 8 provides Stream API contains set of predefined reduction operations such as average(), sum(), min(), max(), and count(). These operations return a value by combining the elements of a stream.
Reducing is the repeated process of combining all elements. reduce operation applies a binary operator to each element in the stream where the first argument to the operator is the return value of the previous application and second argument is the current stream element.
identity : Like the Stream. reduce operation, the identity element is both the initial value of the reduction and the default result if there are no elements in the stream. In this example, the identity element is 0 ; this is the initial value of the sum of ages and the default value if no members exist.
A reduction is a terminal operation that aggregates a stream into a type or a primitive. The Java 8 Stream API contains a set of predefined reduction operations, such as average , sum , min , max , and count , which return one value by combining the elements of a stream.
Note that if you're doing this not for self-education but to actually use it in some production code, you might want to consider the built-in Collectors.joining
collector:
String result = numbers.stream()
.map(Object::toString)
// or
// .map(x -> x.toString()) // exactly the same
// or
// .map(String::valueOf) // handles nulls by turning them to the string "null"
.collect(Collectors.joining(","));
It has several overloads, similar to Scala's mkString
. Still, this collector only accepts CharSequence
s, so you need to convert your values to strings explicitly as a separate map
step.
Additionally, there is the String.join
method, which also works for a collection of CharSequence
s. If you specifically have one of those (e.g. List<String>
), it might be more convenient to use this method rather than converting the collection to a stream first:
List<String> strings = ...;
String result = String.join(",", strings);
// vs
String result = strings.stream().collect(Collectors.joining(","))
If I remember my java correctly, you can declare the argument type as Collection<?>
to be able to pass a collection of any objects.
As to biting the separator off, I think, just .substring(1)
will do what you want.
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