Kotlin - Как пропустить записи об исключениях при отображении и фильтрации - PullRequest
0 голосов
/ 20 июня 2019

Интересно, как пропустить одну запись при отображении или фильтрации?

fun getFilteredList(list: List<String>, match: String): List<String>? {

    val flist = list.filter {
         try {
             // Some parsing logic which can throw exceptions
             val res = SomeParser.parse(match)
             it == res
         } catch (e: Exception){
             // I want to skip this entry to include in flist but still continue 
             // for left of the list entries without return. How to do that?
             return null
         }
     }
     return flist
}

1 Ответ

1 голос
/ 20 июня 2019

Проблема в том, что вы используете ключевое слово return. Ваш код должен выглядеть так:

// return type no longer needs to be nullable
fun getFilteredList(list: List<String>, match: String): List<String> {
    val flist = list.filter {
         try {
             val res = SomeParser.parse(match)
             it == res
         } catch (e: Exception){
             true
         }
     }
     return flist
}

Или, в зависимости от вашего примера, просто (используя синтаксис "функции одного выражения" ):

fun getFilteredList(list: List<String>, match: String) = list.filter {
    try {
        it == SomeParser.parse(match)
    } catch (ex: Exception) {
        true
    }
}

Примечание: Оба из них вызовут SomeParser.parse для каждого элемента в списке. Однако вы упоминаете, что это всего лишь пример, и реальный код работает по-другому (то есть не может быть извлечен из операции фильтрации).


Причина, по которой return выдавал вам ошибку, связана с лямбда-выражениями. Из Возвращение значения из лямбда-выражения раздела ссылки Kotlin:

Мы можем явно вернуть значение из лямбды, используя синтаксис квалифицированного возврата . В противном случае значение последнего выражения возвращается неявно.

Следовательно, два следующих фрагмента эквивалентны:

ints.filter {
    val shouldFilter = it > 0 
    shouldFilter
}

ints.filter {
    val shouldFilter = it > 0 
    return@filter shouldFilter
}

[...]

И это в сочетании с тем фактом, что filter является inline функцией . Из раздела Non-local retuns ссылки Kotlin:

В Kotlin мы можем использовать только нормальный, неквалифицированный return для выхода из именованной функции или анонимной функции. Это означает, что для выхода из лямбды мы должны использовать метку , а внутри лямбды запрещено return, потому что лямбда не может вернуть функцию включения:

fun foo() {
    ordinaryFunction {
        return // ERROR: cannot make `foo` return here
    }
}

Но если функция, в которую передается лямбда-выражение, является встроенной, возвращаемое значение также может быть встроено, поэтому допускается:

fun foo() {
    inlined {
        return // OK: the lambda is inlined
    }
}

Такие возвраты (находящиеся в лямбде, но выходящие из функции включения) называются нелокальными. [...]

Это означает, что когда у вас было return null, оно фактически пыталось выйти из всей функции getFilteredList. Я предполагаю, что именно поэтому у вас есть тип возвращаемого значения List<String>? вместо List<String>. И когда вы пытались return false, вы пытались вернуть Boolean из функции, тип возврата которой был List<String>?.

...