Сам по себе Kotlin очень мощный инструмент, но многие часто используют его не на полную мощность, превращая его в какую-то... Java 6. Попробую рассказать почему так делать не надо и как использовать функциональные фичи языка на полную.  Начну с них. И, заодно, расскажу что это вообще такое: когда функция принимает другую функцию как параметр или возвращает ее - это функция высшего порядка. Просто, не правда ли? Но как этим пользоваться?  То, что функции в Котлине могут получать и возвращать другие функции для нас должно означать то, что мы можем записать их в переменную. Выглядеть это будет как-то так: Тогда, мы сможем передать ее, используя синтаксис вида: Отлично, но что если мы хотим использовать функцию, которую мы определили нормальным способом? Или вообще передать метод? Что-ж, для этого тоже есть возможность - ссылка на функцию. Вот так мы можем проверить строку на пустоту: Перейдем к более конкретному кейсу. Допустим, нам нужно распарсить строки определенным образом, но только в одном месте в программе. Очевидно, что логика будет повторяться. Что делать? Создадим для этого отдельный объект с одним методом? Или пропишем для каждого "ручками" прямо на месте? Нет, копить технический долг ни к чему, лучше мы сделаем, например, что-то такое: Теперь, когда мы разобрались с ФВП, перейдем к вещам, которыми, скорее всего, пользовались все.  let, run, with, apply, и also. Знакомые слова? Надеюсь, но все же разберем их.  Сначала let и also. Они наиболее просты и понятны, потому что все что они делают внутри - это вызов block(this) . По сути, мы просто делаем вызов определенной нами "на месте" функции. Разница лишь в том, что они возвращают. also используется когда вы хотите продолжить работу с тем же объектом, у которого решили вызвать функцию и let, если вам нужно вернуть новый объект. Теперь к run, with и apply:run очень похож на let, apply на also, а with это почти то же самое что и run, просто receiver получаем разными способами. Чем они удобны и зачем нужны, если есть let и also? Все просто, тут вместо it используется this, который вообще можно опустить и не писать. И как же эффективно использовать все эти функции? Мы можем и в большинстве случаев даже должны писать все наши функции полностью в функциях областей видимости. Так мы получим гарантии, что наши промежуточные значения живут ровно столько, сколько нужно, а код становится проще читать, поскольку все преобразования исходных данных теперь вытекают друг из друга, позволяя нам иметь в каждой подзадаче ровно столько информации, сколько нам надо для ее решения. Функциональная "изоляция" позволит в том числе упростить чтение и тестирование своего кода. Вы же заметили слово inline в объявлении? А оно, кстати, очень важно. К сожалению, использование функций высшего порядка влечёт за собой снижение производительности, так как функция является объектом и происходит захват контекста замыканием, то есть функции становятся доступны переменные, объявленные вне её тела. Разумное применение встроенных функций позволяет решить эту проблему. Но делать блоки встроенных функций слишком большими все равно не стоит.  Все мы уже должны были понять, что плодить иерархии и создавать экземпляры классов там, где никакого специфического поведения у отдельных экземпляров нет - дурацкая идея (хотя есть и исключения)? Это лишний раз усложняет структуру и мешает нам писать код из цепочек функций, потому что нам  нужно сначала создать бесполезный экземпляр, и только потом мы сможем воспользоваться его функционалом в блоке области видимости:  Использование объекта позволило бы нам сделать наш код проще: Как хорошо, когда нет ничего лишнего, да?  Но допустим мы все же вынуждены иметь дело с классом, у которого есть поведение, но экземпляр класса создавать не хотим? К счастью, и для этого найдется достаточно простое решение. Мы просто скинем всю статику, которая есть в объекте в companion object: Теперь мы можем сделать так же, как и с объектом. Для начала я приведу пример кода: Лично мне он не нравится. Логическая цепочка тут нарушена, поскольку мы в первую очередь хотим понимать что создание экземпляра класса Other и вызов его метода нужны просто чтобы создать экземпляр класса Some, но запись не дает моментально этого понять.  Конечно, мы можем заинлайнить его: Но у меня есть вариант получше. Было бы неплохо, если бы мы могли привязать логику, нужную только для создания объекта к... созданию объекта? И мы можем, для этого нам всего лишь нужно написать вот такой Factory-метод: Теперь мы можем сделать так: Или если класс Other тоже имеет свой фабричный метод:  Понимаю, на первый взгляд вообще стало хуже. но что если функций и необходимых объектов в иерархии станет сильно больше? Иерархия может быть достаточно большой, а данные могут требовать много преобразований. Не пытайтесь использовать это всегда и везде, но задумайтесь об этом на стадии рефакторинга.  Предполагаю, что не знать о наличии в Котлине возможности писать функции-расширения и как это делать могут совсем новички, но на всякий случай я объясню. Это функция, с которой вы можете взаимодействовать так же, как с методом класса. Вот как это выглядит: Или если хотите экзотики:  Первое, что стоит знать о таких функциях - это их приоритет исполнения. Вы не сможете перекрыть метод класса функцией-расширением. Хотя если вы напишете функцию вторым способом, IntelliJ IDEA будет показывать, как будто вы используете именно расширение - не обманывайтесь, я проверял. Теперь, давайте поговорим о ссылках на функции-расширения. Если мы сделали ее через val то все просто и понятно, передаем ее просто как foo и ничего лишнего, работаем как с любой другой переменной. Но если через fun, появляются нюансы, на которые имеет смысл обратить внимание.  Давайте посмотрим на вот такой код: В принципе, ничто не мешает нам так сделать, но есть одно "но", из-за которого я считаю это очень плохой практикой.  Все дело в том, что передать ссылку на эту функцию просто не получится. Никак. Даже внутри самого класса. Если так сделать, то Котлин просто не поймет, как обращаться к этой функции - как к методу класса Some или Other.  Однако, если мы, например, вынесем расширения в отдельный файлик под расширения определённого класса или вообще растащим их по пакетам на свое усмотрение - сможем легко обратиться к функции как Some::someExtention.  Естественно, в данном случае класс или объект не важно - поведение будет одинаковым. Кстати, если вы немножко копались в устройстве Котлина, то вот вам еще немного бесполезной информации. Допустим, вы решили непонятно зачем использовать вместо нормального способа передачи функции как параметра класс KFunction. В этом случае у меня две новости - первая в том, что ваши вкусы весьма специфичны, а вторая, что в этом случае наша функция-расширение обрабатывается в качестве самой обычной функции, у которой первый параметр это экземпляр класса, который она расширяет. Backend-разработка