갈림길 이정표

[java] 람다식 표현 본문

Programming Language/Java 마스터하기(feat. 이것이 자바다)

[java] 람다식 표현

이몽뇽 2020. 8. 7. 09:26
package pack;

public class myLamda {
	
	//지금까지의 전통적인 방법 (legacy)
	/*static class Inner implements HelloInter{
		
		@Override
		public int addData(int a, int b) {
			return a + b;
		}
	}*/
	
	
	public static void main(String[] args) {
		//전통적 방법									//1. 인터페이스 클래스 (Function annotation) 만듦
		/*Inner inner = new Inner();				//2. (오버라이드 한뒤) 객체 생성 
		System.out.println(inner.addData(3, 4));*/
													//전통적 방법의 한계: FuntionInterface 에선 두개 이상의 메소드를 정의할 수 없음
		
		
		//람다 표현식 (새로 추가된 방법)
		HelloInter h_inter = (x, y) -> x + y;	//(클래스명) 객체 = (parameter) -> 함수;
		System.out.println(h_inter.addData(3, 4));
		
		HelloInter h_inter2 = (x, y) -> x * y;	//(클래스명) 객체 = (parameter) -> 함수2;
		System.out.println(h_inter2.addData(3, 4));
		
	}

}
package pack;

@FunctionalInterface	// ← 추상 메소드 하나만 만들도록 강요하는 '제약 annotation' (java의 한계)
public interface HelloInter {
	int addData(int a, int b);
//	int addData2(int a, int b); → 안돼(X)
}
package pack;

public interface MyInterface {
	void abc();
}

//---------------------------------------------------//

package pack;

public interface MyInterArg {	//Arg (argument = parameter)
	void def(int a, int b);
}

//---------------------------------------------------//


package pack;

public interface MyInterArgRetrun {	
	int def(int a, int b);			//결과값이 있는 메소드
}

//===================================================//


package pack;

public class MyInterMain {
	public static void main(String[] args) {
		//Lambda test
		//1. 인자가 없는 추상 메소드 처리
			//전통적 방법
		MyInterface interface1 = new MyInterface() {	//Interface 는 새로운 객체생성 불가 (단지, 추상메소드 오버라이딩 하기 위함)
			@Override									//= 내부 무명클래스 선언
			public void abc() {
				System.out.println("일반적인 익명 클래스의 메소드 오버라이드" + "(전통적 방법)");
			}
		};
		interface1.abc();	//오버라이딩 했으므로 가능
		
			//람다식 방법 (오버라이딩 할 때 메소드이름 언급 안해도 됨 → 코드 길이 줄일 수 있다.)
//		MyInterface interface2 = () -> {System.out.println("일반적인 익명 클래스의 메소드 오버라이드");};	//괄호 (블록 수) 주의
		MyInterface interface2 = () -> System.out.println("일반적인 익명 클래스의 메소드 오버라이드" + "(람다식 방법)");
		interface2.abc();
		
		System.out.println();
		MyInterface interface3 = () -> {		//복수개 메소드 수행시 블럭화 필요
			System.out.println("람다식 표현");
			System.out.println("복수 메소드일 경우");
			System.out.println("블럭화 필요");
			
		};	//세미클론(;) 꼭 표시!
		interface3.abc();
		
		System.out.println("===================");
		
		//2. 인자가 있는 추상 메소드 처리
			//전통적 방법
		MyInterArg interArg = new MyInterArg() {
			
			@Override
			public void def(int m, int n) {
				System.out.println("두수의 합은 " + (m + n) + "(전통적 방법)");
			}
		};
		interArg.def(3, 4);
		System.out.println();
		
			//람다식 표현
		MyInterArg interArg2 = (m, n) -> System.out.println("두수의 합은 " + (m + n) + "(람다식 방법)");
		interArg2.def(3, 4);
		
//		※매개변수가 하나일 경우에는 parameter '()' 안해도 됨
//		MyInterArg interArg2 = (m) -> System.out.println("합은 " + (m + m));
//		MyInterArg interArg2 = m -> System.out.println(" 합은 " + (m + m));
		
		System.out.println("===================");
		
		//3.반환값이 있는 추상 메소드 처리
			//전통적 방법
		MyInterArgRetrun interArgReturn = new MyInterArgRetrun() {
			
			@Override
			public int def(int a, int b) {
				/* ... */
				return a + b;
			}
		};
		
		int result = interArgReturn.def(3, 4);
		System.out.println("result: " + result + "(전통적 방법)");
		
		System.out.println();
		
			//람다식 표현
		MyInterArgRetrun interArgRetrun2 = (a, b) -> {
			/* ... */
			return a + b;
		};
		int result2 = interArgRetrun2.def(3, 4);
		System.out.println("result: " + result2 + "(람다식 방법)");
		
		MyInterArgRetrun interArgRetrun3 = (a, b) -> /*return*/ a * b;	//statement가 하나일 경우 return 생략
		int result3 = interArgRetrun3.def(3, 4);
		System.out.println("result: " + result3 + "(람다식 방법)");
	}
}
package pack;

