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
, на самом деле является реализацией функции-члена accept
интерфейса BiConsumer
, тип которого void
.Вот почему возвращать Boolean
не имеет смысла.Даже вы просто return
, это просто конец метода accept
.Поскольку это не функция kotlin inline
, она не завершит функцию включения.
Исходный код Java BiConsumer
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 преобразует реализацию интерфейса одного метода в лямбду, создается иллюзия, что map.forEach
выглядит как встроенный вызов, принимающий function type
точно так же, как List
.Правда состоит в том, что лямбда, принятая map.forEach
, - это не kotlin function type
, а реализация BiConsumer
, а самое главное, это не inline
.