3

I have an array of ints that I want to use to instantiate a array or list of objects. In my case, the old-fashoned way to do it would be:

int[] layer_sizes = {784, 500, 10};
Layer[] layers = new Layer[layer_sizes.length];
for (int i=0; i<layer_sizes.length; i++)
    layers[i] = new Layer(layer_sizes[i]);

But now I see Java 8 has all these fancy streams. I now want to do something like Python's list comprehensions:

List<Layer> layers = Stream.of(layer_sizes).map(size -> Layer(size));

But it doesn't let me do that, and I'm not sure why... The message it gives is

incompatible types: no instance(s) of type variable(s) R exist so that Stream<R> comforms to List<Layer> where R, T are type variables....

Is there a way to use Streams to construct an array of objects in one line?

EDIT: Not a duplicate of previous question, because it turns out that there're some peculiarities of making streams from primitives.

Conclusion

Thank you Sam Sun and Eran. The line I ended up using was this:

Layer[] layers = Arrays.stream(layer_sizes).boxed().map(Layer::new).toArray(Layer[]::new);

Whatever boxed() is, you need it, unless you declare layer_sizes as an Integer instead of int.

P.S. If the java developers are reading this, it would be amazing for Java 9 or whatever's next to have something like

Layer[] layers = {new Layer(size) for (size:layer_sizes)}  // OR at least:
Layer[] layers = Stream.of(layer_sizes).map(Layer::new).toArray()
Community
  • 1
  • 1
Peter
  • 12,274
  • 9
  • 71
  • 86
  • Possible duplicate of [How to Convert a Java 8 Stream to an Array?](http://stackoverflow.com/questions/23079003/how-to-convert-a-java-8-stream-to-an-array) – Aaditya Gavandalkar Jan 05 '16 at 13:06
  • Similar: http://www.programcreek.com/2014/01/convert-stream-to-array-in-java-8/ – Aaditya Gavandalkar Jan 05 '16 at 13:07
  • For future reference, `boxed` converts the IntStream, a class for providing a stream of `ints`, to an instanceof the interface `Stream` with a type of `Integer`. Basically, you're going from a stream of `int` to a stream of `Integer`, and you need that because generics behave weirdly with primitive types (and especially arrays) – samczsun Jan 05 '16 at 14:14

2 Answers2

4

You are missing two things - collecting the Stream into a List and invoking the Layer constructor (you are missing the new keyword) :

List<Layer> layers = 
    IntStream.of(layer_sizes)
             .mapToObj(size -> new Layer(size))
             .collect(Collectors.toList());

And if you wish your output to be an array instead of a List, call toArray instead of collect.

EDIT :

I just realized that Stream.of, when passed an int[], would produce a Stream<int[]>, not a Stream<Integer>. Therefore, you should use IntStream, which handles primitive int elements.

The alternative is to replace the input int[] layer_sizes = {784, 500, 10}; with Integer[] layer_sizes = {784, 500, 10};.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • Thanks... my bad on forgetting new... but it still doesn't work. I'm now getting the error `Inference variable T has incompatible bounds: equality constraints: Layer, lower bounds: Object` – Peter Jan 05 '16 at 13:22
  • @Peter What did you try? `collect` or `toArray`? If `toArray()`, try `toArray(Layer[]::new)`. – Eran Jan 05 '16 at 13:28
  • Both. `toArray(Layer[]::new)` almost worked but now oddly, it complains about the "size" variable being fed into Layer, saying `int[] cannot be converted into int`. I don't see why it should think size is an int[]. – Peter Jan 05 '16 at 13:31
  • @Peter Oh, I see the problem now. Your `int[]` is converted to a `Stream` and not `Stream`. You can either use an `Integer[]`, or use `IntStream.of` and `mapToObj`. – Eran Jan 05 '16 at 13:33
3

Eran's answer has the general idea of what to do, but is missing a few key details.

Using Stream.of on an int[] will result in a Stream<int[]>; one of the magical artifacts of Java.

Instead, you should use Arrays.stream or IntStream.of to get a IntStream (remember, primitives can't be a parameter).

For the map operation, you can use a method reference to Layer::new.

This all boils down to this new snippit

List<Layer> layers = IntStream.of(layer_sizes).boxed().map(Layer::new).collect(Collectors.toList());
samczsun
  • 1,014
  • 6
  • 16