为什么以及如何通过编译器对这两个条件进行不同的处理?

时间:2012-01-24 15:08:14

标签: java generics type-inference conditional-operator type-bounds

以下两个代码示例表示相同的逻辑。检查字符串是否为null并根据该检查进行分支。第一个样本安全编译。第二个产生与Java泛型相关的类型不匹配错误。我的问题似乎很简单,但它让我望而却步。为什么编译器对这两个语句的处理方式不同?我怎样才能更好地了解这里发生了什么?

/* compiles cleanly */
protected Collection<String> getUserRoles(Object context,
        Set<String> mappableRoles) {
    String cookieValue = extractCookieValue(context);
    if (cookieValue != null) {
        return securityService.getRolesForUser(cookieValue);
    } else {
        return Collections.emptySet();
    }
}


/* produces a compiler error */
protected Collection<String> getUserRoles(Object context,
            Set<String> mappableRoles) {
    String cookieValue = extractCookieValue(context);
    return cookieValue == null ? Collections.emptySet()
            : securityService.getRolesForUser(cookieValue);
}

Eclipse的编译错误。

Type mismatch: cannot convert from Set<capture#1-of ? extends Object> to Collection<String>

根据要求,这是SecurityService接口的相关部分。

public interface SecurityService {
    public Set<String> getRolesForUser(String userId);
}

3 个答案:

答案 0 :(得分:7)

问题应该在于编译器如何解释三元运算符的返回值。您可能需要查看part 15.25 of the JLS或此question(有点相关,因为它通过自动装箱更加复杂,并且在运行时而不是在编译时抛出错误。)

希望这会让你朝着正确的方向前进。

答案 1 :(得分:5)

这是因为Collections.emptySet()会返回无类型的Set。相反,试试这个:

Collections.<String>emptySet()

答案 2 :(得分:1)

Collections.emptySet()声明为

public static final <T> Set<T> emptySet()

第一个 T 用于Type Inference。第二个 getUserRoles 实现过于复杂,java编译器无法检测到正确的类型。这就是问题的原因。 解决方法:

protected Collection<String> getUserRoles(Object context,
            Set<String> mappableRoles) {
    String cookieValue = extractCookieValue(context);
    Collection<String> a = null;
    return cookieValue == null ? a = Collections.emptySet()
            : securityService.getRolesForUser(cookieValue);
}