code: public static <T> T reduce(Iterator<? extends T> iterator, Function2<? super T, ? super T, ? extends T> function) {
  		if (function == null)
  			throw new NullPointerException("function");
  		if (iterator.hasNext()) {
  			T result = iterator.next();
  			while (iterator.hasNext()) {
  				result = function.apply(result, iterator.next());
  			}
  			return result;
  		} else {
  			return null;
  		}
  	}
docs: <p>
  Applies the combinator {@code function} to all elements of the iterator in turn.
  </p>
  <p>
  One of the function parameters is an element of the iterator, and the other is the result of previous application
  of the function. The seed of the operation is the first element in the iterator. The second value is computed by
  applying the function to the seed together with the second element of the iterator. The third value is computed
  from the previous result together with the third element and so on. In other words, the previous result of each
  step is taken and passed together with the next element to the combinator function.
  </p>
  <p>
  If the iterator is empty, <code>null</code> is returned.
  </p>
  <p>
  More formally, given an iterator {@code [a, b, c, d]} and a function {@code f}, the result of {@code reduce} is
  <code>f(f(f(a, b), c), d)</code>
  </p>
  
  @param iterator
  the to-be-reduced iterator. May not be <code>null</code>.
  @param function
  the combinator function. May not be <code>null</code>.
  @return the last result of the applied combinator function or <code>null</code> for the empty input.