카테고리 없음

1222 Java(이벤트, 람다식, 일반화 T)

버스창문 2025. 12. 22. 16:04

Java엔 delegate가 없다

c#에서 대리자등을 이용해서 다른쪽에 함수 구현해서 이벤트 구독시키던거 생각하면 좀 불편하긴한데 비슷하게라도 쓸 수 있다.

뭐가 됐든 금요일에 Json으로 정신나갈뻔 했던 것보다는 훨씬 낫다.

public interface OnAttackListener {
    void onAttack(String attacker, String target, int damage);
}

인터페이스로 미리 이벤트 틀을 구현해놓는다.

public class BattleSimulator {

    private OnAttackListener listener;

    // 콜백 등록
    public void setOnAttackListener(OnAttackListener listener) {
        this.listener = listener;
    }

    public void attack(String attacker, String target, int damage) {
        System.out.println(attacker + " attacks " + target);

        // 공격 처리 후 콜백 호출
        if (listener != null) {
            listener.onAttack(attacker, target, damage);
        }
    }
}

구현해놓은 이벤트 틀을 변수로 미리 잡아두고, 그걸 할당하는 함수를 구현해놓는다.

그리고 할당된게 있으면, 실행되도록 셋팅까지

public static void Q8()
    {
        BattleSimulator battle = new BattleSimulator();

        battle.setOnAttackListener(new OnAttackListener() {
            @Override
            public void onAttack(String attacker, String target, int damage) {
                System.out.println("[LOG] " + attacker + " dealt " + damage + " to " + target);
            }
        });

        battle.attack("Hero", "Orc", 15);
    }

setOnAttackListener의 매개변수를, 마치 c#의 무명함수처럼 해놓은 모습이다.

인터페이스였으니 @Override를 붙이고 구조를 구현해놓은 모습

Hero attacks Orc
[LOG] Hero dealt 15 to Orc

결과창

 

 

 

delegate, 무명함수 = 지루하고 현학적임, 코드 꼬이면 봐야할게 늘어남, 세상이 무너짐

람다식 = 금방끝남, 사전작업이 필요X

 

 

c#에서조차 지루하고 현학적인 무명함수따위는 개념만 배우고 바로 치워버리고 람다식을 갈겼던걸 생각하면 아주 그립다.

public static void Q8_1()
    {
        BattleSimulator battle = new BattleSimulator();

        battle.setOnAttackListener(
            (attacker, target, damage) -> {
                System.out.println("[LOG] " + attacker + " -> " + target + " (" + damage + ")");
            }
        );

        battle.attack("Hero", "Slime", 7);
    }

물론 여기에도 람다식은 있지만, 문법이 살짝 다르다.

c#에선 => 였었을텐데

최소한 그 외의 괄호치고 안에 매개변수 써놓는 등의 문법은 다 똑같아보이니 다행이다.

 

 

 

Action과 Func

c#에서 대리자를 편하게 쓰게해줬던 1등공신들

Java에서도 있다

public class Player{
    private String name;
    private int level;
    private int exp;
    public Consumer<String> damageAction;

    public void TestDamageAction(String test)
    {
        damageAction.accept(test);
    }
public static void main(String[] args) throws Exception {
        System.out.println("Hello, World!");

        Player p_Test = new Player("asdf", 1,2);
        p_Test.damageAction = (s) -> 
        {
            System.out.println(s);
        };
        p_Test.TestDamageAction("asdf");

        //Q8_1();
    }

 

이름은 조금 다르지만, 매우 익숙한 그 형태를 보니 마음이 편안해지는것같다.

차이점은 .accept를 찍어야 사용이 된다는점

 

 
import java.util.function.Consumer;

그리고 이거 선언해놔야 작동한다는점

c#에서 대충 쓰면 위에거 자동으로 생성해줬었던걸 생각하면 이게 진짜 제일 불편하다.

 

그리고 c#에선 안에 들어갈수있는 매개변수를 그냥 미친듯이 만들어놔서 사실상 제한이 없었지만,

consumer 얘는 단 하나, 그리고 2개까지 쓸수있게 BiConsumer라는게 있다.

3개 이상부턴 없는데, 3개 이상 써야한다면 DTO를 만들어서 consumer에서 쓴다고한다

 

 

 

일반화 T

 

import java.util.ArrayList;
import java.util.List;

public class Box<T> {
    List<T> box;
    public Box()
    {
        this.box = new ArrayList<>();
    }
    public void add(T a)
    {
        box.add(a);
    }
    public void printAll() {
    for (T item : box) {
        System.out.print(item + " ");
    }
    System.out.println();
}
}
public static void Q9()
    {
        Box<Integer> box = new Box<>();
        box.add(1);
        box.add(2);
        box.printAll();
    }
1 2

이건 그냥 별 차이없는것같다.

인스턴스 생성할때 new Box<> << 이 괄호 안에 아무것도 안넣는거정도

List 생성할때부터 해서 왜 자꾸 변수타입이랑 옆에 인스턴스 형태가 다른건지 아주 화딱지가 난다

 

그리고 foreach가 없고,

for(T item : box)

        변수 ,  배열

 

이런 형태로 사용한다.