Implement Java method that returns Collection in Kotlin

余生颓废 提交于 2020-08-08 05:13:35

问题


I'm using Kotlin with Spring Security. When implementing this method:

public interface UserDetails extends Serializable {
  Collection<? extends GrantedAuthority> getAuthorities();
  ...
}

I noticed Intellij generates this Kotlin code:

override fun getAuthorities(): MutableCollection<out GrantedAuthority> { ... }

... which makes sense since java.util.Collection is mutable.

However, if I replaced the MutableCollection with Collection (which should be kotlin.collections.Collection IIRC), the code still compiles fine. This confuses me because kotlin.collections.Collection is a read-only interface that MutableCollection inherits from. It doesn't make sense that I can return an immutable collection for a method that's declared to return a mutable collection.

So my questions are:

  1. Why does using kotlin.collections.Collection not cause an error here?
  2. What's the correct Kotlin return type that's equivalent to java.util.Collection?

回答1:


  1. Why does using kotlin.collections.Collection not cause an error here?

If you're not aware, the mutable and non-mutable collection interfaces in Kotlin both resolve to one interface in Java. So Kotlin's Collection and MutableCollection are both java.util.Collection in Java, Kotlin's List and MutableList are both java.util.List in Java, and so on.

Also, Kotlin has what it terms declaration-site variance. The Kotlin Collection interface is defined as Collection<out E> which means the interface is a producer of type E. As a consequence, having:

val col: Collection<GrantedAuthority> = ...

Is nearly the same as:

val col: MutableCollection<out GrantedAuthority> = ...

I say nearly because, while MutableCollection<out ...> prevents anyone from adding any elements, it does not prevent one from mutating the collection entirely. For example, you could still call clear() on the collection.


  1. What's the correct Kotlin return type that's equivalent to java.util.Collection?

Java does not have declaration-site variance. It also doesn't distinguish between mutable and non-mutable collections (at least not at the interface level).

This means that, technically, the best match of the following Java type:

Collection<? extends GrantedAuthority>

Is the following Kotlin type:

MutableCollection<out GrantedAuthority>

Both types are mutable collection types and are defined to be producers of type GrantedAuthority (via ? extends in Java and out in Kotlin). Neither type let's you add anything to the collection.

However, if your getAuthorities() method is supposed to return an unmodifiable collection (e.g. Collections.unmodifiableCollection(collection) in Java) then the more appropriate conversion from Java to Kotlin would be to use:

kotlin.collections.Collection<GrantedAuthority>



回答2:


The reason that this works is that Collection and MutableCollection are both equivalent to java.util.Collection. You can see the full list of Java types that are mapped for Java interop here.

This works because the non-mutable collection interfaces aren't actually immutable (for that, you'd want the Immutable Collections Library), but they simply provide a read-only interface (as you note). Since Java doesn't make this distinction, both have to be mapped to the same Java platform type.

What's the correct Kotlin return type that's equivalent to java.util.Collection?

The correct return type depends on the interface you want to expose to your Kotlin clients. If they shouldn't be mutating the returned collection, use Collection. If you expect them to want to mutate it, use MutableCollection. For your Java clients, it doesn't matter: they're equivalent.



来源:https://stackoverflow.com/questions/63128815/implement-java-method-that-returns-collection-in-kotlin

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!