0

I have a question concerning Java 8 and Lists. Is it possible to initialise a List easier than my code below is?

final List<List<ScheduleIntervalContainer>> weekScheduler = new ArrayList<>();

weekScheduler.add(0, new ArrayList<ScheduleIntervalContainer>());
weekScheduler.add(1, new ArrayList<ScheduleIntervalContainer>());
weekScheduler.add(2, new ArrayList<ScheduleIntervalContainer>());
weekScheduler.add(3, new ArrayList<ScheduleIntervalContainer>());
weekScheduler.add(4, new ArrayList<ScheduleIntervalContainer>());
weekScheduler.add(5, new ArrayList<ScheduleIntervalContainer>());
weekScheduler.add(6, new ArrayList<ScheduleIntervalContainer>());
Tunaki
  • 132,869
  • 46
  • 340
  • 423
quma
  • 5,233
  • 26
  • 80
  • 146

4 Answers4

10

Personally I would just use a for loop:

List<List<ScheduleIntervalContainer>> weekScheduler = new ArrayList<>();
for (int i = 0; i < 7; i++)
    weekScheduler.add(new ArrayList<>());

However, if you want a Java 8 solution:

List<List<ScheduleIntervalContainer>> weekScheduler 
        = Stream.generate(ArrayList<ScheduleIntervalContainer>::new)
                .limit(7)
                .collect(Collectors.toList());
Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
7

You can use:

List<List<ScheduleIntervalContainer>> weekScheduler = 
     IntStream.rangeClosed(0, 6).mapToObj(i -> new ArrayList<ScheduleIntervalContainer>())
                                .collect(Collectors.toList());

