본문 바로가기
@silver-w2025. 10. 9. 15:09
  1. JAVA에서 람다를 다루기 위한 노력
  2. 코틀린에서의 람다
  3. Closure
  4. try with resources (use)
 - 함수 : 코틀린에선 1급 시민, 자바에선 2급시민 
 - 코틀린에서 함수 타입 : (파라미터 타입, ..) -> 반환타입
 - 코틀린에서 람다를 사용하는 방법은 두가지 이고 이 중 중괄호 방식이 더 많이 사용된다.
 - 메서드 호출 시 마지막 파라미터인 람다를 쓸 땐 소괄호 밖으로 람다를 뺄 수 있다
 - 파라미터의 함수의 매개값이 한개 라면 it를 사용할 수 있지만 it을 사용하지 않는 것이 코드 가독성이 높다.
 - 람다 내부에 return을 사용하지 않아도 되지만 이때는 마지막 expression 결과는 람다의 반환 값이다.
 - Closure를 사용하여 final이 아닌 변수도 코틀린에서 람다로 사용가능하다.

더보기

1 . 자바에서의 람다 

 - 람다 사용 전 : 필터 요인이 많아질 수록 파라미터가 길어져 장황해진다.

public class Main {
    public static void main(String[] args) {
        // Fruits - 멤버변수로 name과 price가 있는 객체
        List<Fruit> fruits = Arrays.asList(
                new Fruit("Apple", 1_000),
                new Fruit("Apple", 1_200),
                new Fruit("Apple", 1_200),
                new Fruit("Apple", 1_500),
                new Fruit("Banana", 3_000),
                new Fruit("Banana", 3_200),
                new Fruit("Banana", 2_500),
                new Fruit("watermelon", 13_000));
    }

    List<Fruit> target(List<Fruit> fruits, String name) {
        List<Fruit> result = new ArrayList<>();
        for (Fruit fruit : fruits) {
            if (fruit.getName().equals(name)) {
                result.add(fruit);
            }
        }
        return result;
    }
}

 → 익명클래스와 인터페이스를 이용해서 코드의 양을 줄일 수 있다.

// 인터페이스 
public interface FruitFilter {
    boolean isSelected(Fruit fruit);
}

// FruitFilter 객체 
public static List<Fruit> filterFruits(List<Fruit> fruits, FruitFilter filter) {
    List<Fruit> result = new ArrayList<>();
    return result;
}


// isSelected 오버라이딩
private List<Fruit> fruits;
List<Fruit> result = filterFruits(fruits, new FruitFilter() {
    @Override
    public boolean isSelected(Fruit fruit) {
        return Arrays.asList("Apple", "Banana").contains(fruit.getName())
                && fruit.getPrice() >= 3_000;
    }
});

 → 복잡하고 다양한 filter가 필요 할 수 있음

 

▶ 이에 여러 인터페이스가 필요하게 됨

 

□ 자바 람다로 리펙토링


(1) 변수 -> 변수를 이용한 함수 
 - (변수1, 변수2) -> 변수1과 변수2를 이용한 함tn

public class Main {
    public static void main(String[] args) {
        // Fruits - 멤버변수로 name과 price가 있는 객체
        List<Fruit> fruits = Arrays.asList(
                new Fruit("Apple", 1_000),
                new Fruit("Apple", 1_200),
                new Fruit("Apple", 1_200),
                new Fruit("Apple", 1_500),
                new Fruit("Banana", 3_000),
                new Fruit("Banana", 3_200),
                new Fruit("Banana", 2_500),
                new Fruit("watermelon", 13_000));


        List<Fruit> result = filterFruits(fruits
                , fruit -> fruit.getName().equals("Apple"));
    }
}

(2) Predicate (미리 만들어져 있는 함수형 인터페이스)

package fp;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class Fruit {
    private final String name;
    private final int price;

	.....

    public List<Fruit> filterFruits2(List<Fruit> fruits, Predicate<Fruit> filter) {
        List<Fruit> result = new ArrayList<>();
        for(Fruit fruit : fruits) {
            if(filter.test(fruit)) {
                result.add(fruit);
            }
        }
        return result;
    }
}

 

(3) stream 이용

public List<Fruit> streamFruits(List<Fruit> fruits, Predicate<Fruit> fruitFilter) {
    return fruits.stream()
            .filter(fruitFilter)
            .collect(Collectors.toList());
}

 
(4) 메서드 레퍼런스 이용

public static boolean isApple(Fruit fruit) {
    return fruit.getName().equals("Apple");
}

List<Fruit> result2 = filterFruits(fruits, Fruit::isApple);

 

