Module YieldReturn

Class Generator<T>

java.lang.Object
io.github.danthe1st.jvmyieldreturn.Generator<T>
Type Parameters:
T - The type of elements to iterate over.

public class Generator<T> extends Object
Allows to create an Iterable or Stream obtaining its values by lazily evaluating a function.

This function can send values to the Iterable by calling yield. When the first object is requested by an Iterator, the function is executed until a yield call. The function is then suspended until the next element is requested.

The provided function is called once per call to Iterable.iterator().

The method yield(Object) might return in a different thread or might not return at all. try-finally or closing of try-with-resources-blocks might not be executed if a yield(Object) call happens inside these blocks.

private void example() {
	System.out.println("main thread: " + Thread.currentThread());

	for(String s : Generator.iterable(this::someMethod)){
		System.out.println("Text: " + s);
	}

	System.out.println();
	System.out.println("Now using streams:");

	Generator.stream(this::someMethod).limit(2).forEach(System.out::println);
}

private void someMethod(Generator<String> y) {
	y.yield("Hello - " + Thread.currentThread());
	System.out.println("between yields");
	y.yield("World - " + Thread.currentThread());

	for(String s : Generator.iterable(this::otherMethod)){
		y.yield("nested: " + s);
	}

	y.yield("bye - " + Thread.currentThread());
}

private void otherMethod(Generator<String> y) {
	y.yield("it can");
	y.yield("also be");
	y.yield("nested");
}

In general, the Generator object passed to the function should not be passed to other methods that might call yield(Object) inside a try-finally or closing of try-with-resources-block.

private void badCodeTryFinally() {
	Iterable<String> iterable = Generator.iterable(this::methodWithTryFinally);
	String firstElement = iterable.iterator().next();
	System.out.println(firstElement);
}

private void methodWithTryFinally(Generator<String> y) {
	try{
		y.yield("Hello World");// DON'T DO THIS
	}finally{// may not get executed
		System.out.println("Some very important cleanup code");
	}
}

In case a try-finally or closing of try-with-resources-block is needed, it can surround the complete iteration code ensuring that the resource is closed when the iteration completes.

private void goodCodeTryFinally() {
	try{
		Iterable<String> iterable = Generator.iterable(this::yieldSomething);
		String firstElement = iterable.iterator().next();
		System.out.println(firstElement);
	}finally{// will get executed
		System.out.println("Some very important cleanup code");
	}

}

private void yieldSomething(Generator<String> y) {
	y.yield("Hello World");// OK, this is not surrounded by any try-finally
}
  • Method Details

    • yield

      public void yield(T value)
      Passes an object to the corresponding Iterator and suspends until the next object is requested.

      This method might return in a different thread or might not return at all. try-finally or closing of try-with-resources-blocks might not be executed if a yield(Object) call happens inside these blocks.

      Parameters:
      value - The object that should be passed to the Iterator.
    • iterable

      public static <T> Iterable<T> iterable(Consumer<Generator<T>> fun)
      Creates an Iterable obtaining its values by lazily evaluating a function.

      When calling yield(Object) in the passed function, that call might return in a different thread or might not return at all. try-finally or closing of try-with-resources-blocks might not be executed if a yield(Object) call happens inside these blocks.

      Type Parameters:
      T - The type of elements to iterate over.
      Parameters:
      fun - The function used for obtaining values to iterate over. Values are passed to the Iterator using a parameter passed to the function.
      Returns:
      An Iterable that allows iterating over the values provided by the given function.
      See Also:
    • stream

      public static <T> Stream<T> stream(Consumer<Generator<T>> fun)
      Creates a Stream obtaining its values by lazily evaluating a function.

      When calling yield(Object) in the passed function, that call might return in a different thread or might not return at all. try-finally or closing of try-with-resources-blocks might not be executed if a yield(Object) call happens inside these blocks.

      Type Parameters:
      T - The type of the elements to iterate over.
      Parameters:
      fun - The function used for obtaining values to iterate over. Values are passed to the Stream using a parameter passed to the function.
      Returns:
      A Stream that allows lazily accessing the values provided by the given function.
      See Also: