@Udf(description = "When reducing an array, "
      + "the reduce function must have two arguments. "
      + "The two arguments for the reduce function are in order: "
      + "the state and the array item. "
      + "The final state is returned."
  )
  public <T,S> S reduceArray(
      @UdfParameter(description = "The array.") final List<T> list,
      @UdfParameter(description = "The initial state.") final S initialState,
      @UdfParameter(description = "The reduce function.") final BiFunction<S, T, S> biFunction
  ) {
    if (initialState == null || biFunction == null) {
      return null;
    }

    if (list == null) {
      return initialState;
    }

    S state = initialState;
    for (T listItem: list) {
      state = biFunction.apply(state, listItem);
    }
    return state;
  }
@Test
  public void shouldReduceArray() {
    assertThat(udf.reduceArray( ImmutableList.of(), "", biFunction1()), is(""));
    assertThat(udf.reduceArray(ImmutableList.of(), "answer", biFunction1()), is("answer"));
    assertThat(udf.reduceArray(ImmutableList.of(2, 3, 4, 4, 1000), "", biFunction1()), is("evenoddeveneveneven"));
    assertThat(udf.reduceArray(ImmutableList.of(3, -1, -5), "This is: ", biFunction1()), is("This is: oddoddodd"));

    assertThat(udf.reduceArray(ImmutableList.of(), 0, biFunction2()), is(0));
    assertThat(udf.reduceArray(Arrays.asList(-1, -13), 14, biFunction2()), is(0));
    assertThat(udf.reduceArray(ImmutableList.of(-5, 10), 1, biFunction2()), is(6));
    assertThat(udf.reduceArray(ImmutableList.of(100, 1000, 42), -100, biFunction2()), is(1042));
  }