2017-06-22 93 views
4

下无法编译:为什么Streams API在这种情况下需要泛型类型的提示?

@NotNull String defaultFormatter(@Nullable Object value) { 
     if (value instanceof Collection) { 
      return ((Collection) value).stream() 
         .map(MyClass::defaultFormatter) 
         .collect(Collectors.joining(eol)); 
     } 
     return String.valueOf(value); 
    } 

特别是,当用javac编译,错误是:

Error:(809, 94) java: incompatible types: 
     java.lang.Object cannot be converted to 
     @org.jetbrains.annotations.NotNull java.lang.String 

但以下编译就好:

@NotNull String defaultFormatter(@Nullable Object value) { 
     if (value instanceof Collection) { 
      Stream<String> stream = ((Collection) value).stream() 
         .map(MyClass::defaultFormatter); 
      return stream.collect(Collectors.joining(eol)); 
     } 
     return String.valueOf(value); 
    } 

的唯一的区别是我引入了一个额外的变量。请注意,我没有演员,所以没有语义变化。

有人可以解释为什么这是需要的吗?

+0

您是使用'javac'还是IDE的编译器? – Kayaman

+0

这两个IntelliJ IDEA的语法荧光笔,并通过编译与javac确认。 – ddimitrov

+3

可能的重复https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it。请参阅*“原始类型是该类型的擦除”*一节。您需要使用'Collection '而不是'Collection'。 – Radiodef

回答

4

这个答案的上半部分基本上是Radiodef在上面评论中说的。我不想窃取这些词,但如果没有事先解释,---以下的答案并不真实。

正如Radiodef指出的那样,这在第一种情况下不起作用的原因是因为它使用原始类型Collection。相反,使用Collection<?>,并且它会工作:

 return ((Collection<?>) value).stream() 
        .map(MyClass::defaultFormatter) 
        .collect(Collectors.joining(eol)); 

为什么它的工作原理与明确的变量是因为不受控制转换的原因。注意,下文中产生一个未选中转换警告:

 Stream<String> stream = ((Collection) value).stream() 
        .map(MyClass::defaultFormatter); 

实际类型的RHS表达的是Stream;你被允许胁迫该给Stream<String>,如JLS Sec 5.1.9描述:

有从原始类或接口类型未经检查的转换(§4.8)G任何参数化的类型的形式G<T1,...,Tn>的。


你之所以不能没有变量做同样的事情更微妙一些。 This answer addresses the issue more directly:当您使用原始类型时,所有泛型都将从该类型中删除,而不仅仅是与删除类型直接相关的泛型。

所以,当Stream是原始的Stream.collect的类型为类型的擦除时,它是通用的:

  • Stream.collect(Collector<? super T,A,R> collector)返回R;
  • R擦除是Object

所以collect调用的返回类型为Object,当你观察这里。这不能通过未经检查的转换自动强制为List<String>,因为它不是List

相关问题