├── .gitignore ├── LICENSE ├── README.md ├── YouTube-social-icon_red_24px.png ├── build.gradle ├── pom.xml ├── settings.gradle └── src ├── main └── java │ └── cc │ └── kevinlee │ └── modernjava │ ├── e01 │ ├── LambdaExample.java │ ├── OopAndFpExamples.java │ ├── OopExample.java │ └── WhyJava8.java │ ├── e02_function │ └── FunctionExamples.java │ ├── e03_consumer │ └── ConsumerExamples.java │ ├── e04_predicate │ └── PredicateExamples.java │ ├── e05_supplier │ └── SupplierExamples.java │ ├── e06_custom_functionalinterface │ └── CustomFunctionalInterfaceExamples.java │ ├── e07_functionalinterface_examples │ └── FunctionalInterfaceExamples.java │ ├── e08_01_stream_prelude │ └── StreamPrelude.java │ ├── e08_02_identity │ └── IdentityExamples.java │ ├── e08_03_stream_01 │ └── StreamExamples1.java │ ├── e08_03_stream_02 │ └── StreamExamples2.java │ ├── e08_03_stream_03 │ └── StreamExamples3.java │ ├── e08_03_stream_04 │ └── StreamExamples4.java │ ├── e08_03_stream_05_parallel │ ├── StreamExamples5Parallel.java │ ├── StreamExamples5ParallelPerformance.java │ └── StreamExamples5ParallelPerformancePractical.java │ ├── e09_closure │ ├── ClosureExamples.java │ └── ClosureExamples2.java │ ├── ep10_higher_order_function │ └── HigherOrderFunctionExamples.java │ └── ep11_method_reference │ ├── MethodReferenceExamples.java │ ├── MethodReferenceExamples2Constructor.java │ └── MethodReferenceExamples3Array.java └── test └── java └── cc └── kevinlee └── modernjava └── e01 └── CalculatorServiceTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | *.pydevproject 4 | .project 5 | .classpath 6 | .settings/ 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .loadpath 16 | 17 | .idea 18 | *.iml 19 | 20 | # External tool builders 21 | .externalToolBuilders/ 22 | 23 | # Locally stored "Eclipse launch configurations" 24 | *.launch 25 | 26 | # CDT-specific 27 | .cproject 28 | 29 | # PDT-specific 30 | .buildpath 31 | 32 | 33 | gradle/ 34 | gradlew* 35 | .gradle 36 | build/ 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 모던 자바 (자바8) 못다한 이야기 2 | # Modern Java (Java8) Untold 3 | 4 | 이곳은 제가 유튜브에 올리고 있는 모던 자바 영상에서 작성된 코드를 5 | 정리하고 주석을 달아서 모아 놓은 저장소입니다. 6 | 7 | 앞으로 계속 업데이트 될 예정이니 직접 코드 작성을 하실 경우 8 | clone 하셔서 수정을 하지 마시고, 따로 프로젝트 생성을 하시는게 좋을것 같습니다. 9 | 그렇지 않으면 merge conflict를 경험하시게 될지도... 10 | 11 | **모던 자바 - 못다한 이야기 영상 02~05까지는 볼륨이 좀 작습니다. 죄송합니다. 한번에 다 녹화해서 확인 못했습니다.** 12 | 13 | **중간에 작은 실수한거 수정도 못하고 올려서 5편 이후로는 볼륨 문제를 신경썼고, 7편부터는 녹화한 영상 미리 다 확인하고 14 | 필요한 정보를 추가하거나 삭제하는 편집과정을 도입했습니다.** 15 | 16 | ## 나는 프로그래머다 웨비너 17 | 나는 프로그래머다 웨비너 - 자바8 깊숙히 (무삭제 노모 유출 버전!) 18 | 19 | 20 | ## 모던 자바 - 못다한 이야기 21 | 22 | 모던 자바 (자바8) - 못다한 이야기 영상 - 전편 보기 클릭! 23 | (각편당 링크는 이 밑에 있습니다). 24 | 25 | ### 01. 모던 자바 - 못다한 이야기: 웨비나, 소개, 왜 배워야 하죠? 26 | 27 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 00 소개영상 모던 자바 (자바8) - 못다한 이야기: - 00 소개영상 28 | 29 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 01 왜 배워야 하나요? 뭐가 좋아요? 모던 자바 (자바8) 못다한 이야기 - 01 왜 배워야 하나요? 뭐가 좋아요? 30 | 31 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 01-B 왜 배워야 하나요? 뭐가 좋아요? (추가설명편) 모던 자바 (자바8) 못다한 이야기 - 01-B 왜 배워야 하나요? 뭐가 좋아요? (추가설명편) 32 | 33 | 관련 소스 (클릭!) 34 | 35 | 36 | ### 02. Functional Interface 37 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 02 Function, The Transformer 모던 자바 (자바8) 못다한 이야기 - 02 Function, The Transformer 38 | 39 | 관련 소스 (클릭!) 40 | 41 | 42 | ### 03. Consumer 43 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 03 Consumer, The Spartan 모던 자바 (자바8) 못다한 이야기 - 03 Consumer, The Spartan, "Give Them Nothing but Take from Them Everything" (스파르탄, "모든걸 빼앗고 아무것도 내주지 마라!") 44 | 45 | 관련 소스 (클릭!) 46 | 47 | 48 | ### 04. Predicate 49 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 04 Predicate, The Judge 모던 자바 (자바8) 못다한 이야기 - 04 Predicate, The Judge 50 | 51 | 관련 소스 (클릭!) 52 | 53 | 54 | ### 05. Supplier 55 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 05 Supplier, The Master of Lazy Evaluation 모던 자바 (자바8) 못다한 이야기 - 05 Supplier, The Master of Lazy Evaluation 56 | 57 | 관련 소스 (클릭!) 58 | 59 | 60 | ### 06. 직접 만드는 Functional Interface 어때요? 참 쉽죠? 61 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 06 직접 만드는 Functional Interface 어때요? 참 쉽죠? 모던 자바 (자바8) 못다한 이야기 - 06 직접 만드는 Functional Interface 어때요? 참 쉽죠? 62 | 63 | 관련 소스 (클릭!) 64 | 65 | 66 | ### 07. FunctionalInterface 실전 예제 / 제약 사항 67 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 07 실전 예제와 Functional Interface의 제약 사항 모던 자바 (자바8) 못다한 이야기 - 07 실전 예제와 Functional Interface의 제약 사항 68 | 69 | 관련 소스 (클릭!) 70 | 71 | 72 | ### 08. Stream API 73 | #### 08 - 01 시작하기전에 74 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 08 Stream API - 01 시작하기전에 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 01 시작하기전에 75 | 76 | 관련 소스 (클릭!) 77 | 78 | 79 | #### 08 - 02 Identity Function 예제 80 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 08 Stream API - 02 Identity Function 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 02 Identity Function 81 | 82 | 관련 소스 (클릭!) 83 | 84 | 85 | #### 08 - 03 Stream API - 01 무한 Collection 86 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 08 Stream API - 03 Stream API 01 - 무한 collection 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 01 - 무한 collection 87 | 88 | 관련 소스 (클릭!) 89 | 90 | 91 | #### 08 - 03 Stream API - 02 Stream vs 예전방식 92 | Youtube: 모던 자바 (자바8) - 못다한 이야기: - 08 Stream API - 03 Stream API 02 - Stream vs 예전방식 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 02 - Stream vs 예전방식 93 | 94 | 관련 소스 (클릭!) 95 | 96 | 97 | #### 08 - 03 Stream API - 03 기초 98 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 03 - 기초 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 03 - 기초 99 | 100 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 03A - IDE 활용 팁 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 03A - IDE 활용 팁 101 | 102 | 관련 소스 (클릭!) 103 | 104 | 105 | #### 08 - 03 Stream API - 04 좀더 실용적인 예 106 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 04 - 좀더 실용적인 예 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 04 - 좀더 실용적인 예 107 | 108 | 관련 소스 (클릭!) 109 | 110 | 111 | #### 08 - 03 Stream API - 05 병렬 프로그래밍 (Parallel Programming with ParallelStream) 112 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 05 - Parallel Programming (with ParallelStream) 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 05 - Parallel Programming (with ParallelStream) 113 | 114 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 06 - ParallelStream 성능 테스트 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 06 - ParallelStream 성능 테스트 115 | 116 | 관련 소스 (클릭!) 117 | 118 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 07 - ParallelStream 주의 사항과 앞으로의 계획 모던 자바 (자바8) 못다한 이야기 - 08 Stream API - 03 Stream API 07 - ParallelStream 주의 사항과 앞으로의 계획 119 | 120 | JMH: 자바 성능 벤치마크툴 (클릭) 121 | 122 | ### 09. Closure 123 | 124 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 09 - 01 Closure 모던 자바 (자바8) 못다한 이야기 - 09 - 01 Closure 125 | 126 | 관련 소스 (클릭!) 127 | 128 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 09 - 02 Closure 및 Lambda Expression 내부 구현 모던 자바 (자바8) 못다한 이야기 - 09 - 02 Closure 및 Lambda Expression 내부 구현 129 | 130 | 131 | ### 10. Higher-Order Function (HOF, 고차 함수 혹은 고계 함수) 132 | 133 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 10 - Higher-Order Function 모던 자바 (자바8) 못다한 이야기 - 10 - Higher-Order Function 134 | 135 | 관련 소스 (클릭!) 136 | 137 | ### 11. Method Reference (In progress) 138 | 139 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 11 (1) - Method Reference 모던 자바 (자바8) 못다한 이야기 - 11 (1부) - Method Reference 140 | 141 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 11 (2) - Method Reference 사용예 모던 자바 (자바8) 못다한 이야기 - 11 (2부) - Method Reference 사용예 142 | 143 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 11 (3부) - Method Reference로 Method를 Data처럼 모던 자바 (자바8) 못다한 이야기 - 11 (3부) - Method Reference로 Method를 Data처럼 144 | 145 | Youtube: 모던 자바 (자바8) 못다한 이야기 - 11 (4부) Method Reference, Constructor를 Data처럼 사용하기 모던 자바 (자바8) 못다한 이야기 - 11 (4부) Method Reference, Constructor를 Data처럼 사용하기 146 | 147 | 148 | 관련 소스 (클릭!) 149 | 150 | 더 추가될 예정입니다. 151 | 152 | 153 | -------------------------------------------------------------------------------- /YouTube-social-icon_red_24px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevin-lee/modern-java-untold/52e752a37d1d6f5c6425af7da11dcd9a7ba2fad7/YouTube-social-icon_red_24px.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | group 'cc.kevinlee' 2 | version '1.0' 3 | 4 | task wrapper(type: Wrapper) { 5 | gradleVersion = '2.5' 6 | distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" 7 | } 8 | 9 | apply plugin: 'java' 10 | 11 | sourceCompatibility = 1.8 12 | targetCompatibility = 1.8 13 | 14 | repositories { 15 | mavenCentral() 16 | maven { 17 | url "http://dl.bintray.com/kevinlee/maven" 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'cc.kevinlee:j8plus:0.0.15' 23 | compile "org.projectlombok:lombok:1.16.4" 24 | 25 | testCompile 'junit:junit:4.11' 26 | testCompile 'org.assertj:assertj-core:3.0.0' 27 | testCompile 'cc.kevinlee:test0ster1:0.0.6' 28 | } 29 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | cc.kevinlee 7 | modern-java-untold 8 | 1.0 9 | jar 10 | 11 | Modern Java Untold 12 | https://github.com/Kevin-Lee/modern-java-untold 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 4.11 18 | 0.0.6 19 | 20 | 21 | 22 | 23 | kevin-public-releases 24 | Kevin's Public Releases 25 | http://dl.bintray.com/kevinlee/maven 26 | 27 | 28 | 29 | 30 | scm:git:git@kevin-lee-github:Kevin-Lee/modern-java-untold.git 31 | scm:git:git@kevin-lee-github:Kevin-Lee/modern-java-untold.git 32 | https://github.com/Kevin-Lee/modern-java-untold 33 | HEAD 34 | 35 | 36 | 37 | 38 | 39 | org.apache.maven.plugins 40 | maven-compiler-plugin 41 | 3.1 42 | 43 | ${java.version} 44 | ${java.version} 45 | ${project.build.sourceEncoding} 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-source-plugin 51 | 2.1.2 52 | 53 | 54 | attach-sources 55 | 56 | jar 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-release-plugin 64 | 2.5.1 65 | 66 | true 67 | releases 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | junit 76 | junit 77 | ${junit.version} 78 | test 79 | 80 | 81 | cc.kevinlee 82 | test0ster1 83 | ${test0ster1.version} 84 | test 85 | 86 | 87 | org.assertj 88 | assertj-core 89 | 3.0.0 90 | test 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'modern-java-untold' 2 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e01/LambdaExample.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e01; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.function.Predicate; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * @author Kevin Lee 13 | * @since 2015-08-01 14 | */ 15 | public class LambdaExample { 16 | 17 | public static void main(final String[] args) { 18 | 19 | filteringTest(); 20 | 21 | final List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); 22 | 23 | final int repeat = 5; 24 | System.out.println("\nLambdaExample.raceCondition"); 25 | /* 5번 반복 */ 26 | Stream.iterate(0, i -> i + 1) // <= 이게 뭐냐구요? 5번 반복인데, 자세한건 Stream API 관련 영상을 기다려주세요! 27 | .limit(repeat) 28 | .forEach(i -> raceCondition(numbers)); 29 | 30 | System.out.println("\nLambdaExample.noRaceCondition"); 31 | Stream.iterate(0, i -> i + 1) // <= 이게 뭐냐구요? 5번 반복인데, 자세한건 Stream API 관련 영상을 기다려주세요! 32 | .limit(repeat) 33 | .forEach(i -> noRaceCondition(numbers)); 34 | 35 | parallelProgramming(); 36 | } 37 | 38 | private static void filteringTest() { 39 | System.out.println("\nLambdaExample.filteringTest"); 40 | final List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 41 | 42 | /* 예전 방법으로 2보다 큰 정수 찾기 */ 43 | final List result = new ArrayList<>(); // boilerplate code 44 | for (final Integer number : list) { // boilerplate code 45 | if (number > 2) { // 이부분만 다름 46 | result.add(number); // boilerplate code 47 | } 48 | } 49 | System.out.println("n > 2 = " + result); 50 | 51 | /* 예전 방법으로 7보다 작은 정수 찾기 */ 52 | final List result2 = new ArrayList<>(); // boilerplate code 53 | for (final Integer number : list) { // boilerplate code 54 | if (number < 7) { // 이부분만 다름 55 | result2.add(number); // boilerplate code 56 | } 57 | } 58 | System.out.println("n < 7 = " + result2); 59 | 60 | /* 람다를 이용해서 2보다 큰 정수 찾기 */ 61 | final Predicate greaterThan2 = n -> n > 2; 62 | final List result3 = filter(list, greaterThan2); 63 | System.out.println("n > 2 = " + result3); 64 | 65 | /* 람다를 이용해서 7보다 작은 정수 찾기 (기존 filter 메소드 재사용) */ 66 | final Predicate lessThan7 = n -> n < 7; 67 | final List result4 = filter(list, lessThan7); 68 | System.out.println("n < 7 = " + result4); 69 | 70 | /* Function composition: 71 | * 2개의 함수를 합쳐서 쉽게 72 | * 2보다 크고 7보다 작은 정수 찾기 73 | */ 74 | final List result5 = filter(list, greaterThan2.and(lessThan7)); 75 | System.out.println("2 < n < 7 = " + result5); 76 | 77 | /* Closure: 람다 바디에서 람다 바깥에 있는 factor (free variable) 접근 78 | * Note: 엄밀히 따지면 자바의 Closure는 variable이 아니라 거기 들은 값(value)에 79 | * 접근 하는겁니다 (capturing value). 80 | */ 81 | int factor = 10; // effectively final 82 | final Comparator comparator = (o1, o2) -> o1 > factor ? o1 : o1.compareTo(o2); 83 | 84 | } 85 | 86 | private static List filter(final List list, final Predicate predicate) { 87 | final List result = new ArrayList<>(); 88 | for (final T value : list) { 89 | if (predicate.test(value)) { // predicate의 test를 통과한 경우만 저장 90 | result.add(value); 91 | } 92 | } 93 | return result; 94 | } 95 | 96 | 97 | private static void raceCondition(final List numbers) { 98 | 99 | /* Race condition */ 100 | final int[] sum = new int[1]; 101 | numbers.parallelStream() 102 | .forEach(i -> sum[0] = sum[0] + i); // mutation! 103 | 104 | System.out.println("race condition: " + sum[0]); 105 | } 106 | 107 | private static void noRaceCondition(final List numbers) { 108 | /* No race condition */ 109 | final int total = numbers.parallelStream() 110 | .reduce(0, (i1, i2) -> i1 + i2); 111 | System.out.println("no race condition: " + total); 112 | } 113 | 114 | private static void parallelProgramming() { 115 | System.out.println("\nLambdaExample.parallelProgramming"); 116 | final long start = System.currentTimeMillis(); 117 | /* 118 | * peek에 넘기는 function은 3초가 걸리는 119 | * 연산을 시뮬레이션한 것입니다. 120 | * 121 | * 코어 4개짜리 CPU에서 3초정도 걸립니다. 122 | * 저장된 숫자를 하나 더 늘리면 (1, 2, 3, 4, 5), 123 | * 처리하는데 8초정도 걸립니다. 124 | * 125 | * 저장된 숫자의 갯수를 CPU코어 만큼 늘려서 테스트 해보시고, 126 | * 코어보다 하나 많게 해서 테스트 해보세요. 127 | * 예) 코어가 8개면 128 | * (1, 2, 3, 4, 5, 6, 7, 8) => 3초정도 걸립니다. 129 | * (1, 2, 3, 4, 5, 6, 7, 8, 9) => 6초정도 걸립니다. 130 | */ 131 | final int total = Arrays.asList(1, 2, 3, 4) 132 | .parallelStream() 133 | .peek(i -> { 134 | // 처리 시간 오래 걸리는 함수 시뮬레이션 135 | try { 136 | TimeUnit.SECONDS.sleep(3); 137 | } catch (InterruptedException e) { 138 | e.printStackTrace(); 139 | } 140 | }) 141 | .reduce(0, (i1, i2) -> i1 + i2); 142 | System.out.println("It took " + ((System.currentTimeMillis() - start) / 1000) + " seconds."); 143 | System.out.println("total: " + total); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e01/OopAndFpExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e01; 2 | 3 | /** 4 | * 이 파일 관련된 내용은 아직 영상 업로드가 안 됐습니다. 이번 주말에 업로드 하면서 5 | * 이 파일도 업데이트 할테니 git pull 해주세요. :) 6 | * 7 | * @author Kevin Lee 8 | * @since 2015-08-02 9 | */ 10 | public class OopAndFpExamples { 11 | 12 | public static void main(final String[] args) { 13 | final CalculatorService calculatorService = 14 | new CalculatorService(new Addition(), new Subtraction(), new Multiplication(), new Division()); 15 | 16 | final int additionResult = calculatorService.add(11, 4); 17 | System.out.println(additionResult); 18 | 19 | final int subtractionResult = calculatorService.subtract(11, 1); 20 | System.out.println(subtractionResult); 21 | 22 | final int multiplicationResult = calculatorService.multiply(11, 2); 23 | System.out.println(multiplicationResult); 24 | 25 | final int divisionResult = calculatorService.divide(20, 4); 26 | System.out.println(divisionResult); 27 | 28 | 29 | final FpCalculatorService fpCalculatorService = new FpCalculatorService(); 30 | final Calculation addition = (i1, i2) -> i1 + i2; 31 | System.out.println(" additon: " + fpCalculatorService.calculate(addition, 11, 4)); 32 | System.out.println(" subtraction: " + fpCalculatorService.calculate((i1, i2) -> i1 - i2, 11, 1)); 33 | System.out.println("multiplication: " + fpCalculatorService.calculate((i1, i2) -> i1 * i2, 11, 2)); 34 | System.out.println(" division: " + fpCalculatorService.calculate((i1, i2) -> i1 / i2, 20, 4)); 35 | System.out.println(" custom calc: " + fpCalculatorService.calculate((i1, i2) -> ((i1 + i2) * 2) / i2, 20, 4)); 36 | } 37 | } 38 | 39 | interface Calculation { 40 | int calculate(final int num1, final int num2); 41 | } 42 | 43 | class Addition implements Calculation { 44 | @Override 45 | public int calculate(final int num1, final int num2) { 46 | return num1 + num2; 47 | } 48 | } 49 | 50 | class Subtraction implements Calculation { 51 | @Override 52 | public int calculate(final int num1, final int num2) { 53 | return num1 - num2; 54 | } 55 | } 56 | 57 | class Multiplication implements Calculation { 58 | @Override 59 | public int calculate(final int num1, final int num2) { 60 | return num1 * num2; 61 | } 62 | } 63 | 64 | class Division implements Calculation { 65 | @Override 66 | public int calculate(final int num1, final int num2) { 67 | return num1 / num2; 68 | } 69 | } 70 | 71 | class CalculatorService { 72 | private final Calculation addition; 73 | private final Calculation subtraction; 74 | private final Calculation multiplication; 75 | private final Calculation division; 76 | 77 | public CalculatorService(final Calculation addition, final Calculation subtraction, final Calculation multiplication, final Calculation division) { 78 | this.addition = addition; 79 | this.subtraction = subtraction; 80 | this.multiplication = multiplication; 81 | this.division = division; 82 | } 83 | 84 | public int add(final int num1, final int num2) { 85 | if (num1 > 10 && num2 < num1) { // boilerplate code 86 | return addition.calculate(num1, num2); 87 | } else { // boilerplate code 88 | throw new IllegalArgumentException("Invalid input num1: " + num1 + ", num2: " + num2); // boilerplate code 89 | } // boilerplate code 90 | } 91 | 92 | public int subtract(final int num1, final int num2) { 93 | if (num1 > 10 && num2 < num1) { // boilerplate code 94 | return subtraction.calculate(num1, num2); 95 | } else { // boilerplate code 96 | throw new IllegalArgumentException("Invalid input num1: " + num1 + ", num2: " + num2); // boilerplate code 97 | } // boilerplate code 98 | } 99 | 100 | public int multiply(final int num1, final int num2) { 101 | if (num1 > 10 && num2 < num1) { // boilerplate code 102 | return multiplication.calculate(num1, num2); 103 | } else { // boilerplate code 104 | throw new IllegalArgumentException("Invalid input num1: " + num1 + ", num2: " + num2); // boilerplate code 105 | } // boilerplate code 106 | } 107 | 108 | public int divide(final int num1, final int num2) { 109 | if (num1 > 10 && num2 < num1) { // boilerplate code 110 | return division.calculate(num1, num2); 111 | } else { // boilerplate code 112 | throw new IllegalArgumentException("Invalid input num1: " + num1 + ", num2: " + num2); // boilerplate code 113 | } // boilerplate code 114 | } 115 | } 116 | 117 | class FpCalculatorService { 118 | public int calculate(final Calculation calculation, final int num1, final int num2) { 119 | if (num1 > 10 && num2 < num1) { 120 | return calculation.calculate(num1, num2); 121 | } else { 122 | throw new IllegalArgumentException("Invalid input num1: " + num1 + ", num2: " + num2); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e01/OopExample.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e01; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.HashSet; 7 | 8 | /** 9 | * An example of "Inheritance breaks Encapsulation" 10 | * 상속(Inheritance)이 캡슐화(Encapsulation)를 망치는 예제입니다. 11 | * 12 | * @author Kevin Lee 13 | * @since 2015-08-01 14 | */ 15 | public class OopExample { 16 | public static void main(final String[] args) { 17 | final MyList list = new MyList<>(); 18 | list.add(1); 19 | list.add(2); 20 | list.add(3); 21 | System.out.println(" list count: " + list.getCount()); // 예상대로 3이 나옵니다. 22 | 23 | final MyList list2 = new MyList<>(); 24 | list2.addAll(Arrays.asList(1, 2, 3, 4, 5)); 25 | System.out.println(" list2 count: " + list2.getCount()); // 예상대로 5가 나옵니다. 26 | 27 | System.out.println("--------------------"); 28 | final MySet mySet = new MySet<>(); 29 | mySet.add(1); 30 | mySet.add(2); 31 | mySet.add(3); 32 | System.out.println(" mySet count: " + mySet.getCount()); // 예상대로 3이 나옵니다. 33 | 34 | final MySet mySet2 = new MySet<>(); 35 | mySet2.addAll(Arrays.asList(1, 2, 3, 4, 5)); 36 | System.out.println(" mySet2 count: " + mySet2.getCount()); // 예상과 달리 10이!!! 37 | 38 | System.out.println("--------------------"); 39 | final MyNewSet myNewSet = new MyNewSet<>(); 40 | myNewSet.add(1); 41 | myNewSet.add(2); 42 | myNewSet.add(3); 43 | System.out.println(" myNewSet count: " + myNewSet.getCount()); // 예상대로 3이 나옵니다. 44 | 45 | final MyNewSet myNewSet2 = new MyNewSet<>(); 46 | myNewSet2.addAll(Arrays.asList(1, 2, 3, 4, 5)); 47 | System.out.println("myNewSet2 count: " + myNewSet2.getCount()); // 예상대로 5가 나옵니다. 48 | 49 | } 50 | } 51 | 52 | class MyList extends ArrayList { 53 | private int count; 54 | 55 | public int getCount() { 56 | return count; 57 | } 58 | 59 | @Override 60 | public boolean addAll(final Collection c) { 61 | count += c.size(); 62 | return super.addAll(c); 63 | } 64 | 65 | @Override 66 | public boolean add(final E o) { 67 | count++; 68 | return super.add(o); 69 | } 70 | } 71 | 72 | 73 | class MySet extends HashSet { 74 | private int count; 75 | 76 | public int getCount() { 77 | return count; 78 | } 79 | 80 | @Override 81 | public boolean addAll(final Collection c) { 82 | count += c.size(); 83 | return super.addAll(c); 84 | } 85 | 86 | @Override 87 | public boolean add(final E o) { 88 | count++; 89 | return super.add(o); 90 | } 91 | } 92 | 93 | /** 94 | * NewSet은 HashSet에 있는 Inheritance가 Encapsulation을 깨뜨리는 것을 미리 예방해서 95 | * 다시 디자인한것입니다. (add 와 addAll 메소드에 한정) 96 | */ 97 | class NewSet extends HashSet { 98 | @Override 99 | public boolean add(final E e) { 100 | return add0(e); 101 | } 102 | 103 | private boolean add0(final E e) { 104 | return super.add(e); 105 | } 106 | 107 | @Override 108 | public boolean addAll(final Collection c) { 109 | boolean modified = false; 110 | for (E e : c) 111 | if (add0(e)) 112 | modified = true; 113 | return modified; 114 | } 115 | } 116 | 117 | 118 | class MyNewSet extends NewSet { 119 | private int count; 120 | 121 | public int getCount() { 122 | return count; 123 | } 124 | 125 | @Override 126 | public boolean addAll(final Collection c) { 127 | count += c.size(); 128 | return super.addAll(c); 129 | } 130 | 131 | @Override 132 | public boolean add(final E o) { 133 | count++; 134 | return super.add(o); 135 | } 136 | } 137 | 138 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e01/WhyJava8.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e01; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileReader; 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Paths; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.Collections; 12 | import java.util.List; 13 | import java.util.stream.Stream; 14 | 15 | import static java.util.stream.Collectors.joining; 16 | import static java.util.stream.Collectors.toList; 17 | 18 | /** 19 | * @author Kevin Lee 20 | * @since 2015-08-01 21 | */ 22 | public class WhyJava8 { 23 | private static final List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 24 | 25 | public static void main(final String[] args) throws IOException { 26 | simpleTask(); 27 | 28 | // file 읽기전에 파일을 하나 작성 하셔야 합니다. 파일 위치를 확인해 보세요. 현재는 /tmp/test.txt 29 | readFile(); 30 | } 31 | 32 | private static void simpleTask() { 33 | 34 | /* 옛날 옛적 for loop 사용하기 */ 35 | final StringBuilder stringBuilder1 = new StringBuilder(); 36 | final int size = numbers.size(); // size()매번 호출하면 비효율 적이니까 이렇게... (문제에 집중하기 힘들어요 ㅠ_ㅠ) 37 | for (int i = 0; i < size; i++) { // i에 0 넣고 i가 size 보다 작으면... 가만? 우리가 왜 아직도 이런 코드를 짜야? ㅠ_ㅠ 38 | stringBuilder1.append(numbers.get(i)); // String 빌더에 Integer 추가 39 | if (i != size - 1) { // 현재 index값인 i가 List size 빼기 1 하고 같지 않다? 뭐지? 아! List에 저장된 마지막값! 40 | stringBuilder1.append(" : "); // " : " 추가 41 | } 42 | } 43 | 44 | /* for-each 사용 */ 45 | final StringBuilder stringBuilder = new StringBuilder(); 46 | final String separator = " : "; // 각 숫자를 연결해줄 " : " 47 | for (final Integer number : numbers) { // 저장된 숫자를 하나씩 받아서 48 | stringBuilder.append(number).append(separator); // String빌더에 숫자 + " : " 추가 49 | } 50 | final int stringLength = stringBuilder.length(); // 빌더 length를 얻고... 근데 왜??? 51 | if (stringLength > 0) { // length가 0 보다 크면... 그러니까 왜??? 아!? 뭔가 들어 있으면? isNotEmpty 같은거 없나? 52 | stringBuilder.delete(stringLength - separator.length(), stringLength); 53 | // String빌더 length 빼기 " : ".length부터 String빌더 length까지 지우기? 이게 뭐야? 54 | } 55 | System.out.println(stringBuilder.toString()); 56 | 57 | /* Java 8 버전 */ 58 | final String result = numbers.stream() 59 | .map(String::valueOf) // 각 Integer를 String으로 변환 60 | .collect(joining(" : ")); // 1 : 2 : 3 : ... 10 끝! 61 | System.out.println(result); 62 | } 63 | 64 | private static void readFile() throws IOException { 65 | /* Java 7 */ 66 | try (final FileReader fileReader = new FileReader(new File("/tmp/test.txt")); 67 | final BufferedReader bufferedReader = new BufferedReader(fileReader)) { 68 | 69 | final List uniqueWords = new ArrayList<>(); // 이게 왜 필요하죠? 70 | String line = bufferedReader.readLine(); // 파일 한줄씩 읽기 71 | while (line != null) { // Q: line == null이면 무슨일이? A: EOF 72 | final String[] words = line.split("[\\s]+"); // 공백 문자로 String 나누기 73 | for (final String word : words) { 74 | if (!uniqueWords.contains(word)) { // uniqueWords 안에 word가 없다면? 75 | uniqueWords.add(word); // uniqueWords 안에 word 넣기 76 | } 77 | } 78 | line = bufferedReader.readLine(); // 앗! 깜빡할뻔! 다음 줄 읽기... 79 | } 80 | Collections.sort(uniqueWords); // 오름차순 정렬 (String 기본 정렬) 81 | System.out.println(uniqueWords); 82 | } 83 | // 익셉션을 먹어치운다구요?! 84 | // 절대 집에서 따라하지 마세요. ㅡ_ㅡ; 85 | // catch (final Exception e) { // immutability 를 좋아하는 저는 여기도 final을 씁니다. ;) 이건 따라하면 좋아요. ^^ 86 | // } 87 | 88 | /* Java 8 */ 89 | try (final Stream lines = Files.lines(Paths.get("/tmp/test.txt"))) { 90 | System.out.println( 91 | lines.map(line -> line.split("[\\s]+")) // String을 공백문자로 나누기 92 | .flatMap(Arrays::stream) // Stream => Stream => Stream 이 귀찮은 2단변신 과정을 한줄로! 93 | .distinct() // 유일한 단어만 94 | .sorted() // 오름차순 정렬 (String 기본 정렬) 95 | .collect(toList()) 96 | ); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e02_function/FunctionExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e02_function; 2 | 3 | import java.util.function.Function; 4 | 5 | /** 6 | * @author Kevin Lee 7 | * @since 2015-08-01 8 | */ 9 | public class FunctionExamples { 10 | 11 | private static void functionExamples() { 12 | 13 | final Function toInt = value -> Integer.parseInt(value); 14 | 15 | final Integer number = toInt.apply("100"); 16 | System.out.println(number); 17 | 18 | final Function identity = Function.identity(); 19 | final Function identity2 = t -> t; 20 | 21 | System.out.println(identity.apply(999)); 22 | System.out.println(identity2.apply(999)); 23 | } 24 | 25 | 26 | public static void main(final String[] args) { 27 | functionExamples(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e03_consumer/ConsumerExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e03_consumer; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * @author Kevin Lee 7 | * @since 2015-08-01 8 | */ 9 | public class ConsumerExamples { 10 | 11 | private static void consumerExamples() { 12 | 13 | final Consumer print = value -> System.out.println(value); 14 | print.accept("Hello"); 15 | 16 | final Consumer greetings = value -> System.out.println("Hello " + value); 17 | greetings.accept("World"); 18 | greetings.accept("Kevin"); 19 | 20 | } 21 | 22 | public static void main(final String[] args) { 23 | consumerExamples(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e04_predicate/PredicateExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e04_predicate; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.function.Predicate; 7 | 8 | /** 9 | * @author Kevin Lee 10 | * @since 2015-08-01 11 | */ 12 | public class PredicateExamples { 13 | 14 | private static void predicateExamples() { 15 | 16 | final Predicate isPositive = i -> i > 0; 17 | 18 | System.out.println(isPositive.test(1)); 19 | System.out.println(isPositive.test(0)); 20 | System.out.println(isPositive.test(-1)); 21 | 22 | final List numbers = Arrays.asList(-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5); 23 | 24 | final List positiveNumbers = new ArrayList<>(); 25 | for (final Integer num : numbers) { 26 | if (isPositive.test(num)) { 27 | positiveNumbers.add(num); 28 | } 29 | } 30 | System.out.println("positive integers: " + positiveNumbers); 31 | 32 | final Predicate lessThan3 = i -> i < 3; 33 | final List numbersLessThan3 = new ArrayList<>(); 34 | for (final Integer num : numbers) { 35 | if (lessThan3.test(num)) { 36 | numbersLessThan3.add(num); 37 | } 38 | } 39 | System.out.println("less than 3: " + numbersLessThan3); 40 | 41 | System.out.println("positive integers: " + filter(numbers, isPositive)); 42 | System.out.println("less than 3: " + filter(numbers, lessThan3)); 43 | 44 | } 45 | 46 | private static List filter(final List list, final Predicate filter) { 47 | final List result = new ArrayList<>(); 48 | for (final T input : list) { 49 | if (filter.test(input)) { 50 | result.add(input); 51 | } 52 | } 53 | return result; 54 | } 55 | 56 | public static void main(final String[] args) { 57 | predicateExamples(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e05_supplier/SupplierExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e05_supplier; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.function.Supplier; 5 | 6 | /** 7 | * @author Kevin Lee 8 | * @since 2015-08-01 9 | */ 10 | public class SupplierExamples { 11 | 12 | /** 13 | * 계산 하는데 오래 걸리는 메소드를 시뮬레이션 해봤습니다. 항상 3초가 걸려요. 14 | * 15 | * @return 항상 "Kevin"만 리턴 16 | */ 17 | private static String getVeryExpensiveValue() { 18 | try { 19 | TimeUnit.SECONDS.sleep(3); 20 | } catch (InterruptedException e) { 21 | e.printStackTrace(); 22 | } 23 | return "Kevin"; 24 | } 25 | 26 | private static void callingExpensiveMethodWithoutSupplier() { 27 | System.out.println("SupplierExamples.callingExpensiveMethodWithoutSupplier()"); 28 | final long start = System.currentTimeMillis(); 29 | printIfValidIndex(0, getVeryExpensiveValue()); 30 | printIfValidIndex(-1, getVeryExpensiveValue()); 31 | printIfValidIndex(-2, getVeryExpensiveValue()); 32 | System.out.println("It took " + ((System.currentTimeMillis() - start) / 1000) + " seconds."); 33 | 34 | } 35 | 36 | private static void printIfValidIndex(final int number, final String value) { 37 | if (number >= 0) { 38 | System.out.println("The value is " + value + "."); 39 | } else { 40 | System.out.println("Invalid"); 41 | } 42 | } 43 | 44 | private static void callingExpensiveMethodWithSupplier() { 45 | System.out.println("SupplierExamples.callingExpensiveMethodWithSupplier()"); 46 | final long start = System.currentTimeMillis(); 47 | printIfValidIndex(0, () -> getVeryExpensiveValue()); 48 | printIfValidIndex(-1, () -> getVeryExpensiveValue()); 49 | printIfValidIndex(-2, () -> getVeryExpensiveValue()); 50 | System.out.println("It took " + ((System.currentTimeMillis() - start) / 1000) + " seconds."); 51 | } 52 | 53 | 54 | private static void printIfValidIndex(final int number, final Supplier valueSupplier) { 55 | if (number >= 0) { 56 | System.out.println("The value is " + valueSupplier.get() + "."); 57 | } else { 58 | System.out.println("Invalid"); 59 | } 60 | } 61 | 62 | 63 | private static void supplierExamples() { 64 | System.out.println("SupplierExamples.supplierExamples()"); 65 | final Supplier helloSupplier = () -> "Hello "; 66 | System.out.println(helloSupplier.get() + "world"); 67 | } 68 | 69 | 70 | public static void main(final String[] args) { 71 | supplierExamples(); 72 | 73 | System.out.println("\nSupplier 사용하지 않고 시간 오래 걸리는 메소드 호출"); 74 | callingExpensiveMethodWithoutSupplier(); 75 | 76 | System.out.println("\nSupplier 사용해서 시간 오래 걸리는 메소드 호출"); 77 | callingExpensiveMethodWithSupplier(); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e06_custom_functionalinterface/CustomFunctionalInterfaceExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e06_custom_functionalinterface; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * @author Kevin Lee 7 | * @since 2015-08-01 8 | */ 9 | public class CustomFunctionalInterfaceExamples { 10 | 11 | public static void main(final String[] args) { 12 | println(1, 2, 3, 13 | (i1, i2, i3) -> String.valueOf(i1 + i2 + i3)); 14 | println("Area is ", 12, 20, 15 | (message, length, width) -> message + (length * width)); 16 | println(1L, "Kevin", "test@email.com", 17 | (id, name, email) -> "User info: ID=" + id + ", name=" + name + ", email=" + email); 18 | 19 | final Function3 f3 = (i1, i2, i3) -> String.valueOf(i1 + i2 + i3); 20 | 21 | final BigDecimalToCurrency bigDecimalToCurrency = bd -> "$" + bd.toString(); 22 | System.out.println(bigDecimalToCurrency.toCurrency(new BigDecimal("120.00"))); 23 | 24 | final InvalidFunctionalInterface anonymousClass = new InvalidFunctionalInterface() { 25 | @Override 26 | public String mkString(final T value) { 27 | return value.toString(); 28 | } 29 | }; 30 | System.out.println("anonymous class: " + anonymousClass.mkString(123)); 31 | 32 | // value -> value.toString() 부분에서 에러! Target method is generic. 33 | // final InvalidFunctionalInterface invalidFunctionalInterface = value -> value.toString(); 34 | // System.out.println(invalidFunctionalInterface.mkString(123)); 35 | } 36 | 37 | private static void println(T1 t1, T2 t2, T3 t3, Function3 function) { 38 | System.out.println(function.apply(t1, t2, t3)); 39 | } 40 | } 41 | 42 | @FunctionalInterface 43 | interface Function3 { 44 | R apply(T1 t1, T2 t2, T3 t3); 45 | 46 | // void print(int i); 47 | } 48 | 49 | @FunctionalInterface 50 | interface BigDecimalToCurrency { 51 | String toCurrency(BigDecimal value); 52 | } 53 | 54 | /** 55 | * Generic method를 가지는 FunctionalInterface는 56 | * Lambda Expression을 사용할수 없습니다. 57 | */ 58 | @FunctionalInterface 59 | interface InvalidFunctionalInterface { 60 | String mkString(T value); 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e07_functionalinterface_examples/FunctionalInterfaceExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e07_functionalinterface_examples; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | 7 | import java.math.BigDecimal; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | import java.util.function.Function; 12 | import java.util.function.Predicate; 13 | 14 | /** 15 | * @author Kevin Lee 16 | * @since 2015-08-08 17 | */ 18 | public class FunctionalInterfaceExamples { 19 | public static void main(String[] args) { 20 | final Product productA = new Product(1L, "A", new BigDecimal("10.00")); 21 | final Product productB = new Product(2L, "B", new BigDecimal("55.50")); 22 | final Product productC = new Product(3L, "C", new BigDecimal("17.45")); 23 | final Product productD = new Product(4L, "D", new BigDecimal("20.00")); 24 | final Product productE = new Product(5L, "E", new BigDecimal("110.99")); 25 | final List products = Arrays.asList(productA, productB, productC, productD, productE); 26 | 27 | final BigDecimal twenty = new BigDecimal("20"); 28 | /* 가격이 $20 이상 되는 Product 찾기 */ 29 | System.out.println("products >= $20: " + 30 | filter(products, product -> product.getPrice().compareTo(twenty) >= 0) 31 | ); 32 | /* 가격이 $10 이하 되는 Product 찾기 */ 33 | System.out.println("products <= $10: " + 34 | filter(products, product -> product.getPrice().compareTo(new BigDecimal("10")) <= 0) 35 | ); 36 | 37 | /* 가격이 $50 초과되는 Product 찾기 */ 38 | final List expensiveProducts = 39 | filter(products, product -> product.getPrice().compareTo(new BigDecimal("50")) > 0); 40 | 41 | /* 42 | * 가격이 $50 초과되는 Product를 찾은후 (filter) 43 | * 50% 할인 가격 적용 (원래 가격 * 0.5) 44 | */ 45 | final List discountedProducts = 46 | map( 47 | filter(products, product -> product.getPrice().compareTo(new BigDecimal("50")) > 0), 48 | product -> new DiscountedProduct(product.getId(), 49 | product.getName(), 50 | product.getPrice().multiply(new BigDecimal("0.5"))) 51 | ); 52 | 53 | System.out.println(" expensive products: " + expensiveProducts); 54 | System.out.println("discounted products: " + discountedProducts); 55 | 56 | final Predicate lessThanOrEqualTo30 = 57 | product -> product.getPrice().compareTo(new BigDecimal("30")) <= 0; 58 | System.out.println("discounted products (<= $30)" + 59 | filter(discountedProducts, lessThanOrEqualTo30) 60 | ); 61 | System.out.println(" products (<= $30)" + 62 | filter(products, lessThanOrEqualTo30) 63 | ); 64 | 65 | final List prices = map(products, product -> product.getPrice()); 66 | BigDecimal total = BigDecimal.ZERO; 67 | for (final BigDecimal price : prices) { 68 | total = total.add(price); 69 | } 70 | System.out.println(" total: " + total); 71 | 72 | final BigDecimal newTotal = total(products, product -> product.getPrice()); 73 | System.out.println("newTotal: " + newTotal); 74 | 75 | final BigDecimal discountedTotal = total(discountedProducts, product -> product.getPrice()); 76 | System.out.println("discountedTotal: " + discountedTotal); 77 | 78 | 79 | final Order order = new Order(1L, "on-1234", Arrays.asList( 80 | new OrderedItem(1L, productA, 2), 81 | new OrderedItem(2L, productC, 1), 82 | new OrderedItem(3L, productD, 10) 83 | )); 84 | 85 | BigDecimal orderTotal = BigDecimal.ZERO; 86 | for (OrderedItem item : order.getItems()) { 87 | orderTotal = 88 | /* price * quantity = OrderedItem 가격합계 */ 89 | orderTotal.add( 90 | item.getProduct().getPrice().multiply(new BigDecimal(item.getQuantity())) 91 | ); 92 | } 93 | System.out.println("order total in old way: " + orderTotal); 94 | System.out.println(" order total: " + order.totalPrice()); 95 | 96 | } 97 | 98 | private static List filter(final List list, final Predicate predicate) { 99 | final List result = new ArrayList<>(); 100 | for (final T t : list) { 101 | if (predicate.test(t)) { 102 | /* Predicate.test()를 만족하는 경우만 저장 */ 103 | result.add(t); 104 | } 105 | } 106 | return result; 107 | } 108 | 109 | private static List map(final List list, final Function function) { 110 | final List result = new ArrayList<>(); 111 | for (final T t : list) { 112 | /* function을 이용해서 타입변환: T -> R */ 113 | result.add(function.apply(t)); 114 | } 115 | return result; 116 | } 117 | 118 | private static BigDecimal total(final List list, final Function mapper) { 119 | BigDecimal total = BigDecimal.ZERO; 120 | for (final T t : list) { 121 | /* mapper를 이용해서 T타입을 BigDecimal로 변환 */ 122 | total = total.add(mapper.apply(t)); 123 | } 124 | return total; 125 | } 126 | 127 | /* 이 아래에 있는 JavaBean들은 Lombok을 사용하셔야 합니다. 영상을 참조해 주세요. */ 128 | 129 | @AllArgsConstructor 130 | @Data 131 | static class Product { 132 | private Long id; 133 | private String name; 134 | private BigDecimal price; 135 | } 136 | 137 | @ToString(callSuper = true) 138 | static class DiscountedProduct extends Product { 139 | public DiscountedProduct(final Long id, final String name, final BigDecimal price) { 140 | super(id, name, price); 141 | } 142 | } 143 | 144 | @AllArgsConstructor 145 | @Data 146 | static class OrderedItem { 147 | private Long id; 148 | private Product product; 149 | private int quantity; 150 | 151 | public BigDecimal getItemTotal() { 152 | return product.getPrice().multiply(new BigDecimal(quantity)); 153 | } 154 | } 155 | 156 | @AllArgsConstructor 157 | @Data 158 | static class Order { 159 | private Long id; 160 | private String orderNumber; 161 | private List items; 162 | 163 | public BigDecimal totalPrice() { 164 | return total(items, item -> item.getItemTotal()); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_01_stream_prelude/StreamPrelude.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_01_stream_prelude; 2 | 3 | /** 4 | * @author Kevin Lee 5 | * @since 2015-08-15 6 | */ 7 | public class StreamPrelude { 8 | public static void main(String[] args) { 9 | /** 10 | * 다른 입력값, 같은 결과값 11 | * 입력: -1, 1 12 | * 결과: 1 13 | */ 14 | final int abs1 = Math.abs(-1); 15 | final int abs2 = Math.abs(1); 16 | 17 | System.out.println("abs1: " + abs1); 18 | System.out.println("abs2: " + abs2); 19 | System.out.println("abs1 == abs2 is " + (abs1 == abs2)); 20 | 21 | /** 22 | * 입력값: -2147483648 23 | * 결과값: -2147483648 24 | * WARNING!: 사용하실때 주의하세요! 25 | */ 26 | System.out.println(Integer.MIN_VALUE); 27 | System.out.println(Integer.MAX_VALUE); 28 | final int minInt = Math.abs(Integer.MIN_VALUE); 29 | System.out.println("minInt: " + minInt); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_02_identity/IdentityExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_02_identity; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.function.Function; 7 | 8 | /** 9 | * @author Kevin Lee 10 | * @since 2015-08-15 11 | */ 12 | public class IdentityExamples { 13 | public static void main(String[] args) { 14 | 15 | final List numbers = Arrays.asList(1, 2, 3, 4, 5); 16 | System.out.println("\nmapOld(numbers, i -> i * 2)"); 17 | System.out.println( 18 | mapOld(numbers, i -> i * 2) 19 | ); 20 | 21 | System.out.println("mapOld(numbers, null)"); 22 | System.out.println( 23 | mapOld(numbers, null) 24 | ); 25 | 26 | System.out.println(""); 27 | System.out.println("map(numbers, i -> i * 2)\n" + 28 | map(numbers, i -> i * 2) 29 | ); 30 | System.out.println("map(numbers, i -> i)\n" + 31 | map(numbers, i -> i) 32 | ); 33 | System.out.println("map(numbers, Function.identity())\n" + 34 | map(numbers, Function.identity()) 35 | ); 36 | } 37 | 38 | private static List map(final List list, final Function mapper) { 39 | final List result = new ArrayList<>(); 40 | for (final T t : list) { 41 | result.add(mapper.apply(t)); 42 | } 43 | return result; 44 | } 45 | 46 | private static List mapOld(final List list, final Function mapper) { 47 | final List result; 48 | if (mapper != null) { 49 | result = new ArrayList<>(); 50 | } else { 51 | result = new ArrayList<>((List) list); 52 | } 53 | if (result.isEmpty()) { 54 | for (final T t : list) { 55 | result.add(mapper.apply(t)); 56 | } 57 | } 58 | return result; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_03_stream_01/StreamExamples1.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_03_stream_01; 2 | 3 | import java.math.BigInteger; 4 | import java.util.stream.IntStream; 5 | import java.util.stream.Stream; 6 | 7 | /** 8 | * @author Kevin Lee 9 | * @since 2015-08-15 10 | */ 11 | public class StreamExamples1 { 12 | public static void main(String[] args) { 13 | 14 | range(); 15 | /** 16 | * 아래 두 메소드를 실행하고 그냥 두시면 숫자가 계속 증가합니다. 17 | * 꼭 강제종료 시켜주세요. 18 | */ 19 | // infiniteCollection1(); 20 | // infiniteCollection2(); 21 | } 22 | 23 | private static void range() { 24 | /** 25 | * 0 1 2 3 4 5 6 7 8 9 26 | */ 27 | IntStream.range(0, 10) 28 | .forEach(i -> System.out.print(i + " ")); 29 | 30 | /** 31 | * 1 2 3 4 5 6 7 8 9 10 32 | */ 33 | IntStream.rangeClosed(1, 10) 34 | .forEach(i -> System.out.print(i + " ")); 35 | } 36 | 37 | /** 38 | * int를 이용한 무한 Collection 39 | */ 40 | private static void infiniteCollection1() { 41 | IntStream.iterate(1, i -> i + 1) 42 | .forEach(i -> System.out.print(i + " ")); 43 | } 44 | 45 | /** 46 | * BigInteger를 이용한 무한 Collection 47 | */ 48 | private static void infiniteCollection2() { 49 | Stream.iterate(BigInteger.ONE, i -> i.add(BigInteger.ONE)) 50 | .forEach(i -> System.out.print(i + " ")); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_03_stream_02/StreamExamples2.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_03_stream_02; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | import java.util.function.Function; 8 | import java.util.function.Predicate; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * @author Kevin Lee 13 | * @since 2015-08-16 14 | */ 15 | public class StreamExamples2 { 16 | private static final List NUMBERS = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 17 | 18 | public static void main(String[] args) { 19 | Stream.of(1, 2, 3, 4, 5) 20 | .forEach(i -> System.out.print(i + " ")); 21 | System.out.println("\n=================================="); 22 | 23 | Integer result = null; 24 | for (final Integer number : NUMBERS) { 25 | if (number > 3 && number < 9) { 26 | final Integer newNumber = number * 2; 27 | if (newNumber > 10) { 28 | result = newNumber; 29 | break; 30 | } 31 | } 32 | } 33 | System.out.println("\n=================================="); 34 | System.out.println("Imperative Result: " + result); 35 | 36 | 37 | System.out.println("\n=================================="); 38 | System.out.println("Functional Result: " + 39 | NUMBERS.stream() 40 | .filter(number -> number > 3) 41 | .filter(number -> number < 9) 42 | .map(number -> number * 2) 43 | .filter(number -> number > 10) 44 | .findFirst() 45 | ); 46 | 47 | System.out.println("\n=================================="); 48 | System.out.println("Functional Result (with logging): " + 49 | NUMBERS.stream() 50 | .filter(number -> { 51 | System.out.println("number > 3"); 52 | return number > 3; 53 | }) 54 | .filter(number -> { 55 | System.out.println("number < 9"); 56 | return number < 9; 57 | }) 58 | .map(number -> { 59 | System.out.println("number * 2"); 60 | return number * 2; 61 | }) 62 | .filter(number -> { 63 | System.out.println("number > 10"); 64 | return number > 10; 65 | }) 66 | .findFirst() 67 | ); 68 | System.out.println("\n=================================="); 69 | 70 | final List greaterThan3 = filter(NUMBERS, i -> i > 3); 71 | final List lessThan9 = filter(greaterThan3, i -> i < 9); 72 | final List doubled = map(lessThan9, i -> i * 2); 73 | final List greaterThan10 = filter(doubled, i -> i > 10); 74 | System.out.println("My own method result: " + greaterThan10); 75 | System.out.println("My own method result.get(0): " + greaterThan10.get(0)); 76 | 77 | System.out.println("\n=================================="); 78 | final List myOwnMethodResult = 79 | filter( 80 | map( 81 | filter( 82 | filter(NUMBERS, 83 | i -> i > 3), 84 | i -> i < 9), 85 | i -> i * 2), 86 | i -> i > 10); 87 | System.out.println("My own method result: " + myOwnMethodResult); 88 | System.out.println("My own method result.get(0): " + myOwnMethodResult.get(0)); 89 | 90 | System.out.println("\n=================================="); 91 | customMethodsWithLogging(); 92 | } 93 | 94 | private static void customMethodsWithLogging() { 95 | final AtomicInteger count = new AtomicInteger(1); 96 | 97 | final List greaterThan3 = filter(NUMBERS, i -> { 98 | System.out.println(count.getAndAdd(1) + ": i > 3"); 99 | return i > 3; 100 | }); 101 | final List lessThan9 = filter(greaterThan3, i -> { 102 | System.out.println(count.getAndAdd(1) + ": i < 9"); 103 | return i < 9; 104 | }); 105 | final List doubled = map(lessThan9, i -> { 106 | System.out.println(count.getAndAdd(1) + ": i * 2"); 107 | return i * 2; 108 | }); 109 | final List greaterThan10 = filter(doubled, i -> { 110 | System.out.println(count.getAndAdd(1) + ": i > 10"); 111 | return i > 10; 112 | }); 113 | System.out.println("My own method result: " + greaterThan10); 114 | System.out.println("My own method result.get(0): " + greaterThan10.get(0)); 115 | } 116 | 117 | private static List filter(List list, Predicate predicate) { 118 | final List result = new ArrayList<>(); 119 | for (final T t : list) { 120 | if (predicate.test(t)) { 121 | result.add(t); 122 | } 123 | } 124 | return result; 125 | } 126 | 127 | private static List map(List list, Function mapper) { 128 | final List result = new ArrayList<>(); 129 | for (final T t : list) { 130 | result.add(mapper.apply(t)); 131 | } 132 | return result; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_03_stream_03/StreamExamples3.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_03_stream_03; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.stream.Stream; 6 | 7 | import static java.util.stream.Collectors.*; 8 | 9 | /** 10 | * @author Kevin Lee 11 | * @since 2015-08-22 12 | */ 13 | public class StreamExamples3 { 14 | public static void main(String[] args) { 15 | System.out.println("collect(toList()): " + 16 | Stream.of(1, 3, 3, 5, 5) 17 | .filter(i -> i > 2) 18 | .map(i -> i * 2) 19 | .map(i -> "#" + i) 20 | .collect(toList()) 21 | ); 22 | 23 | System.out.println("collect(toSet()): " + 24 | Stream.of(1, 3, 3, 5, 5) 25 | .filter(i -> i > 2) 26 | .map(i -> i * 2) 27 | .map(i -> "#" + i) 28 | .collect(toSet()) 29 | ); 30 | 31 | System.out.println("collect(joining()): " + 32 | Stream.of(1, 3, 3, 5, 5) 33 | .filter(i -> i > 2) 34 | .map(i -> i * 2) 35 | .map(i -> "#" + i) 36 | .collect(joining()) 37 | ); 38 | 39 | System.out.println("collect(joining(\", \")): " + 40 | Stream.of(1, 3, 3, 5, 5) 41 | .filter(i -> i > 2) 42 | .map(i -> i * 2) 43 | .map(i -> "#" + i) 44 | .collect(joining(", ")) 45 | ); 46 | 47 | System.out.println("collect(joining(\", \", \"[\", \"]\")): " + 48 | Stream.of(1, 3, 3, 5, 5) 49 | .filter(i -> i > 2) 50 | .map(i -> i * 2) 51 | .map(i -> "#" + i) 52 | .collect(joining(", ", "[", "]")) // [#6, #6, #10, #10] 53 | ); 54 | 55 | System.out.println("distinct().collect(joining(\", \", \"[\", \"]\")): " + 56 | Stream.of(1, 3, 3, 5, 5) 57 | .filter(i -> i > 2) 58 | .map(i -> i * 2) 59 | .map(i -> "#" + i) 60 | .distinct() 61 | .collect(joining(", ", "[", "]")) 62 | ); 63 | 64 | System.out.println("distinct().collect(toList()): " + 65 | Stream.of(1, 3, 3, 5, 5) 66 | .filter(i -> i > 2) 67 | .map(i -> i * 2) 68 | .map(i -> "#" + i) 69 | .distinct() 70 | .collect(toList()) 71 | ); 72 | 73 | final Integer integer3 = 3; 74 | System.out.println( 75 | Stream.of(1, 2, 3, 4, 5) 76 | .filter(i -> i == integer3) 77 | .findFirst() 78 | ); 79 | 80 | final Integer integer127 = 127; 81 | System.out.println( 82 | Stream.of(1, 2, 3, 4, 5, 127) 83 | .filter(i -> i == integer127) 84 | .findFirst() 85 | ); 86 | 87 | final Integer integer128 = 128; 88 | System.out.println( 89 | Stream.of(1, 2, 3, 4, 5, 128) 90 | .filter(i -> i == integer128) 91 | .findFirst() 92 | ); 93 | 94 | 95 | System.out.println( 96 | Stream.of(1, 2, 3, 4, 5, 128) 97 | .filter(i -> i.equals(integer128)) 98 | .findFirst() 99 | ); 100 | 101 | System.out.println(".filter(i -> i > integer3).count(): " + 102 | Stream.of(1, 2, 3, 4, 5) 103 | .filter(i -> i > integer3) 104 | .count() 105 | ); 106 | 107 | final List numbers = Arrays.asList(1, 2, 3, 4, 5); 108 | System.out.println("for (Integer i : numbers): "); 109 | for (Integer i : numbers) { 110 | System.out.print("i = " + i + " "); 111 | } 112 | 113 | System.out.println("\n\nforEach(i -> System.out.println(i)): "); 114 | Stream.of(1, 2, 3, 4, 5) 115 | .forEach(i -> System.out.print(i + " ")); 116 | 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_03_stream_04/StreamExamples4.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_03_stream_04; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.stream.IntStream; 10 | 11 | import static java.util.stream.Collectors.*; 12 | 13 | /** 14 | * @author Kevin Lee 15 | * @since 2015-08-22 16 | */ 17 | public class StreamExamples4 { 18 | public static void main(String[] args) { 19 | final List products = 20 | Arrays.asList( 21 | new Product(1L, "A", new BigDecimal("100.50")), 22 | new Product(2L, "B", new BigDecimal("23.00")), 23 | new Product(3L, "C", new BigDecimal("31.45")), 24 | new Product(4L, "D", new BigDecimal("80.20")), 25 | new Product(5L, "E", new BigDecimal("7.50")) 26 | ); 27 | 28 | System.out.println("Products.price >= 30: \n" + 29 | products.stream() 30 | .filter(product -> product.getPrice().compareTo(new BigDecimal("30")) >= 0) 31 | .collect(toList()) 32 | ); 33 | System.out.println("\n=================================="); 34 | System.out.println("Products.price >= 30 (with joining(\"\\n\")): \n" + 35 | products.stream() 36 | .filter(product -> product.getPrice().compareTo(new BigDecimal("30")) >= 0) 37 | .map(product -> product.toString()) 38 | .collect(joining("\n")) 39 | ); 40 | 41 | System.out.println("\n==========================="); 42 | System.out.println("IntStream.sum: " + 43 | IntStream.of(1, 2, 3, 4, 5) 44 | .sum() 45 | ); 46 | 47 | System.out.println("\n==========================="); 48 | System.out.println("Total Price: " + 49 | products.stream() 50 | .map(product -> product.getPrice()) 51 | .reduce(BigDecimal.ZERO, (price1, price2) -> price1.add(price2)) 52 | ); 53 | 54 | System.out.println("\n==========================="); 55 | System.out.println("Total price (where Product.price >= 30): " + 56 | products.stream() 57 | .filter(product -> product.getPrice().compareTo(new BigDecimal("30")) >= 0) 58 | .map(product -> product.getPrice()) 59 | .reduce(BigDecimal.ZERO, (price1, price2) -> price1.add(price2)) 60 | ); 61 | 62 | System.out.println("\n==========================="); 63 | /* 64 | * BigDecimal타입과 Product타입을 동시에 사용하는 방법입니다만, 65 | * 불필요한 코드가 늘고 가독성이 떨어지기 때문에 권장하지 않습니다 66 | */ 67 | System.out.println("Total price (where Product.price >= 30) (not recommended): " + 68 | products.stream() 69 | .filter(product -> product.getPrice().compareTo(new BigDecimal("30")) >= 0) 70 | .reduce(BigDecimal.ZERO, 71 | (price, product) -> price.add(product.getPrice()), // (BigDecimal, Product) -> BigDecimal 72 | (price1, price2) -> price1.add(price2)) // (BigDecimal, BigDecimal) -> BigDecimal 73 | ); 74 | 75 | System.out.println("\n==========================="); 76 | System.out.println("The number of Products (where Product.price >= 30): " + 77 | products.stream() 78 | .filter(product -> product.getPrice().compareTo(new BigDecimal("30")) >= 0) 79 | .count() 80 | ); 81 | 82 | final OrderedItem item1 = new OrderedItem(1L, products.get(0), 1); 83 | final OrderedItem item2 = new OrderedItem(2L, products.get(2), 3); 84 | final OrderedItem item3 = new OrderedItem(3L, products.get(4), 10); 85 | 86 | final Order order = new Order(1L, Arrays.asList(item1, item2, item3)); 87 | 88 | System.out.println("\n==========================="); 89 | System.out.println("order.totalPrice(): " + order.totalPrice()); 90 | } 91 | } 92 | 93 | @AllArgsConstructor 94 | @Data 95 | class Product { 96 | private Long id; 97 | private String name; 98 | private BigDecimal price; 99 | } 100 | 101 | @AllArgsConstructor 102 | @Data 103 | class OrderedItem { 104 | private Long id; 105 | private Product product; 106 | private int quantity; 107 | 108 | public BigDecimal getTotalPrice() { 109 | return product.getPrice().multiply(new BigDecimal(quantity)); 110 | } 111 | } 112 | 113 | @AllArgsConstructor 114 | @Data 115 | class Order { 116 | private Long id; 117 | private List items; 118 | 119 | public BigDecimal totalPrice() { 120 | return items.stream() 121 | .map(item -> item.getTotalPrice()) 122 | .reduce(BigDecimal.ZERO, (price1, price2) -> price1.add(price2)); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_03_stream_05_parallel/StreamExamples5Parallel.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_03_stream_05_parallel; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.TimeUnit; 5 | import java.util.stream.IntStream; 6 | 7 | import static java.util.stream.Collectors.*; 8 | 9 | /** 10 | * @author Kevin Lee 11 | * @since 2015-08-23 12 | */ 13 | public class StreamExamples5Parallel { 14 | 15 | 16 | public static void main(String[] args) { 17 | 18 | raceConditionTest(); 19 | 20 | /* 21 | * 사용중인 컴퓨터의 코어 개수를 찾는 코드입니다. 22 | */ 23 | int numOfCores = Runtime.getRuntime().availableProcessors(); 24 | 25 | streamTest(numOfCores); 26 | 27 | parallelStreamTest(numOfCores); 28 | parallelStreamTest(numOfCores + 1); 29 | 30 | /** 31 | * System.setProperty로 parallelism을 설정할 경우 몇 가지 문제가 있을 수 있습니다. 32 | * 1. JVM레벨 설정이므로 예기치 못한곳에서 원치 않는 코어 사용/비사용 문제가 발생할수 있습니다. 33 | * 2. System.setProperty로 parallelism을 설정하기 전에 Parallel Stream 을 사용할 경우 34 | * setProperty로 설정한 값의 영향을 받지 않는것을 확인 했습니다. 아무래도 이미 생성된 ForkJoinPool을 내부적으로 35 | * 그대로 사용하기 때문인것 같습니다. 36 | * 3. 결국 JVM 실행시 옵션으로 설정하시는것을 권장합니다. 37 | * e.g.) java -D java.util.concurrent.ForkJoinPool.common.parallelism=3 some.package.MainClassName 38 | */ 39 | // System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", String.valueOf(numOfCores - 1)); 40 | parallelStreamTest(numOfCores); 41 | } 42 | 43 | 44 | /** 45 | * Race Condition을 보여주는 코드입니다. 46 | * Parallel Programming을 할경우 side-effect, 이 예제의 경우, variable의 값을 47 | * 계속 re-assign하는 방법을 이용하게 되면 Race Condition이 발생하기 쉽습니다. 48 | */ 49 | private static void raceConditionTest() { 50 | System.out.println("\n========================================="); 51 | System.out.println("StreamExamples5Parallel.raceConditionTest"); 52 | 53 | final int[] sum = {0}; 54 | IntStream.range(0, 100) 55 | .forEach(i -> sum[0] += i); 56 | 57 | System.out.println(" stream sum (side-effect): " + sum[0]); 58 | final int[] sum2 = {0}; 59 | IntStream.range(0, 100) 60 | .parallel() 61 | .forEach(i -> sum2[0] += i); 62 | 63 | System.out.println(" parallel sum (side-effect): " + sum2[0]); 64 | 65 | System.out.println(" stream sum (no side-effect): " + 66 | IntStream.range(0, 100) 67 | .sum()); 68 | 69 | System.out.println("parallel stream sum (no side-effect): " + 70 | IntStream.range(0, 100) 71 | .parallel() 72 | .sum()); 73 | } 74 | 75 | 76 | private static void streamTest(int numOfCores) { 77 | 78 | System.out.println("\n=================================="); 79 | System.out.println("StreamExamples5Parallel.streamTest"); 80 | final List numbers = getNumbers(numOfCores); 81 | System.out.println("Stream (" + numbers.size() + " elements)"); 82 | final long start = System.currentTimeMillis(); 83 | numbers 84 | .stream() 85 | .map(i -> { 86 | try { 87 | TimeUnit.SECONDS.sleep(1); 88 | } catch (InterruptedException e) { 89 | e.printStackTrace(); 90 | } 91 | return i; 92 | }) 93 | .forEach(i -> System.out.println(i)); 94 | System.out.println(System.currentTimeMillis() - start); 95 | 96 | } 97 | 98 | public void test(int num) { 99 | System.out.println("System.setProperty(\"java.util.concurrent.ForkJoinPool.common.parallelism\", \"" + num + 100 | "\"): " + System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", String.valueOf(num))); 101 | 102 | parallelStreamTest(8); 103 | } 104 | 105 | private static void parallelStreamTest(int numOfCores) { 106 | 107 | System.out.println("\n=========================================="); 108 | System.out.println("StreamExamples5Parallel.parallelStreamTest"); 109 | final List numbers = getNumbers(numOfCores); 110 | 111 | System.out.println("Parallel Stream (" + numbers.size() + " elements)"); 112 | final long start2 = System.currentTimeMillis(); 113 | numbers.parallelStream() 114 | .map(i -> { 115 | try { 116 | TimeUnit.SECONDS.sleep(1); 117 | } catch (InterruptedException e) { 118 | e.printStackTrace(); 119 | } 120 | return i; 121 | }) 122 | .forEach(i -> System.out.println(i)); 123 | System.out.println(System.currentTimeMillis() - start2); 124 | } 125 | 126 | private static List getNumbers(final int howMany) { 127 | return IntStream.rangeClosed(1, howMany) 128 | .mapToObj(i -> i) // auto-boxing을 통해서 int 가 Integer로 자동변환 됩니다. 129 | .collect(toList()); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_03_stream_05_parallel/StreamExamples5ParallelPerformance.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_03_stream_05_parallel; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.stream.LongStream; 5 | import java.util.stream.Stream; 6 | 7 | /** 8 | * @author Kevin Lee 9 | * @since 2015-08-23 10 | */ 11 | public class StreamExamples5ParallelPerformance { 12 | 13 | private static void slowDown() { 14 | try { 15 | TimeUnit.MILLISECONDS.sleep(10L); 16 | } catch (InterruptedException e) { 17 | e.printStackTrace(); 18 | } 19 | } 20 | 21 | public static long iterativeSum(long n) { 22 | long result = 0; 23 | for (long i = 0; i <= n; i++) { 24 | result += i; 25 | slowDown(); 26 | } 27 | return result; 28 | } 29 | 30 | public static long sequentialSum(long n) { 31 | return Stream.iterate(1L, i -> i + 1).limit(n).peek(i -> slowDown()).reduce(Long::sum).get(); 32 | } 33 | 34 | public static long parallelSum(long n) { 35 | return Stream.iterate(1L, i -> i + 1).limit(n).parallel().peek(i -> slowDown()).reduce(Long::sum).get(); 36 | } 37 | 38 | public static long rangedSum(long n) { 39 | return LongStream.rangeClosed(1, n).peek(i -> slowDown()).reduce(Long::sum).getAsLong(); 40 | } 41 | 42 | public static long parallelRangedSum(long n) { 43 | return LongStream.rangeClosed(1, n).parallel().peek(i -> slowDown()).reduce(Long::sum).getAsLong(); 44 | } 45 | 46 | public static void main(String[] args) { 47 | final long n = 1000; 48 | final long start = System.currentTimeMillis(); 49 | // 1 + 2 + 3 + ... + 98 + 99 + 100 50 | System.out.println((1 + n) * (n / 2)); 51 | System.out.println(" Gauss Way: " + (System.currentTimeMillis() - start)); 52 | 53 | final long start1 = System.currentTimeMillis(); 54 | System.out.println(" iterativeSum(n): " + iterativeSum(n)); 55 | System.out.println(" " + (System.currentTimeMillis() - start1) + " ms\n"); 56 | final long start2 = System.currentTimeMillis(); 57 | System.out.println(" sequentialSum(n): " + sequentialSum(n)); 58 | System.out.println(" " + (System.currentTimeMillis() - start2) + " ms\n"); 59 | final long start3 = System.currentTimeMillis(); 60 | System.out.println(" parallelSum(n): " + parallelSum(n)); 61 | System.out.println(" " + (System.currentTimeMillis() - start3) + " ms\n"); 62 | final long start4 = System.currentTimeMillis(); 63 | System.out.println(" rangedSum(n): " + rangedSum(n)); 64 | System.out.println(" " + (System.currentTimeMillis() - start4) + " ms\n"); 65 | final long start5 = System.currentTimeMillis(); 66 | System.out.println("parallelRangedSum(n): " + parallelRangedSum(n)); 67 | System.out.println(" " + (System.currentTimeMillis() - start5) + " ms\n"); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e08_03_stream_05_parallel/StreamExamples5ParallelPerformancePractical.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e08_03_stream_05_parallel; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.*; 8 | import java.util.function.Predicate; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * @author Kevin Lee 13 | * @since 2015-08-23 14 | */ 15 | public class StreamExamples5ParallelPerformancePractical { 16 | private static final String[] priceStrings = {"1.0", "100.99", "35.75", "21.30", "88.00"}; 17 | private static final BigDecimal[] targetPrices = {new BigDecimal("30"), new BigDecimal("20"), new BigDecimal("31")}; 18 | private static final Random random = new Random(123); 19 | private static final Random targetPriceRandom = new Random(111); 20 | 21 | private static final List products; 22 | 23 | static { 24 | final int length = 8_000_000; 25 | final Product[] list = new Product[length]; 26 | 27 | for (int i = 1; i <= length; i++) { 28 | list[i - 1] = new Product((long) i, "Product" + i, new BigDecimal(priceStrings[random.nextInt(5)])); 29 | } 30 | products = Collections.unmodifiableList(Arrays.asList(list)); 31 | } 32 | 33 | private static BigDecimal imperativeSum(final List products, final Predicate predicate) { 34 | BigDecimal sum = BigDecimal.ZERO; 35 | for (final Product product : products) { 36 | if (predicate.test(product)) { 37 | sum = sum.add(product.getPrice()); 38 | } 39 | } 40 | return sum; 41 | } 42 | 43 | private static BigDecimal streamSum(final Stream stream, final Predicate predicate) { 44 | return stream.filter(predicate).map(Product::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add); 45 | } 46 | 47 | private static void imperativeTest(final BigDecimal targetPrice, final boolean printResult) { 48 | /** 49 | * Benchmark 코드라서 결코 일반 앱 개발등에 쓰기 좋은 코딩 스타일로 작성된것이 아닙니다. 50 | * (Stream사용 이외의) 이런 코드 작성을 절대 권장하지 않습니다. 51 | */ 52 | if (printResult) { 53 | System.out.println("============================================"); 54 | System.out.println("\nImperative Sum\n--------------------------------------------"); 55 | } 56 | final long start = System.currentTimeMillis(); 57 | final BigDecimal result = imperativeSum(products, product -> product.getPrice().compareTo(targetPrice) >= 0); 58 | final long howLong = System.currentTimeMillis() - start; 59 | if (printResult) { 60 | System.out.println("Sum: " + result); 61 | System.out.println("It took " + howLong + " ms."); 62 | System.out.println("============================================"); 63 | } 64 | } 65 | 66 | private static void streamTest(final BigDecimal targetPrice, final boolean printResult) { 67 | /** 68 | * Benchmark 코드라서 결코 일반 앱 개발등에 쓰기 좋은 코딩 스타일로 작성된것이 아닙니다. 69 | * (Stream사용 이외의) 이런 코드 작성을 절대 권장하지 않습니다. 70 | */ 71 | if (printResult) { 72 | System.out.println("============================================"); 73 | System.out.println("\nStream Sum\n--------------------------------------------"); 74 | } 75 | final long start = System.currentTimeMillis(); 76 | final BigDecimal result = streamSum(products.stream(), product -> product.getPrice().compareTo(targetPrice) >= 0); 77 | final long howLong = System.currentTimeMillis() - start; 78 | if (printResult) { 79 | System.out.println("Sum: " + result); 80 | System.out.println("It took " + howLong + " ms."); 81 | System.out.println("============================================"); 82 | } 83 | } 84 | 85 | private static void parallelStreamTest(final BigDecimal targetPrice, final boolean printResult) { 86 | /** 87 | * Benchmark 코드라서 결코 일반 앱 개발등에 쓰기 좋은 코딩 스타일로 작성된것이 아닙니다. 88 | * (Stream사용 이외의) 이런 코드 작성을 절대 권장하지 않습니다. 89 | */ 90 | if (printResult) { 91 | System.out.println("============================================"); 92 | System.out.println("\nParallel Stream Sum\n--------------------------------------------"); 93 | } 94 | final long start = System.currentTimeMillis(); 95 | final BigDecimal result = streamSum(products.parallelStream(), product -> product.getPrice().compareTo(targetPrice) >= 0); 96 | final long howLong = System.currentTimeMillis() - start; 97 | if (printResult) { 98 | System.out.println("Sum: " + result); 99 | System.out.println("It took " + howLong + " ms."); 100 | System.out.println("============================================"); 101 | } 102 | } 103 | 104 | public static void main(String[] args) { 105 | /** 106 | * Benchmark 코드라서 결코 일반 앱 개발등에 쓰기 좋은 코딩 스타일로 작성된것이 아닙니다. 107 | * (Stream사용 이외의) 이런 코드 작성을 절대 권장하지 않습니다. 108 | */ 109 | test1(); 110 | test2(); 111 | test3(); 112 | } 113 | 114 | private static void test1() { 115 | 116 | final BigDecimal targetPrice = new BigDecimal("40"); 117 | 118 | imperativeTest(targetPrice, false); 119 | streamTest(targetPrice, false); 120 | parallelStreamTest(targetPrice, false); 121 | 122 | System.out.println("\n\n================================================================\nTest1 Starts!"); 123 | for (int i = 0; i < 5; i++) { 124 | BigDecimal price = targetPrices[targetPriceRandom.nextInt(3)]; 125 | 126 | imperativeTest(price, true); 127 | streamTest(price, true); 128 | parallelStreamTest(price, true); 129 | } 130 | } 131 | 132 | private static void test2() { 133 | 134 | final BigDecimal targetPrice = new BigDecimal("40"); 135 | 136 | parallelStreamTest(targetPrice, false); 137 | imperativeTest(targetPrice, false); 138 | streamTest(targetPrice, false); 139 | 140 | System.out.println("\n\n================================================================\nTest2 Starts!"); 141 | for (int i = 0; i < 5; i++) { 142 | BigDecimal price = targetPrices[targetPriceRandom.nextInt(3)]; 143 | 144 | parallelStreamTest(price, true); 145 | imperativeTest(price, true); 146 | streamTest(price, true); 147 | } 148 | } 149 | 150 | private static void test3() { 151 | 152 | final BigDecimal targetPrice = new BigDecimal("40"); 153 | 154 | streamTest(targetPrice, false); 155 | parallelStreamTest(targetPrice, false); 156 | imperativeTest(targetPrice, false); 157 | 158 | System.out.println("\n\n================================================================\nTest3 Starts!"); 159 | for (int i = 0; i < 5; i++) { 160 | BigDecimal price = targetPrices[targetPriceRandom.nextInt(3)]; 161 | 162 | streamTest(price, true); 163 | parallelStreamTest(price, true); 164 | imperativeTest(price, true); 165 | } 166 | } 167 | 168 | } 169 | 170 | @AllArgsConstructor 171 | @Data 172 | class Product { 173 | private Long id; 174 | private String name; 175 | private BigDecimal price; 176 | } 177 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e09_closure/ClosureExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e09_closure; 2 | 3 | /** 4 | * @author Kevin Lee 5 | * @since 2015-09-13 6 | */ 7 | public class ClosureExamples { 8 | private int number = 999; 9 | 10 | public static void main(String[] args) { 11 | new ClosureExamples().test3(); 12 | } 13 | 14 | 15 | private void test() { 16 | int number = 100; 17 | 18 | testClosure("Anonymous Class", new Runnable() { 19 | @Override 20 | public void run() { 21 | System.out.println(number); 22 | } 23 | }); 24 | 25 | testClosure("Lambda Expression", () -> System.out.println(number)); 26 | 27 | } 28 | private void test1() { 29 | int number = 100; 30 | 31 | testClosure("Anonymous Class", new Runnable() { 32 | @Override 33 | public void run() { 34 | System.out.println(ClosureExamples.this.number); 35 | } 36 | }); 37 | 38 | testClosure("Lambda Expression", () -> System.out.println(this.number)); 39 | 40 | } 41 | 42 | private void test2() { 43 | 44 | testClosure("Anonymous Class", new Runnable() { 45 | @Override 46 | public void run() { 47 | System.out.println("this.toString(): " + this.toString()); 48 | } 49 | }); 50 | 51 | testClosure("Anonymous Class", new Runnable() { 52 | @Override 53 | public void run() { 54 | System.out.println("ClosureExamples.this.toString(): " + ClosureExamples.this.toString()); 55 | } 56 | }); 57 | 58 | testClosure("Lambda Expression", () -> System.out.println("this.toString(): " + this.toString())); 59 | } 60 | 61 | private void test3() { 62 | 63 | System.out.println("\"ClosureExamples calling toString()\": " + toString()); 64 | System.out.println("\"ClosureExamples calling toString(int, String)\": " + toString(1, "Hello")); 65 | 66 | testClosure("Anonymous Class", new Runnable() { 67 | @Override 68 | public void run() { 69 | // System.out.println("toString(int, String): " + toString(1, "Test")); 70 | System.out.println("toString(int, String) causes compile-time error"); 71 | System.out.println("ClosureExamples.this.toString(int, String): " + ClosureExamples.toString(1, "Test")); 72 | } 73 | }); 74 | testClosure("Anonymous Class", new Runnable() { 75 | @Override 76 | public void run() { 77 | // System.out.println("toString(int): " + toString(1)); 78 | System.out.println("toString(int) causes compile-time error"); 79 | System.out.println("ClosureExamples.this.toString(int, String): " + ClosureExamples.this.toString(1)); 80 | } 81 | }); 82 | 83 | testClosure("Lambda Expression", () -> System.out.println("this.toString(int, String): " + this.toString(1, "Test"))); 84 | testClosure("Lambda Expression", () -> System.out.println("toString(int, String): " + toString(1, "Test"))); 85 | testClosure("Lambda Expression", () -> System.out.println("this.toString(int): " + this.toString(1))); 86 | testClosure("Lambda Expression", () -> System.out.println("toString(int): " + toString(1))); 87 | } 88 | 89 | private void test4() { 90 | 91 | int number = 100; 92 | 93 | testClosure("Anonymous Class", new Runnable() { 94 | @Override 95 | public void run() { 96 | int number = 50; // no compile-time error 97 | System.out.println(number); 98 | } 99 | }); 100 | 101 | testClosure("Lambda Expression", () -> { 102 | // int number = 50; // compile-time error 103 | System.out.println(number); 104 | }); 105 | 106 | } 107 | 108 | private static void testClosure(final String name, final Runnable runnable) { 109 | System.out.println("==================================="); 110 | System.out.println(name + ": "); 111 | runnable.run(); 112 | System.out.println("==================================="); 113 | } 114 | 115 | 116 | @Override 117 | public String toString() { 118 | return new StringBuilder("ClosureExamples{") 119 | .append("number=") 120 | .append(number) 121 | .append('}') 122 | .toString(); 123 | } 124 | 125 | public String toString(int number) { 126 | return "#" + number; 127 | } 128 | 129 | public static String toString(int number, T value) { 130 | return "[" + number + "] The value is " + String.valueOf(value) + "."; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/e09_closure/ClosureExamples2.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e09_closure; 2 | 3 | /** 4 | * @author Kevin Lee 5 | * @since 2015-09-13 6 | */ 7 | public class ClosureExamples2 { 8 | private int number = 999; 9 | 10 | public static void main(String[] args) { 11 | new ClosureExamples2().test(); 12 | } 13 | 14 | private void test() { 15 | // int number = 100; 16 | 17 | Runnable runnable = new Runnable() { 18 | @Override 19 | public void run() { 20 | System.out.println(number); 21 | } 22 | }; 23 | runnable.run(); 24 | 25 | Runnable runnable1 = () -> System.out.println(number); 26 | runnable1.run(); 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/ep10_higher_order_function/HigherOrderFunctionExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.ep10_higher_order_function; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.function.Function; 7 | 8 | import static java.util.stream.Collectors.toList; 9 | 10 | /** 11 | * @author Kevin Lee 12 | * @since 2015-10-25 13 | */ 14 | public class HigherOrderFunctionExamples { 15 | public static void main(String[] args) { 16 | 17 | final Function, String> f = g -> g.apply(10); 18 | System.out.println( 19 | f.apply(i -> "#" + i) // "#10" 20 | ); 21 | 22 | final Function> f2 = i -> i2 -> i + i2; 23 | System.out.println( 24 | f2.apply(1).apply(9) // 10 25 | ); 26 | 27 | final List list = Arrays.asList(1, 2, 3, 4, 5); 28 | final List mappedList = map(list, i -> "#" + i); 29 | System.out.println( 30 | mappedList 31 | ); 32 | 33 | System.out.println( 34 | list.stream() 35 | .filter(i -> i > 2) 36 | .map(i -> "#" + i) 37 | .collect(toList()) 38 | ); 39 | 40 | 41 | // Function.identity() 42 | 43 | Function>> f3 = 44 | i1 -> i2 -> i3 -> i1 + i2 + i3; 45 | 46 | System.out.println( 47 | "f3.apply(1).apply(2).apply(3) = " + f3.apply(1).apply(2).apply(3) 48 | ); 49 | 50 | final Function> plus10 = f3.apply(10); 51 | System.out.println( 52 | "plus10.apply(1).apply(1) = " + plus10.apply(1).apply(1) 53 | ); 54 | 55 | } 56 | 57 | private static List map(List list, Function mapper) { 58 | final List result = new ArrayList<>(); 59 | for (final T t : list) { 60 | result.add(mapper.apply(t)); 61 | } 62 | return result; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/ep11_method_reference/MethodReferenceExamples.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.ep11_method_reference; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.function.Function; 7 | 8 | import static java.util.stream.Collectors.toList; 9 | 10 | /** 11 | * @author Kevin Lee 12 | * @since 2015-11-01 13 | */ 14 | public class MethodReferenceExamples { 15 | public static void main(String[] args) { 16 | Arrays.asList(1, 2, 3, 4, 5) 17 | .forEach(System.out::println); 18 | // .forEach(i -> System.out.println(i)); 19 | 20 | System.out.println( 21 | Arrays.asList(new BigDecimal("10.0"), new BigDecimal("23"), new BigDecimal("5")) 22 | .stream() 23 | .sorted(BigDecimalUtil::compare) 24 | // .sorted((bd1, bd2) -> bd1.compareTo(bd2)) 25 | .collect(toList()) 26 | ); 27 | 28 | System.out.println( 29 | Arrays.asList(new BigDecimal("10.0"), new BigDecimal("23"), new BigDecimal("5")) 30 | .stream() 31 | .sorted(BigDecimal::compareTo) 32 | // .sorted((bd1, bd2) -> bd1.compareTo(bd2)) 33 | .collect(toList()) 34 | ); 35 | 36 | 37 | System.out.println("\nThe following three cases have the same result."); 38 | System.out.println("----------------------------------------------------"); 39 | final List abcdList = Arrays.asList("a", "b", "c", "d"); 40 | final String targetString = "c"; 41 | System.out.println("list: " + abcdList); 42 | System.out.println("targetString: \"c\""); 43 | System.out.println("\nanyMatch(targetString::equals)\n" + 44 | abcdList 45 | .stream() 46 | .anyMatch(targetString::equals) 47 | ); 48 | System.out.println("\nanyMatch(\"c\"::equals)\n" + 49 | abcdList 50 | .stream() 51 | .anyMatch("c"::equals) 52 | ); 53 | System.out.println("\nanyMatch(x -> x.equals(\"c\"))\n" + 54 | abcdList 55 | .stream() 56 | .anyMatch(x -> x.equals("c")) 57 | ); 58 | 59 | System.out.println("\n========================================="); 60 | System.out.println("methodReference03();"); 61 | System.out.println("-----------------------------------------"); 62 | methodReference03(); 63 | } 64 | 65 | private static void methodReference03() { 66 | /* First Class Function */ 67 | /** 68 | * A function can be passed as a parameter to another function. 69 | */ 70 | /* Using Lambda Expression 71 | */ 72 | System.out.println(testFirstClassFunction1(3, i -> String.valueOf(i * 2))); 73 | /* 74 | * Using Method Reference 75 | */ 76 | System.out.println(testFirstClassFunction1(3, MethodReferenceExamples::doubleThenToString)); 77 | 78 | /** 79 | * A function can be returned as the result of another function. 80 | */ 81 | /* 82 | * Using Lambda Expression 83 | */ 84 | final Function fl = getDoubleThenToStringUsingLambdaExpression(); 85 | final String resultFromFl = fl.apply(3); 86 | System.out.println(resultFromFl); 87 | /* 88 | * Using Method Reference 89 | */ 90 | final Function fmr = getDoubleThenToStringUsingMethodReference(); 91 | final String resultFromFmr = fmr.apply(3); 92 | System.out.println(resultFromFmr); 93 | 94 | System.out.println("\n-----------------------------------------"); 95 | /** 96 | * A function can be stored in the data structure. 97 | */ 98 | /* 99 | * Using Lambda Expression 100 | */ 101 | final List> fsL = Arrays.asList(i -> String.valueOf(i * 2)); 102 | // Eclipse에 버그가 있는지 바로 윗줄의 코드가 정상 컴파일 되지 않는거 같습니다 만약 그럴 경우 아래 코드를 이용해 주세요. 103 | // 하지만 바로 윗줄 코드는 정상적인 코드입니다. Eclipse 버그 인거 같아요. 104 | // final List> fsL = Arrays.>asList(i -> String.valueOf(i * 2)); 105 | 106 | for (final Function f : fsL) { 107 | final String result = f.apply(3); 108 | System.out.println(result); 109 | } 110 | /* 111 | * Using Method Reference 112 | */ 113 | final List> fsMr = Arrays.asList(MethodReferenceExamples::doubleThenToString); 114 | for (final Function f : fsMr) { 115 | final String result = f.apply(3); 116 | System.out.println(result); 117 | } 118 | 119 | System.out.println("\n-----------------------------------------"); 120 | /* 121 | * Using Lambda Expression 122 | */ 123 | final Function fl2 = i -> String.valueOf(i * 2); 124 | final String resultFl2 = fl2.apply(5); 125 | System.out.println(resultFl2); 126 | 127 | /* 128 | * Method Reference 129 | */ 130 | final Function fmr2 = MethodReferenceExamples::doubleThenToString; 131 | final String resultFmr2 = fmr2.apply(5); 132 | System.out.println(resultFmr2); 133 | 134 | System.out.println("\n-----------------------------------------"); 135 | /* 136 | * Both Lambda Expression and Method Reference 137 | */ 138 | final List> fsBoth = 139 | Arrays.asList( 140 | i -> String.valueOf(i * 2), 141 | MethodReferenceExamples::doubleThenToString, 142 | MethodReferenceExamples::addHashPrefix 143 | ); 144 | 145 | for (final Function f : fsBoth) { 146 | final String result = f.apply(7); 147 | System.out.println(result); 148 | } 149 | } 150 | 151 | private static String doubleThenToString(int i) { 152 | return String.valueOf(i * 2); 153 | } 154 | 155 | private static String addHashPrefix(int number) { 156 | return "#" + number; 157 | } 158 | 159 | private static String testFirstClassFunction1(int n, Function f) { 160 | return "The result is " + f.apply(n) + "."; 161 | } 162 | 163 | private static Function getDoubleThenToStringUsingLambdaExpression() { 164 | return i -> String.valueOf(i * 2); 165 | } 166 | 167 | public static Function getDoubleThenToStringUsingMethodReference() { 168 | return MethodReferenceExamples::doubleThenToString; 169 | } 170 | } 171 | 172 | class BigDecimalUtil { 173 | public static int compare(BigDecimal bd1, BigDecimal bd2) { 174 | return bd1.compareTo(bd2); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/ep11_method_reference/MethodReferenceExamples2Constructor.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.ep11_method_reference; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.function.Function; 8 | 9 | /** 10 | * @author Kevin Lee 11 | * @since 2016-01-17 12 | */ 13 | public class MethodReferenceExamples2Constructor { 14 | public static void main(String[] args) { 15 | final Section section1 = new Section(1); 16 | 17 | final Function sectionFactoryWithLambdaExpression = number -> new Section(number); 18 | final Section section1WithLambdaExpression = sectionFactoryWithLambdaExpression.apply(1); 19 | 20 | final Function sectionFactoryWithMethodReference = Section::new; 21 | final Section section1WithMethodReference = sectionFactoryWithMethodReference.apply(1); 22 | 23 | System.out.println(section1); 24 | System.out.println(section1WithLambdaExpression); 25 | System.out.println(section1WithMethodReference); 26 | 27 | System.out.println("==================================\n"); 28 | 29 | final OldProduct product = new OldProduct(1L, "A", new BigDecimal("100")); 30 | System.out.println(product); 31 | 32 | final OldProductCreator productCreator = OldProduct::new; 33 | System.out.println(productCreator.create(1L, "A", new BigDecimal("100"))); 34 | 35 | System.out.println("==================================\n"); 36 | final ProductA a = createProduct(1L, "A", new BigDecimal("123"), ProductA::new); 37 | final ProductB b = createProduct(2L, "B", new BigDecimal("111"), ProductB::new); 38 | final ProductC c = createProduct(3L, "C", new BigDecimal("10"), ProductC::new); 39 | 40 | System.out.println(a); 41 | System.out.println(b); 42 | System.out.println(c); 43 | } 44 | 45 | private static T createProduct(final Long id, 46 | final String name, 47 | final BigDecimal price, 48 | final ProductCreator productCreator) { 49 | if (id == null || id < 1L) { 50 | throw new IllegalArgumentException("The id must be a positive Long."); 51 | } 52 | if (name == null || name.isEmpty()) { 53 | throw new IllegalArgumentException("The name is not given."); 54 | } 55 | if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) { // price <= ZERO 56 | throw new IllegalArgumentException("The price must be greater then 0."); 57 | } 58 | return productCreator.create(id, name, price); 59 | } 60 | } 61 | 62 | 63 | @FunctionalInterface 64 | interface OldProductCreator { 65 | OldProduct create(Long id, String name, BigDecimal price); 66 | } 67 | 68 | @FunctionalInterface 69 | interface ProductCreator { 70 | T create(Long id, String name, BigDecimal price); 71 | } 72 | 73 | @AllArgsConstructor 74 | @Data 75 | class Section { 76 | private int number; 77 | } 78 | 79 | @AllArgsConstructor 80 | @Data 81 | class OldProduct { 82 | private Long id; 83 | private String name; 84 | private BigDecimal price; 85 | } 86 | 87 | @AllArgsConstructor 88 | @Data 89 | abstract class Product { 90 | private Long id; 91 | private String name; 92 | private BigDecimal price; 93 | } 94 | 95 | class ProductA extends Product { 96 | 97 | public ProductA(final Long id, final String name, final BigDecimal price) { 98 | super(id, name, price); 99 | } 100 | 101 | @Override 102 | public String toString() { 103 | return "A=" + super.toString(); 104 | } 105 | } 106 | 107 | class ProductB extends Product { 108 | 109 | public ProductB(final Long id, final String name, final BigDecimal price) { 110 | super(id, name, price); 111 | } 112 | 113 | @Override 114 | public String toString() { 115 | return "B=" + super.toString(); 116 | } 117 | } 118 | 119 | class ProductC extends Product { 120 | 121 | public ProductC(final Long id, final String name, final BigDecimal price) { 122 | super(id, name, price); 123 | } 124 | 125 | @Override 126 | public String toString() { 127 | return "C=" + super.toString(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/cc/kevinlee/modernjava/ep11_method_reference/MethodReferenceExamples3Array.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.ep11_method_reference; 2 | 3 | import java.lang.reflect.Array; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.function.Function; 7 | import java.util.function.IntFunction; 8 | import java.util.stream.Stream; 9 | 10 | import static java.util.stream.Collectors.toList; 11 | 12 | /** 13 | * @author Kevin Lee 14 | * @since 2016-01-17 15 | */ 16 | public class MethodReferenceExamples3Array { 17 | public static void main(String[] args) { 18 | final String[] array = new String[5]; 19 | System.out.println(array.length); 20 | 21 | final Function arrayFactoryLe = i -> new String[i]; 22 | final String[] arrayCreatedByLambdaExpression = arrayFactoryLe.apply(7); 23 | System.out.println(arrayCreatedByLambdaExpression.length); 24 | 25 | final Function arrayFactoryMr = String[]::new; 26 | final String[] arrayCreatedByMethodReference = arrayFactoryMr.apply(10); 27 | System.out.println(arrayCreatedByMethodReference.length); 28 | 29 | final IntFunction arrayFactoryMr2 = String[]::new; 30 | final String[] arrayCreatedByMethodReference2 = arrayFactoryMr2.apply(11); 31 | System.out.println(arrayCreatedByMethodReference2.length); 32 | 33 | final Integer[] integers = Stream.of(1, 2, 3, 4, 5) 34 | .map(i -> i * 2) 35 | .toArray(Integer[]::new); 36 | System.out.println(Arrays.toString(integers)); 37 | 38 | final String[] strings = Stream.of("A", "B", "C") 39 | .toArray(String[]::new); 40 | // .toArray(i -> new String[i]); 41 | System.out.println(Arrays.toString(strings)); 42 | 43 | final List integers2 = Arrays.asList(1, 2, 3, 4, 5); 44 | 45 | final Integer[] integerArray2 = integers2.toArray(new Integer[0]); 46 | System.out.println(Arrays.toString(integerArray2)); 47 | 48 | // final String[] stringArray2 = integers2.toArray(new String[0]); // no compile-time error 49 | // System.out.println(Arrays.toString(stringArray2)); // runtime error 50 | 51 | // final List ss = integers2.stream().collect(toList()); // compile-time error 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/cc/kevinlee/modernjava/e01/CalculatorServiceTest.java: -------------------------------------------------------------------------------- 1 | package cc.kevinlee.modernjava.e01; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.assertj.core.api.Assertions.*; 6 | 7 | /** 8 | * @author Kevin Lee 9 | * @since 2015-08-02 10 | */ 11 | public class CalculatorServiceTest { 12 | 13 | @Test 14 | public void testCalculateAddition() throws Exception { 15 | final Calculation calculation = (i1, i2) -> i1 + i2; 16 | 17 | final int actual = calculation.calculate(1, 1); 18 | 19 | assertThat(actual).isEqualTo(2); 20 | } 21 | 22 | @Test 23 | public void testCalculateSubtraction() throws Exception { 24 | final Calculation calculation = new Subtraction(); 25 | 26 | final int actual = calculation.calculate(1, 1); 27 | 28 | assertThat(actual).isEqualTo(0); 29 | } 30 | 31 | @Test 32 | public void testCalculateMultiplication() throws Exception { 33 | final Calculation calculation = new Multiplication(); 34 | 35 | final int actual = calculation.calculate(1, 1); 36 | 37 | assertThat(actual).isEqualTo(1); 38 | } 39 | 40 | @Test 41 | public void testCalculateDivision() throws Exception { 42 | final Calculation calculation = new Division(); 43 | 44 | final int actual = calculation.calculate(8, 0); 45 | 46 | assertThat(actual).isEqualTo(2); 47 | } 48 | 49 | } 50 | --------------------------------------------------------------------------------