→ 메서드 자체를 직접 넘겨주는 '것처럼' 쓸 수 있다. 실제로 받는건 Predicate 인터페이스이다. 

 ▶ 함수를 2급시민으로 간주 : 자바에서 함수는 변수에 직접 할당, 파라미터로 바로 넘길 수 없다.

 

2 .  코틀린에서의 람다

- (함수를 1급시민으로 간주)
- 코틀린에서는 함수가 그 자체로 값이 될 수 있고, 변수에 할당할수도, 파라미터로 넘길 수도 있다. 

package fp

fun main() {
    val fruits = listOf(
        Fruit("apple", 1_000),
        Fruit("apple", 1_200),
        Fruit("apple", 1_300),
        Fruit("apple", 1_400),
        Fruit("apple", 1_500),
        Fruit("banana", 2_500),
        Fruit("banana", 3_500),
        Fruit("watermelon", 13_500),
    )
    // 함수의 타입을 (매개변수타입) -> 반환타입으로 명시할 수 있다.
    // 람다 1 - 이름 빼기
    val isApple: (Fruit) -> Boolean = fun(fruit: Fruit): Boolean {  // 함수이름 x
        return fruit.name == "apple"
    }
    // 람다 2 - 중괄호와 -> 이용
    val isApple2: (Fruit) -> Boolean = { fruit: Fruit -> fruit.name == "apple"}

    // 람다 호출 1
    isApple(fruits[0])
    // 람다 호출 2 invoke로 명시적이게
    isApple2.invoke(fruits[1])
}


- filterFruit 구현 :  파라미터에 함수를 넣을 수 있다.

package fp

fun main() {
    val fruits = listOf(
		...
    )
    
    // filterFruit 매개값에 들어가는 변수(함수) 구현
    val isApple = fun(fruit: Fruit): Boolean {
        return fruit.name == "apple"
    }
    // filterFruit 호출
    filterFruits(fruits, isApple)
}
// 자바 filterFruit를 코틀린으로 구현
private fun filterFruits(
    fruits: List<Fruit>, filter: (Fruit) -> Boolean
): List<Fruit> {
    val results = mutableListOf<Fruit>()
    for (fruit in fruits) {
        if (filter(fruit)) {
            results.add(fruit)
        }
    }
    return results
}

익명함수이기 때문에 매개값에 함수를 바로 넣어주어도 된다
이 때, 람다를 여러줄 작성할 수 있고, return을 명시하지 않아도 마지막 줄의 결과를 람다의 반환값으로 본다.

filterFruits(fruits, fun(fruit: Fruit): Boolean {
    return fruit.name == "apple"
})
또는 
filterFruits(fruits,{ fruit: Fruit -> fruit.name == "apple" })

 

 매개값에 변수와 함수를 구분하기 위해 괄호를 구분할 수 있다, 이경우 {}안의 함수는 마지막 인자로 사용된다

또한 람다의 파라미터를 it으로 직접 참고할 수 있다.

filterFruits(fruits){ fruit: Fruit -> fruit.name == "apple" }

// filterFruits에 타입을 명시했기 때문에 위 Fruit 타입도 생략가능하다(타입추론)
filterFruits(fruits){ fruit -> fruit.name == "apple" }

// 타입추론도 가능하고 함수의 파라미터도 하나라면 -> 까지 생략가능하다 (it 키워드 이용)
filterFruits(fruits){ it.name == "apple" }

 

3 .  Closure

- Java에서는 람다를 사용할 때 변수는 final인 변수 혹은 실질적으로 final인 변수만 사용할 수 있는 반면 코틀린에서는 문제없이 작동한다

var targetFruitName = "watermelon"
targetFruitName = "banana"
filterFruits(fruits) { it.name == targetFruitName }

(targetFruitName이 가변이여도 동작함)

 

□ 코틀린에서는 람다가 시작하는 지점에 참조하는 변수들을 모두 캡쳐함.

이는 코틀린에서 람다를 일급 시민으로 간주하기 위해서이며, 이 데이터 구조를 Closure라고 한다.
 

4 . try with resources (use)

use 메서드

 (1) Closable 구현체의 확장 함수
 (2) inline 함수

 (3) 받고 있는 파라미터 = block 함수

 


 

※ (intellij) 코틀린 코드 자바로 변환
tool > Kotlin > Show Kotlin Bytecode


출처 : https://inf.run/sMPv5

 

자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)| 최태현 - 인프런 강의

현재 평점 5.0점 수강생 3,556명인 강의를 만나보세요. 이 강의를 통해 Kotlin 언어의 특성과 배경, 문법과 동작 원리, 사용 용례, Java와 Kotlin을 함께 사용할 때에 주의할 점 등을 배울 수 있습니다. Ko

www.inflearn.com

 

silver-w
@silver-w :: silver-w 님의 블로그

silver-w 님의 블로그 입니다.

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차