본문 바로가기
언어공부/JAVA&SPRING

[패스트캠퍼스 수강 후기] 자바 인강 100% 환급 챌린지 18회차 미션

by hobbiz 2020. 8. 27.
반응형

오늘은 람다식에 대해 공부해보았다.

 

함수형 프로그래밍은

순수 함수(pure function)를 구현하고 호출하며

 

매개변수만을 사용하도록 만든 함수로 외부자료에 부수적인 영향이 발생하지 않도록 한다.

 

입력받은 자료를 기반으로 수행되고 외부에 영향을 미치지 않으므로 병렬처리 등에 가능한 안정적인 확장성 있는 프로그래밍 방식이다.

 

 

 

람다식 문법은 

 

매개변수 하나인 경우 괄호를 생략 가능하다. (두개 인 경우는 괄호를 생략할 수 없다.)

str->{System.out.println(str);}

 

중괄호 안의 구현부가 한 문장인 경우 중괄호 생략이 가능하다.

str->System.out.println(str);

 

중괄호 안의 구현부가 한 문장이라도 return문은 중괄호를 생략할 수 없다.

str->return str.length();  //오류

 

중괄호 안의 구현부가 반환문 하나라면 return과 중괄호를 모두 생략할 수 있다.

(x, y)->x+y  //두 값을 더하여 반환

str->str.length() //문자열 길이를 반환

 

 

아래는 람다식의 예시이다.

 

 

 

람다식은 프로그램 내에서 변수처럼 사용할 수 있다.

 

 

 

<추가공부>

람다식

 

람다식

자바 8에서 함수형 프로그래밍 방식인 람다식을 지원합니다. 이 람다식은 익명 함수를 간단히 표현한 것이라고 할 수 있습니다. 객체지향 프로그래밍보다는 함수형 프로그래밍에 가깝다고 할 수 있습니다.

함수형 프로그래밍

함수형 프로그래밍은 부수 효과를 없애고 순수 함수를 만들어 모듈화의 수준을 높이는 프로그래밍입니다. 부수 효과라고 하면 외부의 값을 변경하는 것이고 순수 함수는 외부의 값을 변경시키지 않고 함수에 값을 넣으면 항상 일정한 값이 나오는 함수입니다.

람다식의 장점

우선 람다식을 사용하면 얻을 수 있는 효과들이 있습니다.

1. 변수의 명시적인 변경이나 재할당 할 때의 문제를 피할 수 있습니다.

2. 쉽게 멀티스레딩이 가능합니다.

3. 코드의 간결성이 높아지고 작성자의 의도 파악이 쉬워집니다.

4. 직관적인 부분에서 좋은 성능을 가진다. 코드를 설명한 데로 만들 수 있다.

이렇게 크게 4가지가 있습니다. 제가 사용하면서 가장 크게 느낀 것은 정말 간결한 것이 좋더라고요.. 직관성도 크게 느낍니다. 이게 어떤 부분인지 확실하게 알 수 있기 때문이죠.

기본 문법

그래서 기본 문법은 무엇이냐.

(Type variable) -> {execute}

이렇게 선언을 합니다. 예제를 보시면 더 자세히 이해하실 수 있습니다.

new Thread(new Runnable(){ @Override public void run(){ System.out.println("HI"); } }).start();

이렇게 스레드를 사용한 익명 함수가 있습니다. 이 함수를 람다식을 쓰면 엄청나게 줄일 수 있습니다. 엄청나게는 아니고 조금 간편하게 줄일 수 있습니다.

new Thread(() ->{ System.out.println("HI"); }).start();

run이라는 메서드가 사라졌습니다. 해석을 하자면 run() 메서드에 전달할 인수가 없기에 동작할 코드를 " -> " 메서드를 사용하여 대 괄호 안에 전달합니다.

확실히 익명 함수를 사용했을 때보다는 람다식을 쓴 것이 상당히 이쁘기도 한 모습입니다.

람다식의 여러 가지 형태

람다식은 여러 가지 형식으로 구현할 수 있습니다.

(String a, String b) -> {a + " + " + b;}// 매게변수가 있는 기본구조 (String a, String b) -> a + " + " + b;// 대괄호를 생략할 때 (int a1 + int a2) -> {return a1 + a2;}// 리턴문을 사용할 때 () -> {return 1 + 2;} // 매게 변수가 없을 때

이렇게 할 수 있습니다. 제가 많이 쓰는 형식은 두 번째 형식으로 매개변수가 실행될 때 함수가 실행되도록 하는 형식을 자주 씁니다.

대괄호를 사용하지 않는 경우는 실행 문장이 하나일 때 사용하지 않습니다. 그 외에는 대괄호가 꼭 필요합니다.

람다식, 하나의 추상메서드를 가진 클래스

람다식은 메서드를 새롭게 선언하는 것처럼 보일 수 있습니다. 하지만 자바는 엄청난 객체지향 언어이기에 항상 메서드를 클래스의 구성 멤버를 선언해야 합니다. 그렇기에 객체의 형식을 가져야 합니다. 말은 이렇지만 사용하는 모습을 보면 간단합니다.

(Interface) obj = (int q, int w) -> q + w;

사실상 간단합니다. 위에서 String을 쓴 것과는 조금 다릅니다. 인터페이스를 사용해야 하기 때문이죠.

interface interMine{ public void add(int a, int b); }

이러한 인터페이스가 있습니다. 이 인터페이스를 사용한 람다식을 보시죠.

interMine im = (int a, int b) -> a + b; im.add();

