JAVA/BASIC

[스프링 JdbcTemplate 참조용] 익명클래스와 람다식

유혁스쿨 2020. 9. 2. 18:41
728x90
반응형

익명클래스

익명클래스를 사용하기 위해서는 추상클래스나 인터페이스가 필요합니다.

 

인터페이스는 객체를 생성할수가 없으므로 인터페이스의 필드를 사용하기 위해서는 따로 인터페이스를 구현받아 재정의하여 사용하도록 인터페이스를 구현받을 클래스가 필요합니다.

 

인터페이스 A를 구현받은 클래스 B가 있습니다.

클래스 B는 인터페이스에 선언된 추상메서드를 c()를 @Override 재정의하여 사용합니다.

B 클래스의 객체 b 를 만들고 b객체를통해 c메서드를 호출하여 재정의된 기능을 사용하게 됩니다.

 

정적메서드가 아닌 일반적인 메서드를 사용하는데 있어서 객체를 통해 접근하는 방법이 정석이지만

만약 이 메서드를 딱 한번만 사용할 것 이라면

"b 객체를 생성해야하는것이, 굳이 클래스를 따로 만드는과정을 해야하는것인가."

"딱 한번만 사용할건데 클래스를 새로만드는게 과연 합리적인 방법인가."

생각을 되짚어 볼수 있습니다.  

 

이때 사용되는 것이 익명클래스 입니다.

상속,구현을 통해 기능을 재정의 하여 사용해야 할때 필요한 방법이므로 추상클래스나 인터페이스가 필요한것입니다.

 

[인터페이스↓]

public interface Car {
    void run(); 
}

[구현클래스↓]

public class Sonata implements Car {

    @Override
    public void run() {
        System.out.println("소나타는 씽씽 달립니다.");
    }
    
}

[메인클래스↓]

public class AnonymousTest {

    public static void main(String[] args) {
        Sonata sonata1 = new Sonata();
        Car sonata2 = new Sonata();
        sonata1.run();
        sonata2.run();       
}

 

만약 페라리 차 를 구매해서 쌩쌩 달리고 싶습니다.

 

"딱 한번만 주행시킬건데 굳이 클래스를 만들어야할까?" 
"그러면 이름없는 ferrari클래스를 Car인터페이스 안에다가만들수는없을까? "

 

우선 Car는 인터페이스를 생성해봅니다.

Car ferrari = new Car();

하지만 Car는 인터페이스기때문에 객체로 생성할 수 없습니다

 

Car ferrari = new Car() { };

클래스를 만들때 처럼 { }블록을 선언해줍니다.

{ } 블록안에 Car인터페이스의 추상메서드인 run( ) 메서드를 오버라이딩 해주면 됩니다.

 

이것은 이클립스의 기능으로도 생성이 됩니다.

new Car()에 빨간밑줄이 생기면서 마우스를 올렸을 때 오바라이딩 하라는 상자가 열립니다

Java의 익명클래스 문법을 이클립스 에서도 인식하고 있는 것이죠.

 

완성된 코드입니다.

 

 Car ferrari = new Car() {
        
    @Override
    public void run() {

    }
            
};

오바라이딩된 run( )메서드 안에 내용을 재정의 하면

public class AnonymousTest {
    
    public static void main(String[] args) {
    
        Car ferrari = new Car() {
        
            @Override
            public void run() {
                System.out.println("페라리를 쌩쌩 달립니다~");
            }
            
        };
        
        ferrari.run();
    }
}

익명클래스 문법으로 구현한 로직입니다.

 

 

또,

public class AnonymousTest {
    
    public static void main(String[] args) {
    
        new Car() {
            @Override
            public void run() {
                System.out.println("그냥 차가 달린다");
            }
        }.run();
    };
}

이렇게도 구현이 가능합니다.

 

이런방법으로 구현하는것이 익명클래스 문법입니다.

어떠세요? 마치 Car인터페이스안에 이름없는 클래스가 있는것과 같은 느낌이 들지 않나요?

 

 

익명클래스 문법은 추상클래스, 인터페이스의 추상메서드가 단 한개만 선언 되 있다면 람다식으로 한번 더 변환 하여 코드를 줄일 수 있습니다.

람다식의 개념에 대해서는 아직 정리하진 않았지만 어떻게 변하는지 코드해보겠습니다

 

[익명클래스↓]

public class AnonymousTest {

