code: public static <T> Stream<T> iterate(final T init, final BooleanSupplier hasNext, final UnaryOperator<T> f) {
          N.checkArgNotNull(hasNext);
          N.checkArgNotNull(f);
  
          return of(new ObjIteratorEx<T>() {
              private T t = (T) NONE;
              private boolean hasNextVal = false;
  
              @Override
              public boolean hasNext() {
                  if (hasNextVal == false) {
                      hasNextVal = hasNext.getAsBoolean();
                  }
  
                  return hasNextVal;
              }
  
              @Override
              public T next() {
                  if (hasNextVal == false && hasNext() == false) {
                      throw new NoSuchElementException();
                  }
  
                  hasNextVal = false;
                  return t = (t == NONE) ? init : f.apply(t);
              }
          });
      }
docs: Returns a sequential ordered {@code Stream} produced by iterative
  application of a function {@code f} to an initial element {@code init},
  producing a {@code Stream} consisting of {@code init}, {@code f(init)},
  {@code f(f(init))}, etc.
  
  <p>The first element (position {@code 0}) in the {@code Stream} will be
  the provided {@code init}.  For {@code n > 0}, the element at position
  {@code n}, will be the result of applying the function {@code f} to the
  element at position {@code n - 1}.
  
  @param init
  @param hasNext
  @param f
  @return