From d8d96634b992e59b40d085aca07f8439ecae1637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=8A=B9=ED=98=81?= Date: Sat, 9 Jan 2021 01:30:36 +0900 Subject: [PATCH 1/7] =?UTF-8?q?item42=20=EC=B4=88=EC=95=88=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item42.md" | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 "7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" diff --git "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" new file mode 100644 index 0000000..cbb574b --- /dev/null +++ "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" @@ -0,0 +1,114 @@ +# item 42. 익명 클래스보다는 람다를 사용하라 + + +### 왜 그럴까요? +익명 클래스 방식은 코드가 너무 길어집니다. +람다를 사용하게 되면 익명 클래스와 개념은 비슷하지만 코드는 훨씬 간결해지는 장점을 누릴 수 있습니다. + +```java +// 익명 클래스를 사용했을때. +Collections.sort(words, new Comparator() { + public int compare(String s1, String s2) { + return Integer.compare(s1.length(), s2.length()); + } +}); + +// 익명 클래스만 떼서 보면? +new Comparator() { + public int compare(String s1, String s2) { + return Integer.compare(s1.length(), s2.length()); + } +} +``` + +람다식(람다)는 함수형 인터페이스(추상 메서드 하나짜리 인터페이스)의 인스턴스를 만들 때 사용합니다. +밑의 코드는 위의 익명 클래스 부분을 람다 방식으로 바꾼 모습입니다. + +```java +// 자바코드 +Collections.sort(words, + (s1, s2) -> Integer.compare(s1.length(), s2.length())); +``` + +이처럼 동일한 동작을 하는 코드를 3줄에서 1줄로 줄이고 어떤 동작을 하는지에 대한 가독성 또한 좋아지는 효과가 있습니다. + +익명 클래스는 Swift에서 대치되는 개념이 없지만 람다식은 Swift의 closure와 몇몇 부분은 비교할 수 있습니다. + +
+ +### 람다와 클로저(Closure)의 비교 + +#### 표현식 +- 람다 : `(매개변수, ...) -> { 실행구문 };` +- 클로저 : `{ (매개 변수) -> (반환 타입) in (실행구문) }` + +#### 개념 +- 람다 : 함수형 인터페이스를 구현하는 표현식입니다. + ```java + // 익명클래스 혹은 구현체를 만들어 calc 메소드를 Override 하는 방법도 있다. + interface Calculator { + int calc(int n); + } + + // 람다로 구현하면? + public static void main(String[] args) { + int n = 2; + Calculator cal = (n) -> {return n + 1;}; + + System.out.println(cal.calc(n)); // 3 + } + ``` +- 클로저 : 코드 내부 혹은 전달도 가능한 '독립된 기능 블럭'입니다. + ```swift + let cal = { (n: Int) -> Int in + return n+1 + } + + cal(2) // 3 + + // 전달 + func plusUsingClosure(number: Int, closure: (Int) -> Int) -> Int { + return closure(number) + } + + plusUsingClosure(number: 2, closure: ci) + ``` + +#### 둘 모두 일급객체 +- 모든 일급 객체는 함수의 실질적인 매개변수가 될 수 있습니다. +- 모든 일급 객체는 함수의 반환값이 될 수 있습니다. +- 모든 일급 객체는 할당의 대상이 될 수 있습니다. +- 모든 일급 객체는 비교 연산(==, equal)을 적용할 수 있습니다.
(다만, Swift에서는 비교연산을 권장하지 않는다고 합니다. [관련 링크](https://stackoverflow.com/questions/24111984/how-do-you-test-functions-and-closures-for-equality)) + + +#### 타입추론 +- 람다 : 컴파일러가 타입 추론을 해줍니다.
타입을 명시해야 코드가 더 명확할 때 / 컴파일러가 타입을 알 수 없다는 오류를 낼때를 제외하고, 람다의 모든 매개변수 타입은 생략하는 것을 권장했습니다. +- 클로저 : 클로저 또한 컴파일러가 타입 추론을 해줍니다. + ```swift + let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] + + reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in + return s1 > s2 + }) + + // 타입 추론이 가능 하므로 매개변수 타입 및 반환 타입 생략 + reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } ) + ``` + 이처럼 메소드는 문자열 배열에서 호출되므로, 인자는 (String, String) -> Bool 타입의 함수일 수 밖에 없을 것입니다. 이 말은 모든 타입을 추론할 수 있으므로, ‘반환 표시 화살표 (->)’ 와 매개 변수 이름 주위의 괄호도 생략이 가능하게 됩니다.
+공식 문서에서는 람다처럼 매개변수 타입을 생략하는것을 권장하진 않고, 필요하거나 코드를 읽을때 모호함을 피하기 위함이면 언제든 타입을 표현해도 된다고 설명하고 있습니다. + +
+ +### 람다 사용 시 권장사항 +해당사항은 클로저를 만들때도 적용하면 좋을 것 같아서 가져와보았습니다. +> 람다는 이름이 없고 문서화도 못 한다. 따라서 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야한다. + +
+ +### 참고한 곳 +- https://juyoung-1008.tistory.com/48 +- https://galid1.tistory.com/509 +- https://jeong-pro.tistory.com/208 +- https://ko.wikipedia.org/wiki/%EC%9D%BC%EA%B8%89_%EA%B0%9D%EC%B2%B4 +- https://docs.swift.org/swift-book/LanguageGuide/Closures.html +- http://xho95.github.io/swift/language/grammar/closure/2020/03/03/Closures.html From 701805ce2b6e2d49db13ad9bdff71bea01f85b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=8A=B9=ED=98=81?= Date: Sat, 9 Jan 2021 01:34:59 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=EC=95=84=EC=9D=B4=ED=85=9C=2042=20?= =?UTF-8?q?=EB=A7=81=ED=81=AC=EC=A3=BC=EC=86=8C=20=EB=B0=8F=20=EB=8B=B4?= =?UTF-8?q?=EB=8B=B9=EC=9E=90=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c3a33a..f87b903 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ Effective Java 3/E을 읽고 프로그래밍에서의 관례적이고 효과적 | 아이템 번호 | 타이틀 | 서브 타이틀 | 담당자 | |:-----:|-------|-------|:------:| -| 아이템 42 | [익명 클래스보다는 람다를 사용하라]() | | | +| 아이템 42 | [익명 클래스보다는 람다를 사용하라](7장_람다와_스트림/item42.md) | | [Lin](https://github.com/Limwin94) | | 아이템 43 | [람다보다는 메서드 참조를 사용하라]() | | | | 아이템 44 | [표준 함수형 인터페이스를 사용하라]() | | | | 아이템 45 | [스트림은 주의해서 사용하라]() | | | @@ -167,4 +167,4 @@ Effective Java 3/E을 읽고 프로그래밍에서의 관례적이고 효과적 - [이펙티브 자바 3판 번역 용어 해설][terms] [effective-java-3e-source-code]: https://github.com/WegraLee/effective-java-3e-source-code -[terms]: https://docs.google.com/document/d/1Nw-_FJKre9x7Uy6DZ0NuAFyYUCjBPCpINxqrP0JFuXk/edit \ No newline at end of file +[terms]: https://docs.google.com/document/d/1Nw-_FJKre9x7Uy6DZ0NuAFyYUCjBPCpINxqrP0JFuXk/edit From ed5bf90d8a8919f4b691d7a92f8f5fce6af2e284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=8A=B9=ED=98=81?= Date: Sun, 17 Jan 2021 16:44:13 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=EA=B0=9C=EC=9A=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item42.md" | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" index cbb574b..518eb32 100644 --- "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" +++ "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" @@ -1,7 +1,10 @@ # item 42. 익명 클래스보다는 람다를 사용하라 +## 개요 +왜 익명 클래스보단 람다를 사용해야하는지, 람다는 무엇이고 비슷한 개념인 Swift의 closure를 설명하며 비교를 해보겠습니다. +
-### 왜 그럴까요? +### 왜 그래야 할까요? 익명 클래스 방식은 코드가 너무 길어집니다. 람다를 사용하게 되면 익명 클래스와 개념은 비슷하지만 코드는 훨씬 간결해지는 장점을 누릴 수 있습니다. From 0593554abcb9cda8ee95422e9d1ec4372cb7a66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=8A=B9=ED=98=81?= Date: Sun, 17 Jan 2021 16:45:05 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=EC=96=B4=EC=83=89=ED=95=9C=20=EB=AC=B8?= =?UTF-8?q?=EC=B2=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item42.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" index 518eb32..7e9f078 100644 --- "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" +++ "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" @@ -1,6 +1,6 @@ # item 42. 익명 클래스보다는 람다를 사용하라 ## 개요 -왜 익명 클래스보단 람다를 사용해야하는지, 람다는 무엇이고 비슷한 개념인 Swift의 closure를 설명하며 비교를 해보겠습니다. +왜 익명 클래스보단 람다를 사용해야하는지, 람다는 무엇이고 비슷한 개념인 Swift의 closure와 함께 비교를 해보겠습니다.
From 966517551f94f2234d7dec43943d5c916c936d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=8A=B9=ED=98=81?= Date: Sun, 17 Jan 2021 16:47:08 +0900 Subject: [PATCH 5/7] =?UTF-8?q?ci=20->=20cal=20=EC=98=A4=ED=83=80=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item42.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" index 7e9f078..3e0a993 100644 --- "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" +++ "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" @@ -74,7 +74,7 @@ Collections.sort(words, return closure(number) } - plusUsingClosure(number: 2, closure: ci) + plusUsingClosure(number: 2, closure: cal) ``` #### 둘 모두 일급객체 From bcfbee33e1636192feec63e3628dc3d23d5daf1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=8A=B9=ED=98=81?= Date: Sun, 17 Jan 2021 17:09:31 +0900 Subject: [PATCH 6/7] =?UTF-8?q?=ED=81=B4=EB=A1=9C=EC=A0=80=20=EC=98=88?= =?UTF-8?q?=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 3가지로 나누어 설명 - Trailing Clousures 예제 추가 --- .../item42.md" | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" index 3e0a993..b2df3e1 100644 --- "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" +++ "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" @@ -61,20 +61,32 @@ Collections.sort(words, System.out.println(cal.calc(n)); // 3 } ``` -- 클로저 : 코드 내부 혹은 전달도 가능한 '독립된 기능 블럭'입니다. - ```swift +- 클로저 : 코드 내부 혹은 전달도 가능한 '독립된 기능 블럭'입니다. 어떻게 사용하는지 3가지 정도로 살펴보도록 하겠습니다. + 1. 클로저를 할당하여 사용 + ```swift let cal = { (n: Int) -> Int in return n+1 } cal(2) // 3 + ``` - // 전달 + 2. 클로저 전달 + ```swift + // 2. func plusUsingClosure(number: Int, closure: (Int) -> Int) -> Int { return closure(number) } - plusUsingClosure(number: 2, closure: cal) + let result = plusUsingClosure(number: 2, closure: cal) // 3 + ``` + + 3. Trailing Closures + ```swift + // 기존에 만들어져있는 클로저를 전달할 수도 있지만 함수를 호출하면서 클로저 본문을 작성할 수도 있습니다. + _ = plusUsingClosure(number: 2) { num -> Int in + return num + 1 // 3 + } ``` #### 둘 모두 일급객체 From ff981a32e47c526203c150b1052062fceb4f0b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=84=EC=8A=B9=ED=98=81?= Date: Sun, 17 Jan 2021 17:12:08 +0900 Subject: [PATCH 7/7] =?UTF-8?q?=EB=9E=8C=EB=8B=A4=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EC=8B=9C=20=EA=B6=8C=EC=9E=A5=EC=82=AC=ED=95=AD=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item42.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" index b2df3e1..3959189 100644 --- "a/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" +++ "b/7\354\236\245_\353\236\214\353\213\244\354\231\200_\354\212\244\355\212\270\353\246\274/item42.md" @@ -116,7 +116,7 @@ Collections.sort(words, ### 람다 사용 시 권장사항 해당사항은 클로저를 만들때도 적용하면 좋을 것 같아서 가져와보았습니다. -> 람다는 이름이 없고 문서화도 못 한다. 따라서 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야한다. +> 람다는 이름이 없고 문서화도 못 한다. 따라서 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야한다. 람다는 한 줄일 때 가장 좋고 길어야 세 줄 안에 끝내는게 좋다. 세 줄을 넘어가면 가독성이 심하게 나빠진다. 람다가 길거나 읽기 어렵다면 더 간단히 줄여보거나 람다를 쓰지 않는 쪽으로 리팩터링하길 바란다.