    public static void main(String[] args) {
        
        //익명클래스
        Car tucSon1 = new Car() {
			
            @Override
            public void run() {
                System.out.println("익명투싼 이 달림다");
            }
            
        };

        tucSon1.run();//익명클래스 구현을 통한 메서드 호출
     }
     
}

 

[람다식]

public class AnonymousTest {

    public static void main(String[] args) {
        
        //람다식
        Car tucSon2 = () -> {System.out.println("람다투싼 이 달립니다.");};

        tucSon2.run();//람다식 구현을 통한 메서드 호출
        
     }
     
}

이렇게 코드라인이 짧아질수 있다는게 너무신기합니다.


람다식

람다식은 익명클래스를 만드는 과정을 더 생략할수 있는 문법입니다.

람다식이 적용될때는 추상클래스 혹은 인터페이스 안에 정의된 추상 메서드딱 하나인 경우에만 가능합니다!

 

[인터페이스↓]

public interface Calculator {
	
	int add(int n1, int n2);

}

[익명클래스↓]

public class AnonymousTest {

    public static void main(String[] args) {
    
        Calculator sharp = new Calculator() {
        
            @Override
            public int add(int n1, int n2) {
                System.out.println("샤프 계산기의 덧셈!");
                return n1+n2;
            }
            
        }; 
        
       	System.out.println(sharp.add(10, 15));

        
    }
    
}

[람다식문법↓]

public class AnonymousTest {

    public static void main(String[] args) {
    
        Calculator casio = (n1, n2) -> { 
            System.out.println("샤프계신기의 덧셈!");
            return n1+n2;
        };

        System.out.println(casio.add(100, 200));
        
    }
    
}

인터페이스를 통해서 익명 클래스를 만들어 사용하려는데

"어? 가만보니 인터페이스에 선언된 추상메서드가 한개만있네? 하나만 있는데 그냥 값만받아주자!"

하고 ( , ) 안에는 add()메서드를 수행하기위해 넣어줄 매개 값만 받고 -> 화살표와 { } 문법을 사용해서

받은 매개값을 -> 전달하여 { } 블록안에 추상메서드 add()에 직접 구현할 기능을 로직코드로 작성하면 되는것 입니다.

 

 

심지어 더 짧게 쓸수도있습니다. 

public class AnonymousTest {

    public static void main(String[] args) {
    
        Calculator shaomi = (x,y) -> {
            return x+y;
        };        
        
        System.out.println("샤오미 결과 : "+shaomi.add(100, 10));
    }
    
}

 

return이 없는 void 메서드 형태와 흡사합니다

public class AnonymousTest {

    public static void main(String[] args) {

        Calculator shaomi = (x,y) -> x+y;
             
        System.out.println("샤오미 결과 : "+shaomi.add(100, 10));
    }
    
}

리턴을 제외한 다른 어떠한 작업을 하지 않을때 더 줄일수 있습니다.
return말고 할게 없으면 블록을 지우고 블록을 지우는 김에 return도 함께 지우는것입니다.

 

 

 

익명클래스에서는 인터페이스의 추상메서드를 오버라이딩을 하여 사용합니다.

람다식은 익명클래스를 구현해주는 인터페이스의 추상메서드가 단 한개일때 코드를 줄여주기때문에

람다식을통해 Calculator 인터페이스의 추상메서드 shaomi() 를 오버라이딩 해준것과 같습니다.

 

이처럼 람다식은 익명클래스를 만드는 과정에서 구현 상속해주는 부모 오브젝트의 추상메서드가 하나라면 코드를 더 생략 해서 사용하는 문법 입니다.

728x90
반응형