Kotlin: цикл через отфильтрованный (возможно, пустой и не более одного элемента) список

У меня есть штормовой болт, который получает кортежи, которые содержат значение типа MyClass , которое, в свою очередь, содержит поле времени startTime . В конце болта, я хотел бы startTime время, которое обработка взяла с самого начала (отмечена startTime ). Поэтому я мог бы сделать:

 override fun doExecute(input: Tuple): Boolean { ... // my processing logic input.values.filterIsInstance(MyClass).forEach { val endToEndTime = (System.currentTimeMillis() - it.startTime).toInt() stats.recordExecutionTime("mytag", endToEndTime) } } 

У меня нет проблем с этим подходом. Просто косметический мудрый, похоже, у меня могло быть более одного экземпляра MyClass в кортеже (чего у меня нет). Поэтому я подумал, могу ли я просто выбрать первый из списка, например:

 override fun doExecute(input: Tuple): Boolean { ... // my processing logic input.values.filterIsInstance(MyClass).first().let { val endToEndTime = (System.currentTimeMillis() - it.startTime).toInt() stats.recordExecutionTime("mytag", endToEndTime) } } 

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

Есть лучший способ сделать это?

    Существует лучший способ! 🙂

    Вы можете использовать firstOrNull() а затем безопасный вызов:

     input.values.filterIsInstance(MyClass).firstOrNull()?.let { val endToEndTime = (System.currentTimeMillis() - it.startTime).toInt() stats.recordExecutionTime("mytag", endToEndTime) } 

    Вы также можете заменить вызов filterIsInstance версией firstOrNull() которая использует предикат, например:

     input.values.firstOrNull { it is MyClass }?.let {ű it as MyClass val endToEndTime = (System.currentTimeMillis() - it.startTime).toInt() stats.recordExecutionTime("mytag", endToEndTime) }