在某些情况下,我想“脱离” ArrayList<Pair<K,V>> set_of_pairs = new ArrayList<Pair<K,V>>();
public void insert(K key, V value) {
Pair<K,V> pair = new Pair<K,V>(key,value);
set_of_pairs.add(pair);
}
public void traverse(Visitor<K,V> visitor) {
}
public V retrieve(K key) {
int i = 0;
if (set_of_pairs.containsKeys(key) == false) {
return null;
}
else {
for(Pair<K,V> set_of_pairs: pair) {
if (pair.getKey() == key) {
return pair.getValue();
}
}
}
}
并直接返回到forEach
的呼叫者。
使用bar
可以起作用:
List
但是如果fun bar(collection: List<String>): Boolean {
collection.forEach { value ->
if ("foo".equals(value))
return true
}
return false
}
是collection
,则会出现编译错误:
Map
为什么?
(在这种情况下,请不要介意使用forEach进行简单搜索。这只是一个最小的示例。实际代码要复杂得多。)
答案 0 :(得分:4)
Ricky Mo's answer在解释为什么会发生错误的正确路线上,但我认为还有更多的方法可以解决错误。
简而言之:
forEach
上对List
的调用正在调用Kotlin标准库函数Iterable.forEach
,它是一个内联函数,位于bar
中您传递给它的lambda。此函数使用一个lambda参数,该参数本身只有一个参数。Map
,实际上是在Map
上定义的Java thus allowing you to return方法,该方法采用BiConsumer
,这实际上是一个接口两参数lambda。 Java没有内联的概念,因此您不能从此BiConsumer
进行非本地返回。我们来谈谈解决方案。
在Iterable.forEach
的情况下,您也可以使用Kotlin Map
,因为它的是 Iterable
。要调用此forEach
,您只需传递一个采用单个参数而不是两个参数的lambda:
collection.forEach { entry ->
if ("foo".equals(entry.key))
return true
}
返回值将在这里起作用,因为内嵌 this forEach
。
您也可以通过在地图条目上使用forEach
来进行上一个呼叫:
collection.forEach { (key, value) ->
if ("foo".equals(key))
return true
}
此语法与您的原始调用非常接近(也许很烦人),但是此lambda仍具有单个参数,从而使它成为对Kotlin标准库forEach
函数而不是Java方法的调用。需要两个参数。
作为最后一个较小的步骤,如果不在lambda中使用值,可以使用_
作为值的名称:
collection.forEach { (key, _) ->
if ("foo".equals(key))
return true
}
答案 1 :(得分:3)
Map
具有forEach
的不同实现。您可以查看源代码。
对于List
:
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
for (element in this) action(element)
}
对于Map
(这是java):
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
list.forEach
接受function type
,而map.forEach
接受BiConsumer
实例。
对于List
,如inline
关键字所建议,您可以将
forEach
调用
for (value in collection)
{
if("foo".equals(value))
{
return true
}
}
一切都对回报有意义。
您传递给map.forEach
的lambda实际上是accept
接口的成员函数BiConsumer
的实现,类型为void
。这就是为什么返回Boolean
毫无意义的原因。即使您只是return
,它也只是结束了accept
方法。由于这不是kotlin inline
函数,因此不会结束封闭函数。
BiConsumer
的Java源代码
public interface BiConsumer<T, U> {
/**
* Performs this operation on the given arguments.
*
* @param t the first input argument
* @param u the second input argument
*/
void accept(T t, U u);
/**
* Returns a composed {@code BiConsumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code BiConsumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
Objects.requireNonNull(after);
return (l, r) -> {
accept(l, r);
after.accept(l, r);
};
}
}
在没有任何简化的情况下,您的函数实际上看起来像这样:
fun bar(collection: Map<String, String>): Boolean {
val action : BiConsumer<String,String> = object : BiConsumer<String, String> {
override fun accept(t: String, u: String) {
//return boolean is not allow here
//return at here just end the accept function. bar is not affected
}
}
collection.forEach(action)
return false
}
由于kotlin将单方法接口实现转换为lambda,它给您一种幻觉,即map.forEach
就像接受function type
的内联调用一样,就像List
一样。事实是,map.forEach
接受的lambda不是kotlin function type
,而是BiConsumer
实现,最重要的是,它不是inline
。