我正试图在Java 8中了解泛型和通配符。但我无法理解为什么不能模拟这个存储库方法。 代码非常简单,因此应该很容易重现。
我在“when”
的“thenReturn”部分得到了这个编译错误The method thenReturn(Stream<capture#1-of ? extends Something>) in the type
OngoingStubbing<Stream<capture#1-of ? extends Something>> is not applicable
for the arguments (Stream<capture#3-of ? extends Something>)
测试:
@Test
public void ItShourReturnStreamFromRepository() {
List<Something> list = new ArrayList<Something>();
list.add(new Something());
Stream<? extends Something> stream = list.stream();
when(someRepository.getStream()).thenReturn(stream);
}
班级:
public class Something {}
存储库:
public interface SomeRepository{
Stream<? extends Something> getStream();
}
有人可以帮忙吗? 谢谢!
答案 0 :(得分:5)
这是通配符类型的一般问题。用简化的Mockito独立示例演示它:
Enum<?> e = Thread.State.BLOCKED;
// produces "incompatible types: Enum<CAP#1> cannot be converted to Enum<CAP#2>"
Arrays.asList(e).set(0, e);
// works since Java 8
List<Enum<?>> list=Arrays.asList(e);
list.add(e);
// works even in older versions
Arrays.<Enum<?>>asList(e).set(0, e);
这指出了可能与Mockito API一起使用的解决方案。但是,要设计像SomeRepository
这样的API,您应该遵循常规“Guidelines for Wildcard Use”:
应该避免使用通配符作为返回类型,因为它会强制程序员使用代码来处理通配符。
Stream的元素类型中的? extends
会产生并发症而没有任何好处。您甚至可以从具有更具体类型的来源创建Stream<Something>
,例如
SubTypeOfSomething subTyped = …
// from specific values
Stream<Something> s1 = Stream.of(subTyped);
// from existing collection
Set<SubTypeOfSomething> set = Collections.singleton(subTyped);
// note: this creates the stream directly from the source set
Stream<Something> s2 = Collections.<Something>unmodifiableSet(set).stream();
// if you really unavoidably have a more specifically typed Stream
Stream<SubTypeOfSomething> s3 = set.stream();
Stream<Something> s4 = s3.map(Function.identity());
Stream<? extends Something>
不提供Stream<Something>
不提供的任何内容。
如果改为输入界面会有所不同,例如关注RC’s suggestion:
interface SomeRepository<T extends Something> {
Stream<T> getStream();
}
然后,您不再拥有通配符,更具体的类型化流可能会带来好处。