-3

In C#, I can transform a single element to an IEnumerable<> like this (using an extension method here):

static class Extensions
{
    static IEnumerable<T> Yield<T>(this T t)
    {
        yield return t;
    }
}

I use this when I need to input an IEnumerable<> somewhere but only have a single element, like here:

var myList = new List<string>("foo".Yield());

Is there some equivalent way to do this in Java?

I am NOT interested in actually creating an Iterable<> on the heap from an element like

List<String> myIterable = new ArrayList<String>();
myIterable.add("foo");

because I already know that kind of solution; I want to know if Java can handle enumerables/iterables as powerfully as C# (C# has Linq and yield return, Java has Streams) and lazily.

Kjara
  • 2,504
  • 15
  • 42
  • "I am NOT interested in actually creating an `Iterable<>` from an element" So what *are* you interested in? "if Java can handle enumerables/iterables as powerfully as C#" is unclear. – Sweeper Oct 14 '22 at 09:16
  • @Sweeper The C# code I wrote does not create an `IEnumerable<>` object; it merely transforms it lazily (it creates a "recipe" for how to get entries when needed). I want to know if Java has an equivalent. – Kjara Oct 14 '22 at 13:05

1 Answers1

4

The easiest way is to use Collections.singleton() or Collections.singletonList().

Collections.singleton(1);
Collections.singletonList("");

Returned collections are immutable in both cases, they are being backed only by the actual element. They are not real collections, in the sense, that they only allow iteration and other non modifying operations.

Or you can make the implementations of Iterator and Iterable yourself, although that would be reimplementing the above to some extent (jdk already provides similar/same functionality).

public class SingleElementIterator<T> implements Iterator<T> {

  private final T element;
  private boolean hasNext;

  public SingleElementIterator(T element) {
    this.element = element;
    this.hasNext = true;
  }

  @Override
  public boolean hasNext() {
    return this.hasNext;
  }

  @Override
  public T next() {
    if (this.hasNext) {
      this.hasNext = false;
      return this.element;
    }
    throw new NoSuchElementException();
  }
}
public class SingleElementIterable<T> implements Iterable<T> {

  private final T element;

  public SingleElementIterable(T element) {
    this.element = element;
  }

  @Override
  public Iterator<T> iterator() {
    return new SingleElementIterator<>(this.element);
  }
}

Example:

public class Temp {

  public static void main(String[] args) {
    Iterable<String> iterable = new SingleElementIterable<>("abc");
    for (String string : iterable) {
      System.out.println(string);
    }
  }
}
Chaosfire
  • 4,818
  • 4
  • 8
  • 23
  • But `Collections.singleton`/`Collections.singletonList` does create a `Set`/`List` object, right? Just like using `List myIterable = new ArrayList(); myIterable.add("foo");`? Your sample implementation also creates a new object on the heap. Isn't there a lazy way of doing it like in C# where no such collection is actually created on the heap? – Kjara Oct 14 '22 at 13:10
  • 1
    As i wrote - `they are being backed only by the actual element.` Collections returned from `singleton...` methods are **not** real collections, you can think of them as wrappers around the element, which only allow you iteration and other non modifying operations. It's quite different from `List myIterable = new ArrayList(); myIterable.add("foo");`, which creates a real, full fledged list, backed by an array, allowing all operations. – Chaosfire Oct 14 '22 at 14:56
  • My sample implementation also follows this idea. It's nothing more than a wrapper, allowing to iterate single element. And yes, it does create new object(not a collection in particular), but you can't escape from object creation. I'm not expert on c#, so don't take my word for it, but i believe that this yield return IEnumerable also creates an object(again, not a collection), just the syntax is shorter. – Chaosfire Oct 14 '22 at 15:01