Java何时需要显式类型参数? [英] When does Java require explicit type parameters?

查看:117
本文介绍了Java何时需要显式类型参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于:

import com.google.common.collect.ImmutableMap;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Stream;

public class Testcase
{
    public static <T, K, V> MapCollectorBuilder<T, K, V>
        toImmutableMap(Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends V> valueMapper)
    {
        return null;
    }

    public static final class MapCollectorBuilder<T, K, V>
    {
        public Collector<T, ?, ImmutableMap<K, V>> build()
        {
            return null;
        }
    }

    public static <T, K, V> Collector<T, ?, ImmutableMap<K, V>> toImmutableMap2(
        Function<? super T, ? extends K> keyMapper,
        Function<? super T, ? extends V> valueMapper)
    {
        return null;
    }

    public void main(String[] args)
    {
        Function<String, String> keyMapper = i -> i;
        Function<String, Integer> valueMapper = Integer::valueOf;

        ImmutableMap<String, Integer> map1 = Stream.of("1", "2", "3")
            .collect(Testcase.toImmutableMap(keyMapper, valueMapper).build());

        ImmutableMap<String, Integer> map2 = Stream.of("1", "2", "3")
            .collect(Testcase.toImmutableMap(i -> i, Integer::valueOf).build());

        ImmutableMap<String, Integer> map3 = Stream.of("1", "2", "3")
            .collect(Testcase.toImmutableMap2(i -> i, Integer::valueOf));
    }
}

涉及 map1的语句 map3 编译正常,但 map2 失败:

The statements involving map1 and map3 compile fine, but map2 fails with:

Testcase.java:[41,57] incompatible types: cannot infer type-variable(s) T,K,V
    (argument mismatch; invalid method reference
      no suitable method found for valueOf(java.lang.Object)
          method java.lang.Integer.valueOf(java.lang.String) is not applicable
            (argument mismatch; java.lang.Object cannot be converted to java.lang.String)
          method java.lang.Integer.valueOf(int) is not applicable
            (argument mismatch; java.lang.Object cannot be converted to int))

编译器错误可以通过提供显式类型参数来解决< String,String,Integer>

The compiler error can be solved by providing explicit type parameters <String, String, Integer>.


  1. Java 8何时需要显式类型参数?意思是,是否存在打破类型推断的已知模式?

  2. 可以 toImmutableMap() MapCollectorBuilder 是否可以更改以避免使用显式类型参数而不会丢失使用Builder来配置收集器?

  1. When does Java 8 require explicit type parameters? Meaning, is there a known pattern that breaks type inference?
  2. Can toImmutableMap() and MapCollectorBuilder be changed to avoid explicit type parameters without losing the use of a Builder for configuring the Collector?

更新


  1. 为什么声明涉及 map3 map2 的声明有何不同?

  1. Why does the statement involving map3 work? How does it differ from the statement involving map2?


推荐答案

回答你的问题意义,是否有一种打破类型推断的已知模式?很快:当然,有一种模式,而且还有一个巨大的规范,用于Java编程语言的整个行为。

To answer your question "Meaning, is there a known pattern that breaks type inference?" shortly: of course, there is a pattern, moreover there is a huge specification for the entire behavior of the Java programming language.

但是关于类型推断和方法调用类型的章节非常详尽且难以理解。最好的说明是,在出现意外行为的情况下,通常会根据规范对预期行为进行大量讨论。

But the chapters regarding type inference and method invocation types are really exhaustive and hard to understand. This is best illustrated by the fact that in the case of unexpected behavior, often large discussions about the expected behavior according to the specification occur.

但有一些点可以解释,对程序员来说是值得记住的。

But there are some points explainable and rememberable for a programmer.

有两种方法可以推断出类型参数,通过传递给方法的参数或构成表达式的部分,或者表达式的目标类型,即调用参数的预期类型,已分配的变量或返回语句时方法的返回类型。

There are two ways how to infer the type parameters, by the arguments passed to a method or parts from which an expression is composed or by the target type of an expression, that is, the expected type for a parameter of an invocation, the variable which is assigned or the return type of a method in case of a return statement.

目标类型可以通过嵌套方法调用传播,例如

The target type can get propagated through nested method invocations like in

TargetType x=foo(bar(/*target type can be used*/));

或有条件的

TargetType x=condition? foo(/*target type can be used*/): foo(/*target type can be used*/);

如果是链式调用

TargetType x=foo(/*target type can NOT be used*/).foo();






现在举例来说:


Now to your examples:

ImmutableMap<String, Integer> map1 = Stream.of("1", "2", "3").collect( expression );

这里, Stream.of(...) .collect(...)链接,因此目标类型不能用于确定的流类型调用,但提供给该方法的参数足以推断出类型 Stream< String> collect 方法提供了分配给 map1 的结果,因此两者都是流类型流< String> 目标类型 ImmutableMap< String,Integer> 已知且可用于该类型推断表达式。在表达式上:

Here, the Stream.of(…) and .collect(…) are chained, therefore the target type cannot be used to determine the stream type of the of invocation but the arguments provided to that method are sufficient to infer the type Stream<String>. The collect method provides the result that gets assigned to map1, so both, the stream type Stream<String>and the target type ImmutableMap<String, Integer> are known and can be used for the type inference for the expression. Onto the expressions:


  • Testcase.toImmutableMap(keyMapper,valueMapper).build()这是一个链式调用,因此目标类型为 build()而已知,但不是 toImmutableMap 。但是, toImmutableMap 的参数是具有已知确切类型的局部变量,因此类型推断可以使用它们来推断 toImmutableMap <的结果类型/ code>并检查它是否符合 .build()的预期

  • Testcase.toImmutableMap(keyMapper, valueMapper).build() this is a chained invocation, so the target type is known for build() but not for toImmutableMap. However, the arguments to toImmutableMap are local variables which have a known exact type, therefore the type inference can use them to infer the result type of toImmutableMap and check whether it matches the expectations for .build()

Testcase.toImmutableMap(i - > i,Integer :: valueOf).build()这又是一个链式调用,但现在参数 i - > ;我的类型不完整,并且缺少目标类型。尝试猜测的类型i - >我不知道目标类型失败。

Testcase.toImmutableMap(i -> i, Integer::valueOf).build() this is again a chained invocation but now the argument i - > i has an incomplete type and suffers from the absence of the target type. The attempt to guess a type for i -> i without knowledge about the target type fails.

Testcase.toImmutableMap2(i - > i, Integer :: valueOf)这是链式调用,因此目标类型可用于 toImmutableMap2 调用(对于 collect 调用,它是一个嵌套调用)。因此, toImmutableMap2 的目标类型允许推断参数的目标类型,因此对于 i - >我 lambda表达式。使用正确的目标类型,可以推断出正确的功能签名。

Testcase.toImmutableMap2(i -> i, Integer::valueOf) this is not a chained invocation, therefore the target type is available for the toImmutableMap2 call (in respect to the collect call, it’s a nested invocation). Therefore, the target type of toImmutableMap2 allows to infer target types for the parameters, hence for the i -> i lambda expression. With a proper target type, the correct functional signature can be inferred.

这篇关于Java何时需要显式类型参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