이렇게 사용을 하면 두 번째 줄에서 인터페이스에 있는 메서드를 호출하게 됩니다.

매개변수를 사용하지 않는 경우에는 이렇게 사용합니다.

interMine im = () -> {~~~}

그냥 빈 괄호를 넣으면 사용이 가능해집니다. 매개변수를 줄 수가 없기 때문이죠.

람다식과 외부 메서드

람다식은 메서드의 내부에 작성해서 사용할 수 있습니다. 그렇기에 메서드 내에 메서드가 선언되는 구조처럼 보일 수 있습니다. 람다식은 외부 클래스에서는 내부 클래스와 동일하게 처리되기 때문에 메서드를 접근하는 데에는 제약이 없습니다.

public class TestLambda { public void outer(int n) { String outer = "외부 메서드"; FuncInterface func = () -> { System.out.println("out 지역 변수: " + outer); // n = 20; System.out.println("out 매개 변수 num: " + n); }; func.execute(); } public static void main(String[] args) { TestLambda tl = new TestLambda(); tl.outer(30); } }

이 예제를 보시면 중간에 주석이 쳐져 있는 곳을 보실 수 있습니다. 람다식의 외부 메서드인 outer의 매개 변수인 n 은 모두 final로 설정되어 있기에 참조만 가능합니다. 저 주석을 풀게 된다면 오류가 뜨는 것을 보실 수 있습니다.

Local variable n defined in an enclosing scope must be final or effectively final

이런 에러가 뜨는데 이것은 "범위 내의 지역변수 n 은 final이어야 한다" 라는 뜻을 가지고 있습니다. 바꿀 수 없다는 거죠. outer 변수 또한 마찬가지입니다. 당연히도 내부 클래스와 같은 개념이기에 해당되는 내용입니다. 일반적인 메서드

에서는 이렇지 않습니다.

메서드 참조

메서드 참조에 대한 형식을 알아보도록 하겠습니다. 우선 ::라는 예약어를 사용합니다. 형식을 이렇습니다.

class :: static method object :: instance method class :: instance method

각각의 차이점은 무엇일까요?

method(x,y -> method(x,y)) -----> method(class::method)

메서드 안에서 실행한 람다식을 ::를 사용하여 간략하게 줄인 것입니다. 이건 보는 것보다는 직접 사용해보는 것이 더 이해해 도움이 될 것이라고 생각합니다.

public class LambdaExam extends JFrame{ public LambdaExam() { setTitle("Frame"); setSize(500,500); setDefaultCloseOperation(2); setLocationRelativeTo(null); add(addAction("닫기", e -> dispose())); } public static void main(String[] args) { new LambdaExam().setVisible(true); } public static JButton addAction(String text, ActionListener e) { JButton btn = new JButton(text); btn.addActionListener(e); return btn; } }

기본 화면을 만들고 안에 버튼 만든 소스코드입니다. 버튼을 누르면 화면이 꺼지도록 만들었습니다. addAction이라는 메서드를 람다식에서 호출을 한 소스입니다.

public class LambdaExam extends JFrame{ public LambdaExam() { setTitle("Frame"); setSize(500,500); setDefaultCloseOperation(2); setLocationRelativeTo(null); add(addAction("닫기", this::print)); } public static void main(String[] args) { new LambdaExam().setVisible(true); } public static JButton addAction(String text, ActionListener e) { JButton btn = new JButton(text); btn.addActionListener(e); return btn; } public void print(ActionEvent e) { JOptionPane.showMessageDialog(null, "출력"); } }

이번에는 print라는 메서드를 추가하였습니다. dispose()라는 함수 대신 print라는 함수를 넣었습니다. class::method가 있어야 하기 때문에 this를 사용하여 클래스 자기 자신을 칭했습니다. 결과는 이렇습니다.

누르면 팝업창이 뜨는 것을 볼 수 있습니다. 간단하지요?

이번에는 제가 하다가 생각이 난 것입니다. 우선 사용하는 방식이 몇 가지 더 있습니다.

Type exam = (x,y) -> x > y ? x : y;

이 소스코드는 람다식을 사용한 if else 문입니다. ?는 if 문을 상징합니다. ?를 기준으로 앞은 조건문 뒤는 true일 시 전자 리턴 false일 시 후자를 리턴합니다. 이것을 보고 생각난 것이 boolean으로 메서드를 생성하고 그 안에 코딩을 해서 true or false를 리턴 시키는 방식을 사용하면 이러한 소스코드가 나오게 됩니다.

interface Test { int testInter(); } public class TestLambda { public static void main(String[] args) { Test func = () -> b1() ? 10 : 20; System.out.println(func.testInter()); } public static boolean b1() { return true; } public boolean b2() { return false; } }

약간 이런 식으로 true false를 구분해놓는 알고리즘을 짜고 반환값도 그에 맞는 값을 정해주면 간편하고 쉽게 사용할 수 있지 않을까 하는 생각이 듭니다. 좋은 로직이 될 수도 있을 것 같은 느낌이 듭니다.

출처: https://blog.naver.com/kkkths/221799585830

 

 

 

 

패스트캠퍼스 강의:

https://bit.ly/3ilMbIO

 

Java 웹 개발 마스터 올인원 패키지 Online. | 패스트캠퍼스

자바 기초문법부터 프로젝트 실습까지 Java 문법부터 스프링/스프링부트, 트렌디한 기술인 JPA까지 모두 배우는 온라인 강의입니다.

www.fastcampus.co.kr

 

반응형

댓글