고차 함수는 다른 함수를 인자로 받거나 함수를 반환하는 함수이다.
(Int, String) -> Unit
(Int, String?) -> String?
((Int, Int) -> Int)?
fun performRequest(
url: String,
callback: (code: Int, content: String) -> Unit
) {
/*...*/
}
fun main(args: Array<String>) {
val url = "http://kotl.in"
performRequest(url) { code, content -> /*...*/ }
performRequest(url) { code, page -> /*...*/ }
}
FuntionN
인터페이스를 구현하는 객체로 저장된다.interface Function0<R> {
R invoke();
}
interface Function1<P1, R> {
R invoke(P1 p1);
}
interface Function2<P1, P2, R> {
R invoke(P1 p1, P2 p2);
}
// ...
public class UsingForEach {
public static void main(String[] args) {
List<String> strings = new ArrayList();
strings.add("42");
CollectionsKt.forEach(strings, s -> {
System.out.println(s);
return Unit.INSTANCE;
});
}
}
funParam?.invoke(...)
invoke
메서드를 구현하는 인터페이스 (FunctionN
)fun foo(callback: ((Int) -> Int)?) {
// ...
val response = callback?.invoke(1) ?: 0
// ...
}
inline
함수 : 람다의 부가 비용 없애기어떤 함수를 inline
으로 선언하면, 그 함수의 본문이 inline 된다.
Sequence.map
함수의 경우, inline
으로 선언되어 있지 않다.
왜냐하면 람다 함수 파라미터를 다른 클래스 생성자의 파라미터로 넘겨주기 때문이다.
따라서 해당 함수 타입의 파라미터를 무명 클래스 인스턴스로 만들어야 한다.
이런 경우 inline
으로 선언하면 안된다.
public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R> {
return TransformingSequence(this, transform)
}
noinline
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
// ...
}
inline
선언되어 있다.Sequence
의 경우 inline
선언이 되어 있지 않다.Sequence
가 성능에 유리public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
return filterTo(ArrayList<T>(), predicate)
}
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
try-wtih-resource
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
use
fun readFirstLineFromFile(path: String): String {
BufferedReader(FileReader(path)).use { br ->
return br.readLine()
}
}
@InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
this?.close()
} catch (closeException: Exception) {
}
throw e
} finally {
if (!closed) {
this?.close()
}
}
}
non-local return
람다 안에서 return을 사용하면 람다로부터만 반환되는게 아니라,
그 람다를 호출하는 함수가 실행을 끝내고 반환한다.자신을 둘러싸고 있는 블록보다 더 바깥에 있는 다른 블록을 반환하게 만드는 return문을
non-local return
이라 부른다.
data class Person(val name: String, val age: Int)
val people = listOf(Person("Alice", 29), Person("Bob", 31))
fun lookForAlice(people: List<Person>) {
for (person in people) {
if (person.name == "Alice") {
println("Found!")
return
}
}
println("Alice is not found")
}
fun main(args: Array<String>) {
lookForAlice(people) // Found!
}
fun lookForAlice(people: List<Person>) {
people.forEach {
if (it.name == "Alice") {
println("Found!")
return
}
}
println("Alice is not found")
}
fun main(args: Array<String>) {
lookForAlice(people) // Found!
}
fun lookForAlice(people: List<Person>) {
people.forEach {
if (it.name == "Alice") return@forEach
}
println("Alice might be somewhere")
}
fun main(args: Array<String>) {
lookForAlice(people) // Alice might be somewhere
}
fun lookForAlice(people: List<Person>) {
people.forEach(fun (person) {
if (person.name == "Alice") return
println("${person.name} is not Alice")
})
}
fun main(args: Array<String>) {
lookForAlice(people) // Bob is not Alice
}
fun main(args: Array<String>) {
println(StringBuilder().apply sb@{
listOf(1, 2, 3).apply {
this@sb.append(this.toString())
}
})
}
people.filter(fun (person): Boolean {
return person.age < 30
})
people.filter(fun (person) = )
fun lookForAlice(people: List<Person>) {
people.forEach(fun (person) {
if (person.name == "Alice") return
println("${person.name} is not Alice")
})
}
fun main(args: Array<String>) {
lookForAlice(people)
}