public class ThreadLambda {

		
		public ThreadLambda() {
			m1();
			m2();
			m3();
			m4();
		}
		
		//전통적 방법
		void m1() {
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					sendEmail("m1");
				}
			}).start();
		}
		
		//람다식 방법1
		void m2() {
			Thread thread = new Thread(() -> sendEmail("m2"));	//객체생성 후
			thread.start();										//메소드 선언
		}
		
		//람다식 방법2
		void m3() {
			new Thread(() -> sendEmail("m3")).start();			//객체 생성하자마자 메소드 선언
		}
		
		//람다식 방법3
		void m4() {
			Runnable runnable = () -> sendEmail("m4");			//인터페이스 오버라이딩 후
			runnable.run(); 	//Thread -> start();			//메소드 선언
								//Runnable -> run();
		}
		
		public void sendEmail(String ss) {
			System.out.println(ss + " 메세지 전송");
		}
		
		
		public static void main(String[] args) {
			new ThreadLambda();
		}
}
package pack;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class ButtonEventLambda extends JFrame {

	public ButtonEventLamabda() {
		super("lambda");
		
		layInit();
		setBounds(300, 300, 300, 300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	private void layInit() {
		setLayout(null);	//레이아웃 설정 안함 선언
		
		//전통적 방법
		JButton btn = new JButton("button 1");
		btn.setBounds(10, 50, 100, 50);
		add(btn);
		
		//java[객체지향언어]에서 람다[함수형 언어]는 제한적 (인터페이스에 추상메소드가 하나일 경우에만 쓸 수 있기 때문 -> 하지만, 편리성을 위해 자주 쓰인다)
		
		btn.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				
				setTitle("첫번째 버튼 클릭");
			}
		});
		
		//람다식 방법 (오버라이딩 할 메소드가 하나기 때문에 가능)
		JButton btn2 = new JButton("button 2");
		btn2.setBounds(10, 150, 100, 50);
		add(btn2);
		
		/*btn2.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {

				setTitle("첫번째 버튼 클릭");
			}
		});*/		//argument "()"사이를 드래그 하여 오른쪽 클릭 후 Quick fix 하면 자동 람다식 변환
		btn2.addActionListener(e -> setTitle("두번째 번튼 누름"));
		
	}
	
	public static void main(String[] args) {
		new ButtonEventLambda();
	}

}
package pack;

public class JikwonDTO {	//DTO (Data Transfer Objective)
	public int no;
	private String name;
	private String phonenum;
	
	public JikwonDTO(int no, String name, String phonenum) {
		this.no = no;
		this.name = name;
		this.phonenum = phonenum;
	}
	
	@Override
	public String toString() {
		return no + " " + name +" " + phonenum;
	}
}

//-------------------------------------------------------------//

package pack;

import java.util.ArrayList;
import java.util.Collections;	//Collection (X)
import java.util.Comparator;	//람다식 표현 쓰임을 위해
public class JikwonMain {
	static ArrayList<JikwonDTO> jikwons = new ArrayList<JikwonDTO>();		//순서가 있고 중복 허용
	/* list류 & Map류 복습하기! */ 
	static {	//(static)메인에서 바로 부르기 위해
		jikwons.add(new JikwonDTO(3,"홍길동", "111-1111"));
		jikwons.add(new JikwonDTO(1,"고길동", "222-1111"));
		jikwons.add(new JikwonDTO(2,"신길동", "333-1111"));
		jikwons.add(new JikwonDTO(4,"지길동", "666-1111"));
		jikwons.add(new JikwonDTO(5,"이길동", "155-1111"));
		System.out.println("정렬 전: " + jikwons.toString());//오버라이딩 된 toString 메소드
	}
	
	
	public static void main(String[] args) {
		
		//1. 익명 클래스 (전통적 방법)
		Collections.sort(jikwons, new Comparator<JikwonDTO>() {
			@Override
			public int compare(JikwonDTO o1, JikwonDTO o2) {	//양수,0=자리바꿈, 음수 = 자리 안바꿈
				return o1.no - o2.no;		//원래는 private 멤버 get해서 써야함
//				return o2.no - o1.no;		
			}
		});
		System.out.println("정렬 후: " + jikwons.toString());
		
		System.out.println("========");
		
		//2. 람다식 표현 (Comparator 추상 메소드 하나있어서 가능)
		Collections.sort(jikwons, (o1, o2) -> o1.no - o2.no);	//JikwonDTO 를 쓰지 않고 
		System.out.println("정렬 결과: " + jikwons.toString());
		
		System.out.println("========");
		//(향상된 for문)
		ArrayList<Integer> arr = new ArrayList<Integer>();
		for (int i = 1; i <= 10; i++) {
			arr.add(i);		//i(기본형 변수)를 arr(참조형 변수)로 바꿔주는 메소드 add();
		}
		
			//1.전통적 방법
		for(Integer i:arr) {
			System.out.println(i);
		}
		System.out.println();
		
			//2. 람다식 표현
		arr.forEach(i -> {
			System.out.println(i);
		});
		
	}

}
Comments