4

The Java Collections class has the following method:

static <T> List<T> nCopies(int n, T o)

I need a similar method, but slightly more generic, which provides n instances of a given class. Something like:

static <T> List<T> nInstances(int n, Supplier<T> supplier)

In particular, if supplier is Supplier.ofInstance(o), we get the same behavior as the nCopies() method. Is there such a method somewhere in the Guava API?

Thank you.

Otavio Macedo
  • 1,542
  • 1
  • 13
  • 34

3 Answers3

4

No there isn't, and any equivalent construct (that just stores the int n and the supplier and calls the supplier for each get) seems like a terrible idea. That said, apparently you just want to read n objects from a Supplier and store them in a list. In that case, Sean's answer is probably best.

Just for fun though, here's another way you could create an ImmutableList of size n by calling a Supplier n times (transform, limit and cycle all from Iterables):

public static <T> ImmutableList<T> nInstances(int n, Supplier<T> supplier) {
  return ImmutableList.copyOf(transform(
      limit(cycle(supplier), n), Suppliers.<T>supplierFunction()));
}

I uh... wouldn't recommend this over a straightforward loop implementation though (for readability reasons mostly).

ColinD
  • 108,630
  • 30
  • 201
  • 202
  • Here is another fun one line approach: transform(limit(cycle(1), copyCount), Functions.forSupplier(supplier)) – Spina Feb 20 '15 at 18:56
3

Like many other idioms, Java 8 finally delivers with a short and sweet version that doesn't need any external libraries. You can now do this with Streams.generate(Supplier<T> s). For example, for n instances of Foo:

Streams.generate(Foo::new).limit(n)...

You'd finish that line off in different ways depending on how you wanted to create your List. For example, for an ImmutableList:

ImmutableList.copyOf(Streams.generate(Foo::new).limit(n).iterator());
BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
2

No, but it's easy enough to implement:

public static <T> List<T> nInstances(int n, Supplier<T> supplier){
    List<T> list = Lists.newArrayListWithCapacity(n);
    for(int i = 0; i < n; i++){
        list.add(supplier.get());
    }
    return list;
}
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • I don't think that can really be considered equivalent to `Collections.nCopies`, since the distinguishing thing about that is that the `List` it returns uses minimal storage (just an int and one reference). This just dumps all the values returned by the supplier into an `ArrayList`. – ColinD Dec 21 '10 at 16:58
  • Sure, it's easy enough. In fact I have already implemented exactly what you propose. – Otavio Macedo Dec 21 '10 at 17:10
  • @ColinD no, it's not equivalent, obviously (and it's definitely not Guava-worthy). But it does what the OP wanted – Sean Patrick Floyd Dec 21 '10 at 18:30
  • Yeah, though he wasn't very clear on what he actually wanted. The more I think about it though, the more I think that something equivalent to `Collections.nCopies` that calls a `Supplier` for each `get` would be a terrible, terrible idea unless it cached each value... so this is probably best. – ColinD Dec 21 '10 at 18:50