This will create a Stream of int values going from 0 to 6 (included), map each of those ints to a new ArrayList of your class and collect the result to a List.

Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • Your code doesn't work for me. It complains about trying to convert `ArrayList` to `ArrayList`. – Tom Oct 02 '15 at 12:11
  • 2
    @Tom Are you sure you correctly copied it? And correctly imported java.util.List? This codes compiles fine for me (JDK 1.8.0_51) – Tunaki Oct 02 '15 at 12:12
  • Yes I imported it correctly, but something else seems to be wrong on my side, because it works in [ideone](http://ideone.com/x6xBgl). – Tom Oct 02 '15 at 12:19
  • Oh, it seems to be a [bug in IDEA](https://youtrack.jetbrains.com/issue/IDEA-132717). Ok, then everything is fine here :D. – Tom Oct 02 '15 at 12:27
  • 1
    @Holger That's my answer! – Paul Boddington Oct 02 '15 at 12:32
  • @Holger It's annoying that you need to specify the type in `ArrayList::new`. I would have thought type inference could deal with that. – Paul Boddington Oct 02 '15 at 12:34
  • 2
    @Paul Boddington: unfortunately, this is a limitation by design, as explained [here](http://stackoverflow.com/a/26883991/2711488), the inference does not propagate to the *receiver* of a method invocation, hence does not work with chained invocations. It’s unclear whether and when this limitation will become lifted. – Holger Oct 02 '15 at 12:37
  • 3
    You should note that this code has an intented (though harmless) side effect. `mapToObj` expects a function which consumes an `int`. Hence, the method reference `ArrayList::new` will get resolved to the `ArrayList<>(int)` constructor here. In other words, the numbers `0` to `6` get misinterpreted as the initial capacities of the created lists. It would be cleaner to use `i->new ArrayList()` here… – Holger Oct 02 '15 at 12:43
  • @Holger I hadn't thought of that, you are absolutely right and I edited. – Tunaki Oct 02 '15 at 12:45
2

You can use a loop or an IntStream.

final List<List<ScheduleIntervalContainer>> weekScheduler = new ArrayList<>();
IntStream.range(0, 7).forEach(day -> weekScheduler.add(new ArrayList<>()));
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • never knew that this was possible 0.0 is this option java 8 exclusive? – Tom Wellbrock Oct 02 '15 at 12:17
  • @TomWellbrock Streams and lambdas were added in Java 8. I assume it will be available in Java 9 ;) – Peter Lawrey Oct 02 '15 at 12:19
  • 5
    [You shouldn't use stream API's `forEach` to change state](http://www.oracle.com/webfolder/technetwork/tutorials/moocjdk8/documents/week3/lesson-3-3.pdf). That's imperative style programming on a functional style API. You should use a combination of `map` and `collect` instead. – João Neves Oct 02 '15 at 12:27
  • @JoãoNeves Making the code overly complicated so you can pretend Java is a pure functional lanugage is one approach, but I prefer my version of simplicity. ;) – Peter Lawrey Oct 02 '15 at 12:38
  • 4
    @Peter Lawrey: it’s not simpler as you have omitted the creation of the `weekScheduler` list in your example. Letting the stream create the list doesn’t make the code more complicated. – Holger Oct 02 '15 at 12:40
  • 3
    @PeterLawrey I'm not the one saying it, you need to take it up with Oracle. If you like imperative programming that much why use the stream API in the first place? Or should we all start posting bad practices in our answers just because we feel it's better? – João Neves Oct 02 '15 at 12:41
  • @JoãoNeves It makes sense to use the Streams API when it is actually simpler than using plain imperitive style. If you end up making to code more complex than just using a loop, what is the point? – Peter Lawrey Oct 02 '15 at 12:43
  • 1
    @PeterLawrey Don't change the subject, I don't care if you prefer good old `for` loops or the Streams API but just don't mix things. If you like imperative programming stick with loops, if you like functional programming then use the Streams API but don't inject imperative programming into it, – João Neves Oct 02 '15 at 12:46
  • @Holger While I understand your point of view, some may find `ArrayList::new` more complex than `new ArrayList<>())` – Peter Lawrey Oct 02 '15 at 12:47
  • @JoãoNeves Java is one language, not a combination of pure languages. It is neither pure OOP nor functional. If you stick to the assumption that because you are using Streams, it must be functional you will be disappointed at some point. – Peter Lawrey Oct 02 '15 at 12:49
  • 2
    @Peter Lawrey: but that’s not an artifact of the functional programming style nor the stream API, but the limited type inference. Without the limitation, you could just use `…->new ArrayList<>()` or `ArrayList::new`. – Holger Oct 02 '15 at 12:51
  • 1
    @PeterLawrey What's that suppose to mean? What you posted is considered bad practice by Oracle, I've supplied a link to you from an oficial Oracle slideshow about the correct use of `forEach` illustrating that. Making wrong assumptions about my perception of Java doesn't change that. – João Neves Oct 02 '15 at 12:52
  • @Holger And in future versions, I would hope that they fix this, but today it is harder to read esp for some one coming from Java 7. – Peter Lawrey Oct 02 '15 at 12:53
  • @Peter Lawrey: that would be a reason to stick with the good old `for` loop rather than using the stream API in an unintended way. – Holger Oct 02 '15 at 12:57
  • @JoãoNeves When you have a non trivial implementation, it becomes increasing harder to enforce yourself and everyone else to be purely functional. Neither Java nor any tool I know of provides support, like Haskell, where a pure function can only call another pure function etc. We should learn to use the new hammer, but be realistic about when to apply it. – Peter Lawrey Oct 02 '15 at 12:57
  • 2
    @PeterLawrey and realistically your answer is still considered bad practice and could've been easily corrected. Again, should we all start posting bad practices in our answers because we feel it's right? – João Neves Oct 02 '15 at 13:01
  • @JoãoNeves I understand what you are saying, and if you feel you can enforce this practice, it is better, I wish there was better tools for this, however a more pragmatic view is likely to work better in the long run. – Peter Lawrey Oct 02 '15 at 13:18
  • 2
    @PeterLawrey That's your opinion and while you're entitled to it and to program any way you feel like I still think that answers on stackoverflow shouldn't encourage bad practices. – João Neves Oct 02 '15 at 13:23
0

Whenever I code with lists, I use a for loop to speed up the declaration. In your case, I would heavily suggest a loop of any kind, but a for loop would probably be the easiest.

Hayden
  • 31
  • 1