Can anybody explain to me why the following code is not working?
I was trying to get a feel for the new features of Java8 and solved the BerlinClock Kata. During this I had to parse a String in the format "hh:mm:ss"
- I wanted to use streams and wrote the following piece of code.
import java.util.Arrays;
private Integer[] parseTime (String time){
Integer[] hhmmss = (Integer[]) Arrays.stream(time.split(":"))
.map(s->Integer.parseInt(s)).toArray();
return hhmmss;
}
but the runtime system (I think) is complaining that the explicit type cast (Integer[])
cannot be done.
As far as I understand it the Arrays.stream(time.split(":"))
part returns a Stream<String>
, then map(s->Integer.parseInt(s))
converts this to Stream<Integer>
, then toArray()
produces an Object[]
. Now a type cast to Integer[]
should be possible as the intermediate stream was had an Integer
type-parameter.
Note that I know how to solve this problem without type cast by using
int[] hhmmss= Arrays.stream(time.split(":")
.mapToInt(Integer::parseInt).toArray();
and changing the type signature accordingly to int[] parseTime
.
But I do not understand why there is a problem in the type-cast.
Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.
Differences between a Stream and a Collection: A stream does not store data. An operation on a stream does not modify its source, but simply produces a result. Collections have a finite size, but streams do not.
The short version basically is, if you have a small list; for loops perform better, if you have a huge list; a parallel stream will perform better. And since parallel streams have quite a bit of overhead, it is not advised to use these unless you are sure it is worth the overhead.
In Java8 Streams, performance is achieved by parallelism, laziness, and using short-circuit operations, but there is a downside as well, and we need to be very cautious while choosing Streams, as it may degrade the performance of your application.
For the first case, Stream#map()
method will give you a Stream<Integer>
, and then Stream#toArray()
returns an Object[]
, which you need to cast to Integer[]
. But at runtime, this cast may fail, if internally an Object[]
is created instead of an Integer[]
, which is the case here. The source code of toArray()
method for this stream looks like this:
@Override
public final Object[] toArray() {
return toArray(Object[]::new);
}
And you can't cast an Object[]
to an Integer[]
reference.
You can solve this issue by using Stream#toArray(IntFunction)
instead, and then you wouldn't need a cast:
private Integer[] parseTime (String time){
Integer[] hhmmss = Arrays.stream(time.split(":"))
.map(s->Integer.valueOf(s))
.toArray(Integer[]::new);
return hhmmss;
}
In second case however, Stream#mapToInt()
method gives you an IntStream
, and IntStream#toArray()
returns an int[]
, and hence no casting required there.
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