T getFunction(final List<SqlArgument> arguments) {

    // first try to get the candidates without any implicit casting
    Optional<T> candidate = findMatchingCandidate(arguments, false);
    if (candidate.isPresent()) {
      return candidate.get();
    } else if (!supportsImplicitCasts) {
      throw createNoMatchingFunctionException(arguments);
    }

    // if none were found (candidate isn't present) try again with implicit casting
    candidate = findMatchingCandidate(arguments, true);
    if (candidate.isPresent()) {
      return candidate.get();
    }
    throw createNoMatchingFunctionException(arguments);
  }
@Test
  public void shouldChooseCorrectLambdaFunction() {
    // Given:
    givenFunctions(
        function(FIRST_FUNC, -1, GENERIC_MAP, LAMBDA_KEY_FUNCTION)
    );
    givenFunctions(
        function(SECOND_FUNC, -1, GENERIC_MAP, LAMBDA_VALUE_FUNCTION)
    );

    // When:
    final KsqlScalarFunction first_fun = udfIndex.getFunction(
        ImmutableList.of(
            SqlArgument.of(MAP2_ARG),
            SqlArgument.of(
                SqlLambdaResolved.of(
                    ImmutableList.of(SqlTypes.STRING),
                    SqlTypes.STRING))));

    final KsqlScalarFunction second_fun = udfIndex.getFunction(
        ImmutableList.of(
            SqlArgument.of(MAP2_ARG),
            SqlArgument.of(
                SqlLambdaResolved.of(
                    ImmutableList.of(INTEGER),
                    INTEGER))));

    // Then:
    assertThat(first_fun.name(), equalTo(FIRST_FUNC));
    assertThat(second_fun.name(), equalTo(SECOND_FUNC));
  }