[Java]::Remind - Lambda Expression

Gentlee's Self-Study Log·2023년 5월 26일
1

Java Reminder

목록 보기
19/19
post-thumbnail

Lambda Expression - 람다식

람다식이란 "식별자없이 실행가능한 함수"이다.

함수지만, 따로 함수를 생성하지않고 코드 한 줄에 함수를 써서 그것을 호출하는 방식이다.
함수적 프로그래밍을 위해 자바 8부터 람다식(Lambda Expressions)을 지원하면서 코드의 문법이 간결해져 가독성 면에서 장점이 돋보이다.

인터페이스 사용

인터페이스 사용방법 - 익명클래스

흔히 인터페이스는 클래스에서 상속받아 메서드를 오버라이드하며 사용된다. 또 클래스 생성없이 익명 클래스를 만들어서 사용 가능하다.

익명클래스 예시 1

public static void main(String[] args){
	Myinterface m = new Myinterface(){  

        @Override
        public void print(){
        	System.out.println("hello");
        }

    }
    m.print();
}

익명클래스 예시 2

public static void main(String[] args){
	(new Myinterface() {
	
    	@Override
        public void print(){
        	System.out.println("hello");
        }
  
    }).print();
}

인터페이스 사용방법 - 매개변수

인터페이스는 매개변수로도 참조가 되어 사용이 가능하다.

매개변수 예시

public static void myMethod(Myinterface f){
	f.print();
}

public static void main(String[] args){
	Myinterface m = new Myinterface(){

        @Override
        public void print(){
        	System.out.println("hello");
        }

    }
    myMethod(m);
}

인터페이스 사용방법 - 리턴타입

인터페이스를 리턴타입으로도 반환할 수 있다.

리턴타입 예시

public static Myinterface myMethod() {

    return new Myinterface(){

            @Override
            public void print(){
                System.out.println("hello");
            }
    	}
}

public static void main(String[] args){
	Myinterface m = myMethod();
    m.print();
}

이렇게 인터페이스를 사용할 때, 여러가지 방법이 있지만, 익명 클래스와 매개변수, 리턴타입으로 쓸 때는 코드가 복잡해지고 가독성이 떨어지는 단점때문에자바 8버전부터는 람다식이 생겼다.

람다식

람다식의 문법은 하나의 명령문을 가지고 있냐, 여러개를 가지고 있냐에 따라 다르다.

여러개의 명령문을 가지고 있는 경우

(인수 리스트) -> {
	명령문1;
	명령문2;
    retunr 값;
}

하나의 명령문을 가지고 있는 경우

(인수 리스트) -> 명령문

예시

위에 나온 리턴타입으로 사용된 인터페이스 사용방법 예시를 람다식으로 표현한다면 아래 예시처럼 나온다.

// 리턴타입으로 나온 인터페이스
/*
public static Myinterface myMethod() {

    return new Myinterface(){

            @Override
            public void print(){
                System.out.println("hello");
            }
    	}
}
*/

// 람다식으로 표현
public static void main(String[] args){
	Myinterface m = () ->  System.out.println("hello");
    m.print();
}

람다식 주의사항

위 예시처럼 람다식을 사용하려면 interface자체에 메소드가 두개 이상이 있으면 안되고 오직 한개만을 메소드로 가지고 있는 interface만 람다식으로 사용할 수 있다.

그렇기 때문에 @FunctionalInterface 어노테이션으로 인터페이스에 표시하면 람다식을 사용하기 더 편하다.

람다식 표현

매개변수

매개변수가 없는 경우

interface Myinterface(){
	public void print();
}

Myinterface m1 = () -> {System.out.println("Hi");}
Myinterface m2 = () -> System.out.println("Hi");

m1.print();
m2.print();

매개변수가 있는 경우에는 매개변수 이름만 적고 람다식표현을 진행한다.

매개변수가 있는 경우

interface Myinterface1(){
	public void print(String s1);
}
interface Myinterface2(){
	public void print(String s1, String s2);
}

