如何模拟通用通配符的返回值

drW*_*son 1 java wildcard mockito java-8 java-stream

我试图在Java 8中了解泛型和通配符.但我无法理解为什么不能模拟这个存储库方法.代码非常简单,因此应该很容易重现.

我在"thenReturn"部分的"when"中得到了这个编译错误

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>)
Run Code Online (Sandbox Code Playgroud)

考试:

@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);     
}
Run Code Online (Sandbox Code Playgroud)

班级:

public class Something {}
Run Code Online (Sandbox Code Playgroud)

存储库:

public interface SomeRepository{
    Stream<? extends Something> getStream();
}
Run Code Online (Sandbox Code Playgroud)

有人可以帮忙吗?谢谢!

Hol*_*ger 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);
Run Code Online (Sandbox Code Playgroud)

这将指出可能与Mockito API一起使用的解决方案.但是,对于设计类似API的API,SomeRepository您应遵循一般的"通配符使用指南":

应该避免使用通配符作为返回类型,因为它强制程序员使用代码来处理通配符.

? 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());
Run Code Online (Sandbox Code Playgroud)

Stream<? extends Something>不提供任何的Stream<Something>没有提供太多.

如果改为输入界面会有所不同,例如遵循RC的建议:

interface SomeRepository<T extends Something> {
    Stream<T> getStream();
}
Run Code Online (Sandbox Code Playgroud)

然后,您不再拥有通配符,更具体的类型流可能会带来好处.