title: Cannot use Java 8 method with lambda arguments without specifying type arguments
body: <p>I made a method with type arguments, returning a generic type using these type arguments, and taking <code>Function</code> arguments which also depends on the type arguments. When I use lambdas as arguments, the compiler forces me to specify the type arguments of the method, which feels wrong.</p>
  
  <p>I am designing a utility class with methods to use with <code>Stream.flatMap</code>. It maps every kind of collection entry to a FlatEntry which contains a key and value element, and can do this on multiple levels with a builder. The affected method is <code>flatEntryMapperBuilder</code>. Here is the code:</p>
  
  <pre><code>import java.util.function.Function;
  import java.util.stream.Stream;
  
  public class GdkStreams
  {
      public static &lt;T, K, V&gt; Function&lt;T, Stream&lt;FlatEntry&lt;K, V&gt;&gt;&gt; flatEntryMapper(Function&lt;T, K&gt; keyMapper,
                                                                                   Function&lt;T, Stream&lt;V&gt;&gt; valueMapper)
      {
          return input -&gt; {
              K key = keyMapper.apply(input);
              return valueMapper.apply(input).map(value -&gt; new FlatEntry&lt;&gt;(key, value));
          };
      }
  
      public static &lt;T, K, V&gt; FlatEntryMapperBuilder&lt;T, K, V&gt; flatEntryMapperBuilder(Function&lt;T, K&gt; keyMapper,
                                                                                     Function&lt;T, Stream&lt;V&gt;&gt; valueMapper)
      {
          return new FlatEntryMapperBuilder&lt;&gt;(keyMapper, valueMapper);
      }
  
      public static class FlatEntryMapperBuilder&lt;T, K, V&gt;
      {
          private Function&lt;T, K&gt;         keyMapper;
  
          private Function&lt;T, Stream&lt;V&gt;&gt; valueMapper;
  
          private FlatEntryMapperBuilder (Function&lt;T, K&gt; keyMapper, Function&lt;T, Stream&lt;V&gt;&gt; valueMapper)
          {
              this.keyMapper = keyMapper;
              this.valueMapper = valueMapper;
          }
  
          public Function&lt;T, Stream&lt;FlatEntry&lt;K, V&gt;&gt;&gt; build()
          {
              return flatEntryMapper(keyMapper, valueMapper);
          }
  
          public &lt;K2, V2&gt; FlatEntryMapperBuilder&lt;T, K, FlatEntry&lt;K2, V2&gt;&gt; chain(Function&lt;V, K2&gt; keyMapper2,
                                                                                Function&lt;V, Stream&lt;V2&gt;&gt; valueMapper2)
          {
              return new FlatEntryMapperBuilder&lt;&gt;(keyMapper,
                                                  valueMapper.andThen(stream -&gt; stream.flatMap(flatEntryMapper(keyMapper2,
                                                                                                               valueMapper2))));
          }
      }
  
      public static class FlatEntry&lt;K, V&gt;
      {
          public final K key;
  
          public final V value;
  
          public FlatEntry (K key, V value)
          {
              this.key = key;
              this.value = value;
          }
      }
  }
  </code></pre>
  
  <p>The problem comes with its usage. Say I have:</p>
  
  <pre><code>Map&lt;String, Set&lt;String&gt;&gt; level1Map;
  </code></pre>
  
  <p>I can map every element in the sub Sets to a FlatEntry by doing:</p>
  
  <pre><code>level1Map.entrySet().stream().flatMap(GdkStreams.flatEntryMapper(Entry::getKey, entry -&gt; entry.getValue().stream()));
  </code></pre>
  
  <p>And it works just fine. But when I try to do this:</p>
  
  <pre><code>level1Map.entrySet()
           .stream()
           .flatMap(GdkStreams.flatEntryMapperBuilder(Entry::getKey, entry -&gt; entry.getValue().stream()).build());
  </code></pre>
  
  <p>The eclipse (Mars 4.5.0) compiler breaks with:</p>
  
  <pre><code>- The type Map.Entry does not define getKey(Object) that is applicable here
  - The method getValue() is undefined for the type Object
  - Type mismatch: cannot convert from GdkStreams.FlatEntryMapperBuilder&lt;Object,Object,Object&gt; to 
   &lt;unknown&gt;
  </code></pre>
  
  <p>And javac (1.8.0_51) breaks with:</p>
  
  <pre><code>MainTest.java:50: error: incompatible types: cannot infer type-variable(s) T,K#1,V#1
                   .flatMap(GdkStreams.flatEntryMapperBuilder(Entry::getKey, entry -&gt; entry.getValue().stream()).build());
                                                             ^
      (argument mismatch; invalid method reference
        method getKey in interface Entry&lt;K#2,V#2&gt; cannot be applied to given types
          required: no arguments
          found: Object
          reason: actual and formal argument lists differ in length)
    where T,K#1,V#1,K#2,V#2 are type-variables:
      T extends Object declared in method &lt;T,K#1,V#1&gt;flatEntryMapperBuilder(Function&lt;T,K#1&gt;,Function&lt;T,Stream&lt;V#1&gt;&gt;)
      K#1 extends Object declared in method &lt;T,K#1,V#1&gt;flatEntryMapperBuilder(Function&lt;T,K#1&gt;,Function&lt;T,Stream&lt;V#1&gt;&gt;)
      V#1 extends Object declared in method &lt;T,K#1,V#1&gt;flatEntryMapperBuilder(Function&lt;T,K#1&gt;,Function&lt;T,Stream&lt;V#1&gt;&gt;)
      K#2 extends Object declared in interface Entry
      V#2 extends Object declared in interface Entry
  MainTest.java:50: error: invalid method reference
                   .flatMap(GdkStreams.flatEntryMapperBuilder(Entry::getKey, entry -&gt; entry.getValue().stream()).build());
                                                              ^
    non-static method getKey() cannot be referenced from a static context
    where K is a type-variable:
      K extends Object declared in interface Entry
  2 errors
  </code></pre>
  
  <p>If I replace <code>Entry::getKey</code> by <code>entry -&gt; entry.getKey()</code>, javac changes its output drastically:</p>
  
  <pre><code>MainTest.java:51: error: cannot find symbol
                   .flatMap(GdkStreams.flatEntryMapperBuilder(entry -&gt; entry.getKey(), entry -&gt; entry.getValue().stream()).build());
  
                                                                            ^
    symbol:   method getKey()
    location: variable entry of type Object
  MainTest.java:51: error: cannot find symbol
                   .flatMap(GdkStreams.flatEntryMapperBuilder(entry -&gt; entry.getKey(), entry -&gt; entry.getValue().stream()).build());
  
                                                                                                     ^
    symbol:   method getValue()
    location: variable entry of type Object
  2 errors
  </code></pre>
  
  <p>It compiles fine by specifying type parameters, which is what I expected:</p>
  
  <pre><code>level1Map.entrySet()
           .stream()
           .flatMap(GdkStreams.&lt;Entry&lt;String, Set&lt;String&gt;&gt;, String, String&gt; flatEntryMapperBuilder(Entry::getKey,
                                                                                                   entry -&gt; entry.getValue()
                                                                                                                 .stream())
                              .build());
  </code></pre>
  
  <p>or specifying one of the arguments type parameters:</p>
  
  <pre><code>Function&lt;Entry&lt;String, Set&lt;String&gt;&gt;, String&gt; keyGetter = Entry::getKey;
  level1Map.entrySet()
           .stream()
           .flatMap(GdkStreams.flatEntryMapperBuilder(keyGetter, entry -&gt; entry.getValue().stream()).build());
  </code></pre>
  
  <p>But this is clumsy! Imagine now how clumsy it would be to write all type parameters with 2 levels in the map, using the chain method (which is my target usage):</p>
  
  <pre><code>Map&lt;String, Map&lt;String, Set&lt;String&gt;&gt;&gt; level2Map;
  </code></pre>
  
  <p>I have read many other questions about lambdas and generics type inference but none is answering my particular case.</p>
  
  <p>Am I missing something? Can I correct my API so that its usage is less clumsy, or am I stuck with always specifying type arguments? Thanks!</p>