Myinterface1 m1 = (s1) -> System.out.println(s1);
Myinterface1 m1 = s1-> System.out.println(s1); // ()괄호 생략가능
m1.print("Hello");

Myinterface2 m2 = (s1, s2) -> System.out.println(s1+":"+s2);
m2.print("Seoul","Korea");

리턴 값

리턴 값이 없는 경우

interface Myinterface(){
	public void print();
}

Myinterface m1 = () -> {System.out.println("Hi");}
m1.print();

리턴 값이 있는 경우

interface Myinterface(){
	public String getMessage();
}

Myinterface m = () -> {
	String message = "Hello";
    return message;
}

리턴 문 하나만 있는 경우

interface Myinterface(){
	public int sum(x,y);
}

Myinterface m = (x,y) -> x+y;
int r = m.sum(15,20); // 결과 : 35

변수 사용

람다식이 지역변수를 사용하기 위해서는 지역변수가 final 상수 여야 한다. 하지만, 메소드에서 인자로 넘어온 값을 람다식이 사용할때, 자바에서 그 값을 final상수 취급을 하기 때문에 사용가능하다.

interface Myinterface(){
	public void print();
}

public class Test{

	public void test(String s){
    	
        Myinterface m= () -> {
        	System.out.println(s);
        };
        m.print();
    }
}

public static void main(String [] args){
	Test t = new Test();
    t.test("hello");
}

하지만 지역변수를 사용할때 수정을 한다면 에러가 난다.


interface Myinterface(){
	public void print();
}

public class Test{

	public void test(String s){
    	
        Myinterface m= () -> {
        	s = s.toUpperCase();   // 오류
        	System.out.println(s);
        };
        m.print();
    }
}

public static void main(String [] args){
	Test t = new Test();
    t.test("hello");
}

멤버변수는 수정 가능 하다.

public class Test{
	
    Strng name="홍길동";
    
	public void test(String s){
    	
        Myinterface m= () -> {
        	name = name.toUpperCase();   // 오류
        	System.out.println(name);
        };
        m.print();
    }
}

함수형 인터페이스

제공되는 api(java.util.function)중에서 람다식으로 표현할 수 있는 함수형 인터페이스는 간단한 코드로 여러가지 작업을 가능하게 한다.

Function<T,R>

인자값도 있고 리턴값도 받고자 할 때 사용하는 함수형 인터페이스다. apply()메소드를 가지고 있다.

public static void main(String[] args){
	Function<String, Date> date = (s) ->{
    	Date d = null;
        try{
        	d = new SimpleDateFormat("YY/MM/DD").parse(s);
        }catch(ParseException e){
        	e.printStackTrace();
        }
        return d;
    };
    
    Date today = date.apply("2023/05/26");
    System.out.println(today);
}

Predicate< T >

인수를 받고 boolean타입으로 리턴을 하는 함수형 인터페이스다. test()메소드를 가지고 있다.

public static void main(String[] args){
	Predicate<String> check = (s) -> s.equals("java");
    boolean result = check.test("java");
    System.out.println(result);
}

Consumer< T >

인수를 받지만, 리턴값이 없는 함수형 인터페이스다. accept()메소드를 가지고 있다.

public static void main(String[] args){
	Consumer<Date> datePrint = (date) -> {
    	String s = new SimpleDateFormat("YY/MM/DD").format(date);
        System.out.println(s);
    };
    datePrint.accept(new Date());
}

Supplier< T >

인수는 받지 않고 T타입의 값을 리턴받는 함수형 인터페이스다. get()메소드를 가지고 있다.

public static void main(String[] args){
	Supplier<String> city = () -> {
    	String[] arr = {"서울","대구","대전","부산","인천"};
        int index = (int)(Math.random()*5);
        return arr[index];
    };
    
    String s = city.get();
    System.out.println(s);
}
profile
https://github.com/SamGentlee

0개의 댓글