├── .gitignore ├── README.md ├── license.txt ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── nurkiewicz │ │ ├── java8 │ │ ├── FutureOps.java │ │ ├── MultiRunner.java │ │ ├── RandomSource.java │ │ ├── agent │ │ │ ├── Agent.java │ │ │ └── AsyncAgent.java │ │ ├── atomic │ │ │ ├── BigDecimalAccumulator.java │ │ │ ├── EventCounter.java │ │ │ ├── RangeCollector.java │ │ │ └── SafeCalculator.java │ │ ├── defmethods │ │ │ ├── Engine.java │ │ │ ├── Job.java │ │ │ ├── Lifecycle.java │ │ │ └── RuleEngine.java │ │ ├── holidays │ │ │ ├── AmericanHolidays.java │ │ │ ├── Easter.java │ │ │ ├── Holidays.java │ │ │ ├── HolidaysFactory.java │ │ │ └── PolishHolidays.java │ │ ├── interfaces │ │ │ ├── Encrypter.java │ │ │ ├── ReverseEncrypter.java │ │ │ ├── RotEncrypter.java │ │ │ └── XorEncrypter.java │ │ ├── people │ │ │ ├── Person.java │ │ │ ├── PersonDao.java │ │ │ ├── PersonService.java │ │ │ ├── Phone.java │ │ │ └── Sex.java │ │ ├── stackoverflow │ │ │ ├── ArtificialSleepWrapper.java │ │ │ ├── FallbackStubClient.java │ │ │ ├── HttpStackOverflowClient.java │ │ │ ├── InjectErrorsWrapper.java │ │ │ ├── LoadFromStackOverflowTask.java │ │ │ ├── LoggingWrapper.java │ │ │ ├── Question.java │ │ │ └── StackOverflowClient.java │ │ └── util │ │ │ ├── LoremIpsum.java │ │ │ └── PrimeUtil.java │ │ └── rxjava │ │ ├── ObservableOps.java │ │ └── util │ │ └── Indexed.java └── resources │ ├── clojure-questions.html │ ├── groovy-questions.html │ ├── java-questions.html │ ├── lorem-ipsum.txt │ ├── people.csv │ └── scala-questions.html └── test └── java └── com └── nurkiewicz ├── java8 ├── J01_HelloWorldTest.java ├── J02_InterfacesTest.java ├── J02b_ConflictingDefaultMethodsTest.java ├── J03_FunctionTest.java ├── J04_FunctionalInterfacesTest.java ├── J05_MultiRunnerTest.java ├── J06_OptionalTest.java ├── J07_StreamsTest.java ├── J07b_StreamReduceTest.java ├── J07c_StreamInfiniteTest.java ├── J07d_CustomCollectorTest.java ├── J08_FilesTest.java ├── J08_LocalDateTest.java ├── J08_NewMapMethodsTest.java ├── J09_CollectorsTest.java ├── J09_StringsTest.java ├── J10_ParallelStreamsTest.java ├── J11_AtomicTest.java ├── J11b_AtomicTest.java ├── J11c_AtomicTest.java ├── J12_BigDecimalAccumulatorTest.java ├── J13_AsyncAgentTest.java ├── J21_FuturesIntroductionTest.java ├── J22_CreatingTest.java ├── J23_MapTest.java ├── J24_FlatMapTest.java ├── J25_ZipTest.java ├── J26_AllAnyTest.java ├── J27_PromisesTest.java ├── J28_CustomFutureOperatorsTest.java ├── J29_AsyncAgentFuturesTest.java ├── J60_CovarianceTest.java ├── holidays │ ├── EasterTest.java │ ├── HolidaysFactoryTest.java │ └── PolishHolidaysTest.java └── util │ └── AbstractFuturesTest.java └── rxjava ├── R41_IntroductionTest.java ├── R42_CreatingTest.java ├── R43_ListeningTest.java ├── R45_FilteringTest.java ├── R46_ComposingTest.java ├── R47_IndexingTest.java ├── R48_CompletableFutureAndObservable.java ├── R49_TransformingTest.java ├── R50_OperatorsTest.java ├── R51_InfiniteObservableTest.java ├── util └── HeartBeat.java └── weather ├── Weather.java ├── WeatherStation.java └── WeatherStationStub.java /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *.iml 3 | .idea 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java 8 and RxJava workshop driven by tests 2 | 3 | ## Smoke testing 4 | 5 | ### Maven 6 | 7 | Run `mvn clean test` to make sure you have JDK 8 and all dependencies in place. 8 | 9 | ### IDE 10 | 11 | Run `J01_HelloWorldTest.java` from your favourite IDE and make sure it compiles and passes. 12 | 13 | ## Troubleshooting 14 | 15 | ### Error `invalid target release: 1.8` during maven build 16 | 17 | If you see this error message during maven build: 18 | 19 | [INFO] BUILD FAILURE 20 | ... 21 | [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project java8: 22 | Fatal error compiling: invalid target release: 1.8 -> [Help 1] 23 | 24 | it means you are not compiling using Java 8. Download JDK 8 and let maven use it: 25 | 26 | $ export JAVA_HOME=/path/to/jdk8 27 | 28 | ## License 29 | This project is released under version 2.0 of the [Apache License](http://www.apache.org/licenses/LICENSE-2.0). 30 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | Java 8 workshop 5 | com.nurkiewicz 6 | java8 7 | 0.0.1-SNAPSHOT 8 | 9 | 10 | Apache License, Version 2.0 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | 14 | 15 | 16 | UTF-8 17 | 18 | 19 | 20 | 21 | 22 | 23 | com.google.guava 24 | guava 25 | 16.0 26 | 27 | 28 | commons-io 29 | commons-io 30 | 2.4 31 | 32 | 33 | com.netflix.rxjava 34 | rxjava-core 35 | 0.18.1 36 | 37 | 38 | 39 | 40 | ch.qos.logback 41 | logback-classic 42 | 1.0.13 43 | 44 | 45 | org.slf4j 46 | jul-to-slf4j 47 | 1.7.5 48 | 49 | 50 | org.slf4j 51 | log4j-over-slf4j 52 | 1.7.5 53 | 54 | 55 | org.slf4j 56 | jcl-over-slf4j 57 | 1.7.5 58 | 59 | 60 | commons-logging 61 | commons-logging 62 | 1.1.3 63 | provided 64 | 65 | 66 | javax.jms 67 | javax.jms-api 68 | 2.0 69 | 70 | 71 | org.jsoup 72 | jsoup 73 | 1.7.3 74 | 75 | 76 | org.springframework 77 | spring-web 78 | 3.2.4.RELEASE 79 | 80 | 81 | 82 | 83 | junit 84 | junit 85 | 4.11 86 | test 87 | 88 | 89 | org.easytesting 90 | fest-assert-core 91 | 2.0M9 92 | test 93 | 94 | 95 | pl.pragmatists 96 | JUnitParams 97 | 1.0.3 98 | test 99 | 100 | 101 | org.mockito 102 | mockito-all 103 | 1.9.5 104 | 105 | 106 | com.jayway.awaitility 107 | awaitility 108 | 1.6.0 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | maven-compiler-plugin 117 | 3.1 118 | 119 | 1.8 120 | 1.8 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/FutureOps.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import java.time.Duration; 4 | import java.util.List; 5 | import java.util.concurrent.CompletableFuture; 6 | import java.util.concurrent.Future; 7 | import java.util.concurrent.TimeoutException; 8 | 9 | public class FutureOps { 10 | 11 | public static CompletableFuture failed(Throwable t) { 12 | final CompletableFuture future = new CompletableFuture(); 13 | future.completeExceptionally(t); 14 | return future; 15 | } 16 | 17 | public static CompletableFuture never() { 18 | throw new UnsupportedOperationException("never()"); 19 | } 20 | 21 | /** 22 | * Fails with {@link TimeoutException} after given time 23 | */ 24 | public static CompletableFuture timeoutAfter(Duration duration) { 25 | throw new UnsupportedOperationException("timeoutAfter()"); 26 | } 27 | 28 | /** 29 | * Should not block but return {@link CompletableFuture} immediately. 30 | */ 31 | public static CompletableFuture toCompletable(Future future) { 32 | throw new UnsupportedOperationException("toCompletable()"); 33 | } 34 | 35 | /** 36 | * Filters out futures that failed. Preserves order of input, no matter what was the completion order 37 | */ 38 | public static CompletableFuture> ignoreFailures(List> futures) { 39 | throw new UnsupportedOperationException("ignoreFailures()"); 40 | } 41 | 42 | /** 43 | * Takes a {@link CompletableFuture} and returns compatible future, but that completes with delay. 44 | * E.g. if underlying future completes after 7 seconds, and we call this method with 2 seconds duration, 45 | * resulting future will complete after 9 seconds. 46 | * @return {@link CompletableFuture} which completes after underlying future with given duration 47 | */ 48 | public static CompletableFuture delay(CompletableFuture future, Duration duration) { 49 | throw new UnsupportedOperationException("delay()"); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/MultiRunner.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.ThreadFactory; 8 | 9 | /** 10 | * Uses dirty static methods on purpose, so that it's easier to use during testing. 11 | */ 12 | public class MultiRunner { 13 | 14 | public static final int THREAD_COUNT = 20; 15 | 16 | private static final ExecutorService POOL = Executors.newFixedThreadPool(THREAD_COUNT, threadFactory()); 17 | 18 | private static ThreadFactory threadFactory() { 19 | return new ThreadFactoryBuilder() 20 | .setDaemon(true) 21 | .setNameFormat("Multi-%d") 22 | .build(); 23 | } 24 | 25 | public static void runMultiThreaded(Runnable block) { 26 | runMultiThreaded(1, block); 27 | } 28 | 29 | /** 30 | * Runs blocks given number of times. 31 | * Equivalent to replicating block number of times into Iterable and passing to {@link #runMultiThreaded(Iterable)} 32 | * 33 | * @param times How many times to execute it 34 | * @param block Code to execute 35 | */ 36 | public static void runMultiThreaded(int times, Runnable block) { 37 | throw new UnsupportedOperationException("runMultiThreaded()"); 38 | } 39 | 40 | /** 41 | * Runs all given blocks of code, possibly multi-threaded 42 | * 43 | * @param blocks Blocks of code to execute in a thread pool, each one only once 44 | */ 45 | public static void runMultiThreaded(Iterable blocks) { 46 | throw new UnsupportedOperationException("runMultiThreaded()"); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/RandomSource.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | @FunctionalInterface 4 | interface RandomSource { 5 | 6 | int oneOrMinusOne(); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/agent/Agent.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.agent; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.function.Predicate; 5 | import java.util.function.UnaryOperator; 6 | 7 | /** 8 | * A wrapper around any object that asynchronously serializes all modifications one after another. 9 | * Agent guarantees that at any given time only one transformation is happening. 10 | * I.e. if two threads send modification at the same time, they are applied sequentially, in another thread. 11 | * Value inside agent is replaced by the result of transformation. However you might as well mutate such object and return it. 12 | * 13 | * @param Type of underlying value, must be immutable. 14 | * @see Clojure agents 15 | */ 16 | public interface Agent { 17 | 18 | T get(); 19 | 20 | /** 21 | * Changes the underlying value of agent asynchronously. 22 | * Supplied function will be executed later in another thread. 23 | * 24 | * @param transformFun Function that will be executed against current value. 25 | * Its outcome will replace current value. 26 | */ 27 | void send(UnaryOperator transformFun); 28 | 29 | CompletableFuture sendAndGet(UnaryOperator transformFun); 30 | 31 | /** 32 | * Returns value after all already sent operations were processed. 33 | * Result of this method will see changes made by all prior modifications. 34 | * 35 | * @return Future that completes when all previous tasks complete. 36 | */ 37 | CompletableFuture getAsync(); 38 | 39 | CompletableFuture completeIf(Predicate predicate); 40 | 41 | static Agent create(T initial) { 42 | return new AsyncAgent<>(initial); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/agent/AsyncAgent.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.agent; 2 | 3 | import java.util.concurrent.CompletableFuture; 4 | import java.util.function.Predicate; 5 | import java.util.function.UnaryOperator; 6 | 7 | public class AsyncAgent implements Agent { 8 | 9 | public AsyncAgent() { 10 | } 11 | 12 | public AsyncAgent(T initial) { 13 | } 14 | 15 | @Override 16 | public T get() { 17 | throw new UnsupportedOperationException("get()"); 18 | } 19 | 20 | @Override 21 | public void send(UnaryOperator transformFun) { 22 | throw new UnsupportedOperationException("send()"); 23 | } 24 | 25 | @Override 26 | public CompletableFuture sendAndGet(UnaryOperator transformFun) { 27 | throw new UnsupportedOperationException("sendAndGet()"); 28 | } 29 | 30 | @Override 31 | public CompletableFuture getAsync() { 32 | throw new UnsupportedOperationException("getAsync()"); 33 | } 34 | 35 | @Override 36 | public CompletableFuture completeIf(Predicate predicate) { 37 | throw new UnsupportedOperationException("completeIf()"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/atomic/BigDecimalAccumulator.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.atomic; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.function.BinaryOperator; 5 | 6 | public class BigDecimalAccumulator { 7 | 8 | private final BinaryOperator accFun; 9 | 10 | public BigDecimalAccumulator(BigDecimal initialValue, BinaryOperator accFun) { 11 | this(initialValue, accFun, availCpuMin4()); 12 | } 13 | 14 | public BigDecimalAccumulator(BigDecimal initialValue, BinaryOperator accFun, int concurrency) { 15 | this.accFun = accFun; 16 | } 17 | 18 | private static int availCpuMin4() { 19 | return Math.max(Runtime.getRuntime().availableProcessors(), 4); 20 | } 21 | 22 | public BigDecimal get() { 23 | throw new UnsupportedOperationException("get()"); 24 | } 25 | 26 | public void accumulate(BigDecimal value) { 27 | throw new UnsupportedOperationException("accumulate()"); 28 | } 29 | 30 | public void reset() { 31 | throw new UnsupportedOperationException("reset()"); 32 | } 33 | 34 | public BigDecimal getAndReset() { 35 | throw new UnsupportedOperationException("getAndReset()"); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/atomic/EventCounter.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.atomic; 2 | 3 | public class EventCounter extends Number { 4 | 5 | public long incBy(long x) { 6 | throw new UnsupportedOperationException("incBy()"); 7 | } 8 | 9 | public long reset() { 10 | throw new UnsupportedOperationException("reset()"); 11 | } 12 | 13 | @Override 14 | public int intValue() { 15 | throw new UnsupportedOperationException("intValue()"); 16 | } 17 | 18 | @Override 19 | public long longValue() { 20 | throw new UnsupportedOperationException("longValue()"); 21 | } 22 | 23 | @Override 24 | public float floatValue() { 25 | throw new UnsupportedOperationException("floatValue()"); 26 | } 27 | 28 | @Override 29 | public double doubleValue() { 30 | throw new UnsupportedOperationException("doubleValue()"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/atomic/RangeCollector.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.atomic; 2 | 3 | public class RangeCollector { 4 | 5 | public void save(double x) { 6 | throw new UnsupportedOperationException("save()"); 7 | } 8 | 9 | public double getMin() { 10 | throw new UnsupportedOperationException("getMin()"); 11 | } 12 | 13 | public double getMax() { 14 | throw new UnsupportedOperationException("getMax()"); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/atomic/SafeCalculator.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.atomic; 2 | 3 | public class SafeCalculator extends Number { 4 | 5 | /** 6 | * Sets new value 7 | * @return Previous value 8 | */ 9 | public int set(int x) { 10 | throw new UnsupportedOperationException("reset()"); 11 | } 12 | 13 | public int mul(int x) { 14 | throw new UnsupportedOperationException("inc()"); 15 | } 16 | 17 | public int div(int x) { 18 | throw new UnsupportedOperationException("div()"); 19 | } 20 | 21 | public int add(int x) { 22 | throw new UnsupportedOperationException("add()"); 23 | } 24 | 25 | public int sub(int x) { 26 | throw new UnsupportedOperationException("sub()"); 27 | } 28 | 29 | @Override 30 | public int intValue() { 31 | throw new UnsupportedOperationException("intValue()"); 32 | } 33 | 34 | @Override 35 | public long longValue() { 36 | throw new UnsupportedOperationException("longValue()"); 37 | } 38 | 39 | @Override 40 | public float floatValue() { 41 | throw new UnsupportedOperationException("floatValue()"); 42 | } 43 | 44 | @Override 45 | public double doubleValue() { 46 | throw new UnsupportedOperationException("doubleValue()"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/defmethods/Engine.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.defmethods; 2 | 3 | public interface Engine { 4 | 5 | /** 6 | * Do not TOUCH! 7 | */ 8 | default String start() { 9 | return "Engine"; 10 | } 11 | 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/defmethods/Job.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.defmethods; 2 | 3 | 4 | public interface Job { 5 | 6 | /** 7 | * Do not TOUCH! 8 | */ 9 | default String start() { 10 | return "Job"; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/defmethods/Lifecycle.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.defmethods; 2 | 3 | public interface Lifecycle { 4 | 5 | /** 6 | * Do not TOUCH! 7 | */ 8 | default String start() { 9 | return "Lifecycle"; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/defmethods/RuleEngine.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.defmethods; 2 | 3 | public class RuleEngine { 4 | 5 | public String start() { 6 | return "RuleEngine"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/holidays/AmericanHolidays.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import java.time.DayOfWeek; 4 | import java.time.LocalDate; 5 | 6 | public class AmericanHolidays implements Holidays { 7 | @Override 8 | public boolean isHoliday(LocalDate date) { 9 | return date.getDayOfWeek() == DayOfWeek.SATURDAY || 10 | date.getDayOfWeek() == DayOfWeek.SUNDAY; 11 | } 12 | 13 | @Override 14 | public boolean isWorkingDay(LocalDate date) { 15 | return !isHoliday(date); 16 | } 17 | 18 | @Override 19 | public LocalDate nextHolidayAfter(LocalDate date) { 20 | LocalDate cur = date; 21 | do { 22 | cur = cur.plusDays(1); 23 | } while (isWorkingDay(cur)); 24 | return cur; 25 | } 26 | 27 | @Override 28 | public LocalDate nextWorkingDayAfter(LocalDate date) { 29 | LocalDate cur = date; 30 | do { 31 | cur = cur.plusDays(1); 32 | } while (isHoliday(cur)); 33 | return cur; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/holidays/Easter.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import java.time.LocalDate; 4 | import java.time.Year; 5 | 6 | class Easter { 7 | 8 | static LocalDate sundayFor(Year year) { 9 | final int y = year.getValue(); 10 | final int a = y % 19; 11 | final int b = y / 100; 12 | final int c = y % 100; 13 | final int d = b / 4; 14 | final int e = b % 4; 15 | final int f = (b + 8) / 25; 16 | final int g = (b - f + 1) / 3; 17 | final int h = (19 * a + b - d - g + 15) % 30; 18 | final int i = c / 4; 19 | final int k = c % 4; 20 | final int m = (32 + 2 * e + 2 * i - h - k) % 7; 21 | final int n = (a + 11 * h + 22 * m) / 451; 22 | final int month = (h + m - 7 * n + 114) / 31; 23 | final int day = (((h + m - (7 * n) + 114) % 31) + 1); 24 | return LocalDate.of(y, month, day); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/holidays/Holidays.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import java.time.LocalDate; 4 | 5 | public interface Holidays { 6 | 7 | boolean isHoliday(LocalDate date); 8 | 9 | /** 10 | * Complementary to {@link #isHoliday(LocalDate)}. 11 | * @return !{@link #isHoliday(LocalDate)} 12 | */ 13 | boolean isWorkingDay(LocalDate date); 14 | 15 | LocalDate nextHolidayAfter(LocalDate date); 16 | 17 | LocalDate nextWorkingDayAfter(LocalDate date); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/holidays/HolidaysFactory.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import java.util.Locale; 4 | 5 | public class HolidaysFactory { 6 | 7 | public static Holidays of(Locale locale) { 8 | switch (locale.getCountry()) { 9 | case "PL": 10 | return new PolishHolidays(); 11 | case "US": 12 | return new AmericanHolidays(); 13 | default: 14 | throw new IllegalArgumentException("Unsupported: " + locale.getCountry()); 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/holidays/PolishHolidays.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | 5 | import java.time.DayOfWeek; 6 | import java.time.LocalDate; 7 | import java.time.MonthDay; 8 | import java.time.Year; 9 | import java.util.Set; 10 | 11 | import static java.time.Month.AUGUST; 12 | import static java.time.Month.DECEMBER; 13 | import static java.time.Month.JANUARY; 14 | import static java.time.Month.MAY; 15 | import static java.time.Month.NOVEMBER; 16 | 17 | public class PolishHolidays implements Holidays { 18 | 19 | private static final Set FIXED_HOLIDAYS = ImmutableSet.of( 20 | MonthDay.of(JANUARY, 1), 21 | MonthDay.of(JANUARY, 6), 22 | MonthDay.of(MAY, 1), 23 | MonthDay.of(MAY, 3), 24 | MonthDay.of(AUGUST, 15), 25 | MonthDay.of(NOVEMBER, 1), 26 | MonthDay.of(NOVEMBER, 11), 27 | MonthDay.of(DECEMBER, 25), 28 | MonthDay.of(DECEMBER, 26) 29 | ); 30 | 31 | public boolean isHoliday(LocalDate date) { 32 | return isWeekend(date) || 33 | isFixedHoliday(date) || 34 | isEasterMonday(date) || 35 | isCorpusChristi(date); 36 | } 37 | 38 | private boolean isWeekend(LocalDate date) { 39 | return date.getDayOfWeek() == DayOfWeek.SATURDAY || 40 | date.getDayOfWeek() == DayOfWeek.SUNDAY; 41 | } 42 | 43 | private boolean isFixedHoliday(LocalDate date) { 44 | return FIXED_HOLIDAYS.contains(MonthDay.from(date)); 45 | } 46 | 47 | private boolean isEasterMonday(LocalDate date) { 48 | LocalDate easterThatYear = Easter.sundayFor(Year.of(date.getYear())); 49 | return date.equals(easterThatYear.plusDays(1)); 50 | } 51 | 52 | private boolean isCorpusChristi(LocalDate date) { 53 | LocalDate easterThatYear = Easter.sundayFor(Year.of(date.getYear())); 54 | return date.equals(easterThatYear.plusDays(60)); 55 | } 56 | 57 | @Override 58 | public boolean isWorkingDay(LocalDate date) { 59 | return !isHoliday(date); 60 | } 61 | 62 | @Override 63 | public LocalDate nextHolidayAfter(LocalDate date) { 64 | LocalDate cur = date; 65 | do { 66 | cur = cur.plusDays(1); 67 | } while(isWorkingDay(cur)); 68 | return cur; 69 | } 70 | 71 | @Override 72 | public LocalDate nextWorkingDayAfter(LocalDate date) { 73 | LocalDate cur = date; 74 | do { 75 | cur = cur.plusDays(1); 76 | } while(isHoliday(cur)); 77 | return cur; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/interfaces/Encrypter.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.interfaces; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.Reader; 6 | import java.nio.charset.Charset; 7 | 8 | public interface Encrypter { 9 | byte[] encode(byte[] bytes); 10 | 11 | byte[] encode(String str, Charset charset); 12 | 13 | byte[] encode(char[] chars, Charset charset); 14 | 15 | byte[] encode(Reader reader, Charset charset) throws IOException; 16 | 17 | byte[] encode(InputStream is) throws IOException; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/interfaces/ReverseEncrypter.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.interfaces; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.Reader; 8 | import java.nio.charset.Charset; 9 | 10 | public class ReverseEncrypter implements Encrypter { 11 | 12 | @Override 13 | public byte[] encode(byte[] bytes) { 14 | final byte[] result = new byte[bytes.length]; 15 | for (int i = 0; i < bytes.length; ++i) { 16 | result[i] = (byte) (0xFF - bytes[i]); 17 | } 18 | return result; 19 | } 20 | 21 | @Override 22 | public byte[] encode(String str, Charset charset) { 23 | return encode(str.getBytes(charset)); 24 | } 25 | 26 | @Override 27 | public byte[] encode(char[] chars, Charset charset) { 28 | return encode(String.valueOf(chars), charset); 29 | } 30 | 31 | @Override 32 | public byte[] encode(Reader reader, Charset charset) throws IOException { 33 | return encode(IOUtils.toByteArray(reader, charset)); 34 | } 35 | 36 | @Override 37 | public byte[] encode(InputStream is) throws IOException { 38 | return encode(IOUtils.toByteArray(is)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/interfaces/RotEncrypter.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.interfaces; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.Reader; 8 | import java.nio.charset.Charset; 9 | 10 | public class RotEncrypter implements Encrypter { 11 | 12 | @Override 13 | public byte[] encode(byte[] bytes) { 14 | final byte[] result = new byte[bytes.length]; 15 | for (int i = 0; i < bytes.length; ++i) { 16 | result[i] = (byte) (bytes[i] + 13); 17 | } 18 | return result; 19 | } 20 | 21 | @Override 22 | public byte[] encode(String str, Charset charset) { 23 | return encode(str.getBytes(charset)); 24 | } 25 | 26 | @Override 27 | public byte[] encode(char[] chars, Charset charset) { 28 | return encode(String.valueOf(chars), charset); 29 | } 30 | 31 | @Override 32 | public byte[] encode(Reader reader, Charset charset) throws IOException { 33 | return encode(IOUtils.toByteArray(reader, charset)); 34 | } 35 | 36 | @Override 37 | public byte[] encode(InputStream is) throws IOException { 38 | return encode(IOUtils.toByteArray(is)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/interfaces/XorEncrypter.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.interfaces; 2 | 3 | import org.apache.commons.io.IOUtils; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.Reader; 8 | import java.nio.charset.Charset; 9 | 10 | public class XorEncrypter implements Encrypter { 11 | 12 | @Override 13 | public byte[] encode(byte[] bytes) { 14 | final byte[] result = new byte[bytes.length]; 15 | for (int i = 0; i < bytes.length; ++i) { 16 | result[i] = (byte) (bytes[i] ^ 0xCC); 17 | } 18 | return result; 19 | } 20 | 21 | @Override 22 | public byte[] encode(String str, Charset charset) { 23 | return encode(str.getBytes(charset)); 24 | } 25 | 26 | @Override 27 | public byte[] encode(char[] chars, Charset charset) { 28 | return encode(String.valueOf(chars), charset); 29 | } 30 | 31 | @Override 32 | public byte[] encode(Reader reader, Charset charset) throws IOException { 33 | return encode(IOUtils.toByteArray(reader, charset)); 34 | } 35 | 36 | @Override 37 | public byte[] encode(InputStream is) throws IOException { 38 | return encode(IOUtils.toByteArray(is)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/people/Person.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.people; 2 | 3 | import java.time.LocalDate; 4 | import java.util.Arrays; 5 | import java.util.HashSet; 6 | import java.util.Set; 7 | 8 | public class Person { 9 | 10 | private final String name; 11 | private final Sex sex; 12 | private final int weight; 13 | private final int height; 14 | private final LocalDate dateOfBirth; 15 | private final Set phoneNumbers; 16 | 17 | public Person(String name, Sex sex, int weight, int height, LocalDate dateOfBirth, Phone... phoneNumbers) { 18 | this.name = name; 19 | this.sex = sex; 20 | this.weight = weight; 21 | this.height = height; 22 | this.dateOfBirth = dateOfBirth; 23 | this.phoneNumbers = new HashSet<>(Arrays.asList(phoneNumbers)); 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public int getHeight() { 31 | return height; 32 | } 33 | 34 | public LocalDate getDateOfBirth() { 35 | return dateOfBirth; 36 | } 37 | 38 | public Sex getSex() { 39 | return sex; 40 | } 41 | 42 | public int getWeight() { 43 | return weight; 44 | } 45 | 46 | public Set getPhoneNumbers() { 47 | return phoneNumbers; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "Person{name='" + name + '\'' + ", sex=" + sex + ", weight=" + weight + ", height=" + height + ", dateOfBirth=" + dateOfBirth + '}'; 53 | } 54 | 55 | @Override 56 | public boolean equals(Object o) { 57 | if (this == o) return true; 58 | if (o == null || getClass() != o.getClass()) return false; 59 | 60 | Person person = (Person) o; 61 | return height == person.height 62 | && weight == person.weight 63 | && dateOfBirth.equals(person.dateOfBirth) 64 | && name.equals(person.name) 65 | && phoneNumbers.equals(person.phoneNumbers) 66 | && sex == person.sex; 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | int result = name.hashCode(); 72 | result = 31 * result + sex.hashCode(); 73 | result = 31 * result + weight; 74 | result = 31 * result + height; 75 | result = 31 * result + dateOfBirth.hashCode(); 76 | result = 31 * result + phoneNumbers.hashCode(); 77 | return result; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/people/PersonDao.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.people; 2 | 3 | 4 | import java.io.BufferedReader; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.nio.charset.StandardCharsets; 8 | import java.time.LocalDate; 9 | import java.util.List; 10 | 11 | /** 12 | * Loads people from file. Skips header and entries without name 13 | */ 14 | public class PersonDao { 15 | 16 | public List loadPeopleDatabase() { 17 | try (BufferedReader bufferedReader = open("/people.csv")) { 18 | throw new UnsupportedOperationException("loadPeopleDatabase()"); 19 | // return bufferedReader.lines(). 20 | } catch (IOException e) { 21 | throw new RuntimeException(e); 22 | } 23 | } 24 | 25 | private BufferedReader open(String fileName) { 26 | return new BufferedReader( 27 | new InputStreamReader( 28 | getClass().getResourceAsStream(fileName), 29 | StandardCharsets.UTF_8)); 30 | } 31 | 32 | private Person parsePerson(String line) { 33 | final String[] columns = line.split(","); 34 | return new Person( 35 | columns[0], 36 | Sex.valueOf(columns[1]), 37 | Integer.parseInt(columns[3]), 38 | Integer.parseInt(columns[2]), 39 | LocalDate.of( 40 | Integer.parseInt(columns[6]), 41 | Integer.parseInt(columns[5]), 42 | Integer.parseInt(columns[4]) 43 | ) 44 | ); 45 | } 46 | 47 | 48 | } -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/people/PersonService.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.people; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CompletableFuture; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | 8 | public class PersonService implements AutoCloseable { 9 | 10 | private final ExecutorService pool = Executors.newFixedThreadPool(8); 11 | private final PersonDao dao = new PersonDao(); 12 | 13 | public CompletableFuture> loadPeople() { 14 | return CompletableFuture.supplyAsync(dao::loadPeopleDatabase, pool); 15 | } 16 | 17 | public CompletableFuture loadPerson(String name) { 18 | throw new UnsupportedOperationException("Not yet implemented"); 19 | } 20 | 21 | public CompletableFuture calculateRisk(Person person) { 22 | return CompletableFuture.supplyAsync(() -> person.getHeight() / 200.0, pool); 23 | } 24 | 25 | public double bodyMassIndex(Person person) { 26 | return person.getWeight() / (person.getHeight() / 100.0 * person.getHeight() / 100.0); 27 | } 28 | 29 | public CompletableFuture nextUniqueId() { 30 | return CompletableFuture.supplyAsync(() -> 42, pool); 31 | } 32 | 33 | 34 | @Override 35 | public void close() throws Exception { 36 | pool.shutdownNow(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/people/Phone.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.people; 2 | 3 | public class Phone { 4 | 5 | private final int countryCode; 6 | private final long number; 7 | 8 | public Phone(int countryCode, long number) { 9 | this.countryCode = countryCode; 10 | this.number = number; 11 | } 12 | 13 | public int getCountryCode() { 14 | return countryCode; 15 | } 16 | 17 | public long getNumber() { 18 | return number; 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | return "Phone{" + countryCode + " " + number + '}'; 24 | } 25 | 26 | @Override 27 | public boolean equals(Object o) { 28 | if (this == o) return true; 29 | if (o == null || getClass() != o.getClass()) return false; 30 | 31 | Phone phone = (Phone) o; 32 | return countryCode == phone.countryCode && number == phone.number; 33 | 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | int result = countryCode; 39 | result = 31 * result + (int) (number ^ (number >>> 32)); 40 | return result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/people/Sex.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.people; 2 | 3 | public enum Sex { 4 | 5 | MALE, FEMALE 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/ArtificialSleepWrapper.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | import org.jsoup.nodes.Document; 4 | 5 | import java.util.Random; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public class ArtificialSleepWrapper implements StackOverflowClient { 9 | 10 | private static final Random RANDOM = new Random(); 11 | 12 | private final StackOverflowClient target; 13 | 14 | public ArtificialSleepWrapper(StackOverflowClient target) { 15 | this.target = target; 16 | } 17 | 18 | @Override 19 | public String mostRecentQuestionAbout(String tag) { 20 | final long start = System.currentTimeMillis(); 21 | final String result = target.mostRecentQuestionAbout(tag); 22 | artificialSleep(1000 - (System.currentTimeMillis() - start)); 23 | return result; 24 | } 25 | 26 | @Override 27 | public Document mostRecentQuestionsAbout(String tag) { 28 | artificialSleep(1000); 29 | final long start = System.currentTimeMillis(); 30 | final Document result = target.mostRecentQuestionsAbout(tag); 31 | artificialSleep(1000 - (System.currentTimeMillis() - start)); 32 | return result; 33 | } 34 | 35 | protected static void artificialSleep(long expected) { 36 | try { 37 | TimeUnit.MILLISECONDS.sleep((long) (expected + RANDOM.nextGaussian() * expected / 2)); 38 | } catch (InterruptedException e) { 39 | throw new RuntimeException(e); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/FallbackStubClient.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | import com.google.common.base.Throwables; 4 | import org.apache.commons.io.IOUtils; 5 | import org.jsoup.Jsoup; 6 | import org.jsoup.nodes.Document; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.io.IOException; 11 | 12 | public class FallbackStubClient implements StackOverflowClient { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(FallbackStubClient.class); 15 | 16 | private final StackOverflowClient target; 17 | 18 | public FallbackStubClient(StackOverflowClient target) { 19 | this.target = target; 20 | } 21 | 22 | @Override 23 | public String mostRecentQuestionAbout(String tag) { 24 | try { 25 | return target.mostRecentQuestionAbout(tag); 26 | } catch (Exception e) { 27 | log.warn("Problem retrieving tag {}", tag, e); 28 | switch(tag) { 29 | case "java": 30 | return "How to generate xml report with maven depencency?"; 31 | case "scala": 32 | return "Update a timestamp SettingKey in an sbt 0.12 task"; 33 | case "groovy": 34 | return "Reusing Grails variables inside Config.groovy"; 35 | case "clojure": 36 | return "Merge two comma delimited strings in Clojure"; 37 | default: 38 | throw e; 39 | } 40 | } 41 | } 42 | 43 | @Override 44 | public Document mostRecentQuestionsAbout(String tag) { 45 | try { 46 | return target.mostRecentQuestionsAbout(tag); 47 | } catch (Exception e) { 48 | log.warn("Problem retrieving recent question {}", tag, e); 49 | return loadStubHtmlFromDisk(tag); 50 | } 51 | } 52 | 53 | private Document loadStubHtmlFromDisk(String tag) { 54 | try { 55 | final String html = IOUtils.toString(getClass().getResource("/" + tag + "-question.html")); 56 | return Jsoup.parse(html); 57 | } catch (IOException e1) { 58 | throw Throwables.propagate(e1); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/HttpStackOverflowClient.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | import com.google.common.base.Throwables; 4 | import org.jsoup.Jsoup; 5 | import org.jsoup.nodes.Document; 6 | 7 | import java.io.IOException; 8 | 9 | public class HttpStackOverflowClient implements StackOverflowClient { 10 | 11 | @Override 12 | public String mostRecentQuestionAbout(String tag) { 13 | return fetchTitleOnline(tag); 14 | } 15 | 16 | @Override 17 | public Document mostRecentQuestionsAbout(String tag) { 18 | try { 19 | return Jsoup. 20 | connect("http://stackoverflow.com/questions/tagged/" + tag). 21 | get(); 22 | } catch (IOException e) { 23 | throw Throwables.propagate(e); 24 | } 25 | } 26 | 27 | private String fetchTitleOnline(String tag) { 28 | return mostRecentQuestionsAbout(tag).select("a.question-hyperlink").get(0).text(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/InjectErrorsWrapper.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | import org.jsoup.nodes.Document; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.Arrays; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | public class InjectErrorsWrapper implements StackOverflowClient { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(InjectErrorsWrapper.class); 14 | 15 | private final StackOverflowClient target; 16 | private final Set blackList; 17 | 18 | public InjectErrorsWrapper(StackOverflowClient target, String... blackList) { 19 | this.target = target; 20 | this.blackList = new HashSet<>(Arrays.asList(blackList)); 21 | } 22 | 23 | @Override 24 | public String mostRecentQuestionAbout(String tag) { 25 | throwIfBlackListed(tag); 26 | return target.mostRecentQuestionAbout(tag); 27 | } 28 | 29 | @Override 30 | public Document mostRecentQuestionsAbout(String tag) { 31 | throwIfBlackListed(tag); 32 | return target.mostRecentQuestionsAbout(tag); 33 | } 34 | 35 | private void throwIfBlackListed(String tag) { 36 | if (blackList.contains(tag)) { 37 | ArtificialSleepWrapper.artificialSleep(400); 38 | log.warn("About to throw artifical exception due to: {}", tag); 39 | throw new IllegalArgumentException("Unsupported " + tag); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/LoadFromStackOverflowTask.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.concurrent.Callable; 7 | 8 | public class LoadFromStackOverflowTask implements Callable { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(LoadFromStackOverflowTask.class); 11 | 12 | private final StackOverflowClient client; 13 | private final String tag; 14 | 15 | public LoadFromStackOverflowTask(StackOverflowClient client, String tag) { 16 | this.client = client; 17 | this.tag = tag; 18 | } 19 | 20 | @Override 21 | public String call() throws Exception { 22 | return client.mostRecentQuestionAbout(tag); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/LoggingWrapper.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | import com.google.common.base.Joiner; 4 | import com.google.common.base.Splitter; 5 | import com.google.common.collect.Iterables; 6 | import org.jsoup.nodes.Document; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | public class LoggingWrapper implements StackOverflowClient { 11 | 12 | private static final Logger log = LoggerFactory.getLogger(LoggingWrapper.class); 13 | 14 | private final StackOverflowClient target; 15 | 16 | public LoggingWrapper(StackOverflowClient target) { 17 | this.target = target; 18 | } 19 | 20 | @Override 21 | public String mostRecentQuestionAbout(String tag) { 22 | log.debug("Entering mostRecentQuestionAbout({})", tag); 23 | final String title = target.mostRecentQuestionAbout(tag); 24 | log.debug("Leaving mostRecentQuestionAbout({}): {}", tag, title); 25 | return title; 26 | } 27 | 28 | @Override 29 | public Document mostRecentQuestionsAbout(String tag) { 30 | log.debug("Entering mostRecentQuestionsAbout({})", tag); 31 | final Document document = target.mostRecentQuestionsAbout(tag); 32 | if (log.isTraceEnabled()) { 33 | log.trace("Leaving mostRecentQuestionsAbout({}): {}", tag, htmlExcerpt(document)); 34 | } 35 | return document; 36 | } 37 | 38 | private String htmlExcerpt(Document document) { 39 | final String outerHtml = document.outerHtml(); 40 | final Iterable lines = Splitter.onPattern("\r?\n").split(outerHtml); 41 | final Iterable firstLines = Iterables.limit(lines, 4); 42 | final String excerpt = Joiner.on(' ').join(firstLines); 43 | final int remainingBytes = Math.max(outerHtml.length() - excerpt.length(), 0); 44 | return excerpt + " [...and " + remainingBytes + " chars]"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/Question.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | public class Question { 4 | } -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/stackoverflow/StackOverflowClient.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.stackoverflow; 2 | 3 | import org.jsoup.nodes.Document; 4 | 5 | public interface StackOverflowClient { 6 | 7 | String mostRecentQuestionAbout(String tag); 8 | Document mostRecentQuestionsAbout(String tag); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/util/LoremIpsum.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.util; 2 | 3 | import com.google.common.base.Splitter; 4 | import org.apache.commons.io.IOUtils; 5 | 6 | import java.io.IOException; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.function.BiFunction; 10 | import java.util.function.Function; 11 | import java.util.stream.Collectors; 12 | 13 | import static com.google.common.base.CharMatcher.anyOf; 14 | 15 | /** 16 | * @see Map#merge(Object, Object, BiFunction) 17 | * @see Map#computeIfAbsent(Object, Function) 18 | * @see Collectors#groupingBy(Function) 19 | */ 20 | public class LoremIpsum { 21 | 22 | public static String text() throws IOException { 23 | return IOUtils.toString(LoremIpsum.class.getResourceAsStream("/lorem-ipsum.txt")); 24 | } 25 | 26 | /** 27 | * Case insensitive 28 | */ 29 | public static Map wordCount(String text) { 30 | throw new UnsupportedOperationException("wordCount()"); 31 | } 32 | 33 | private static List splitWords(String text) { 34 | return Splitter 35 | .on(anyOf(" .,\n")) 36 | .trimResults() 37 | .omitEmptyStrings() 38 | .splitToList(text); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/java8/util/PrimeUtil.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.util; 2 | 3 | import java.util.function.LongUnaryOperator; 4 | import java.util.stream.LongStream; 5 | 6 | public class PrimeUtil { 7 | 8 | /** 9 | * TODO: Try to implement this without loops and if's 10 | * @see LongStream#iterate(long, LongUnaryOperator) 11 | */ 12 | public static long nextPrimeAfter(long x) { 13 | throw new UnsupportedOperationException("nextPrimeAfter()"); 14 | } 15 | 16 | /** 17 | * TODO: Try to implement this without loops and if's 18 | * @see LongStream#range(long, long) 19 | */ 20 | public static boolean isPrime(long x) { 21 | throw new UnsupportedOperationException("isPrime()"); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/rxjava/ObservableOps.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.nurkiewicz.rxjava.util.Indexed; 4 | import rx.Observable; 5 | 6 | import java.util.List; 7 | import java.util.concurrent.CompletableFuture; 8 | import java.util.function.UnaryOperator; 9 | 10 | public class ObservableOps { 11 | 12 | public static Observable toObservable(CompletableFuture future) { 13 | throw new UnsupportedOperationException("toObservable()"); 14 | } 15 | 16 | /** 17 | * Non-blocking 18 | */ 19 | public static CompletableFuture> toCompletableFuture(Observable observable) { 20 | throw new UnsupportedOperationException("toCompletableFuture()"); 21 | } 22 | 23 | public static Observable iterate(T initialValue, UnaryOperator nextFun) { 24 | throw new UnsupportedOperationException("iterate()"); 25 | } 26 | 27 | public static Observable naturals() { 28 | throw new UnsupportedOperationException("naturals()"); 29 | } 30 | 31 | public static Observable> index(Observable input) { 32 | throw new UnsupportedOperationException("index()"); 33 | } 34 | 35 | public static Observable.Operator, T> withIndex() { 36 | throw new UnsupportedOperationException("withIndex()"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/nurkiewicz/rxjava/util/Indexed.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava.util; 2 | 3 | public class Indexed { 4 | 5 | private final T value; 6 | private final int index; 7 | 8 | public Indexed(T value, int index) { 9 | this.value = value; 10 | this.index = index; 11 | } 12 | 13 | public T getValue() { 14 | return value; 15 | } 16 | 17 | public int getIndex() { 18 | return index; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/lorem-ipsum.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sollicitudin mattis enim. Maecenas tincidunt, leo vitae interdum suscipit, tortor sem faucibus elit, eget rhoncus mauris nulla in enim. Etiam volutpat velit non ligula consequat porta id non odio. Maecenas id nisi et leo tempor aliquet vitae eget quam. Sed a pulvinar turpis. Integer non lacinia dui. Integer aliquet vulputate tortor, eget mollis justo tristique et. Nunc ac tincidunt massa. Maecenas malesuada pharetra vestibulum. Suspendisse vestibulum nisl enim, eget adipiscing massa suscipit aliquet. Integer sit amet lectus blandit, auctor sem blandit, sollicitudin nulla. Suspendisse porta risus eget turpis pretium pulvinar. 2 | In convallis aliquet nibh, et rutrum erat molestie nec. Sed fermentum mattis dolor, eget ullamcorper massa mattis quis. Nullam rutrum tortor vel quam vestibulum, non imperdiet nisl rhoncus. Curabitur posuere massa sit amet scelerisque malesuada. Aenean imperdiet consectetur dui in malesuada. Curabitur nec tincidunt erat. Nam accumsan quis tellus a egestas. Nulla ligula leo, luctus eget sagittis ac, varius a dolor. 3 | In rhoncus magna turpis, et aliquet elit facilisis sit amet. Integer suscipit turpis a nulla imperdiet fermentum. In ultricies quis eros mattis feugiat. Integer vehicula, quam eu semper mattis, nunc augue placerat tortor, sed congue purus metus non turpis. Morbi congue tristique nunc at lacinia. Nullam euismod, lacus non pellentesque iaculis, quam augue dapibus nunc, et condimentum enim magna quis mauris. Mauris imperdiet tellus in dictum aliquet. Mauris congue dolor ut mollis convallis. Integer id consectetur orci. Etiam sed blandit erat. Donec pellentesque augue ac mi sagittis, non accumsan magna viverra. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin lobortis, tortor nec euismod fermentum, nibh ipsum faucibus mauris, ac viverra metus lectus a ipsum. Ut laoreet lectus et nibh sagittis, quis pellentesque quam pellentesque. Mauris nec sem interdum, congue lectus quis, convallis sapien. 4 | Ut vel auctor metus. Duis at enim est. Nulla facilisi. Praesent placerat ligula id nibh fermentum vehicula. Praesent at nibh non enim placerat blandit. Cras eleifend sit amet neque ut cursus. Aenean ac purus mattis mi sollicitudin venenatis eu vehicula felis. Maecenas est velit, elementum sed vulputate nec, feugiat sit amet quam. Cras suscipit luctus ornare. Praesent tristique euismod lectus, eget auctor augue volutpat a. Sed consequat mauris eu massa porta elementum. 5 | Nunc id sem porttitor, adipiscing tellus eget, vestibulum metus. Phasellus sit amet placerat erat. Ut congue metus eget est lobortis adipiscing. Vivamus pharetra nisi id augue bibendum cursus sed eget sapien. Nulla ullamcorper nisi tortor, sit amet semper massa fermentum sed. Nulla eu nisi venenatis, fringilla lacus eget, tincidunt elit. Fusce tristique congue ligula vitae consectetur. Aenean pellentesque venenatis quam eu ornare. Lorem ipsum dolor sit amet, consectetur adipiscing elit. -------------------------------------------------------------------------------- /src/main/resources/people.csv: -------------------------------------------------------------------------------- 1 | #Name,Sex,Height,Weight,BirthDay,Month,Year 2 | Viktoria,FEMALE,174,63,27,8,1986 3 | William,MALE,180,64,26,5,1988 4 | Sofija,FEMALE,169,59,6,5,1984 5 | Onni,MALE,169,48,2,12,1975 6 | Charlie,MALE,179,67,5,8,1976 7 | Mia,FEMALE,185,85,19,4,1983 8 | Sofiya,FEMALE,175,70,20,12,1994 9 | Dylan,MALE,186,72,28,10,1971 10 | Sofia,FEMALE,166,63,23,2,1971 11 | Marie,FEMALE,165,62,19,12,1970 12 | Sofiya,FEMALE,170,66,1,2,1985 13 | Jacob,MALE,167,55,22,6,1963 14 | Luca,MALE,183,80,21,8,1970 15 | Lara,FEMALE,167,55,9,4,1963 16 | Nora,FEMALE,169,54,14,7,1961 17 | Jakub,MALE,174,57,13,6,1987 18 | Georgi,MALE,184,84,21,6,1967 19 | Noah,MALE,180,68,23,1,1977 20 | Nikola,MALE,175,64,15,6,1972 21 | Nareh,FEMALE,167,55,26,10,1981 22 | Lukas,MALE,182,76,25,9,1998 23 | Léa,FEMALE,164,61,9,11,1969 24 | Aron,MALE,183,73,11,12,1971 25 | Noah,MALE,191,83,15,7,1969 26 | Luka,MALE,182,69,12,2,1971 27 | Georgios,MALE,183,73,16,6,1978 28 | Emma,FEMALE,179,60,13,11,1973 29 | Nathan,MALE,174,69,2,1,1970 30 | Daniyar,MALE,183,77,4,6,1976 31 | Sophie,FEMALE,166,60,18,1,1972 32 | Lucas,MALE,168,67,12,5,1985 33 | Francesco,MALE,183,70,25,9,1972 34 | Jack,MALE,180,81,15,6,1970 35 | Yusif,MALE,182,69,7,8,1992 36 | Davit,MALE,185,71,5,11,1982 37 | Rodrigo,MALE,176,52,10,1,1981 38 | Emma,FEMALE,174,60,24,7,1980 39 | Isabella,FEMALE,173,71,1,1,1983 40 | Chloé,FEMALE,178,66,10,4,1976 41 | Alexander,MALE,177,68,24,5,1987 42 | Marija,FEMALE,173,68,17,10,1968 43 | Luka,MALE,167,72,6,5,1992 44 | Harry,MALE,175,64,19,9,1991 45 | Luca,MALE,181,65,24,9,1965 46 | Alexandra,FEMALE,166,52,14,12,1988 47 | Amelia,FEMALE,168,62,8,10,1979 48 | Emma,FEMALE,162,65,7,3,1975 49 | Giorgi,MALE,184,60,15,7,1976 50 | Rasmus,MALE,181,72,15,3,1980 51 | Ellen,FEMALE,176,71,1,12,1966 52 | Sara,FEMALE,168,59,12,6,1978 53 | Uendi,FEMALE,170,66,22,12,1965 54 | Sevinj,FEMALE,183,92,1,11,1978 55 | Chloe,FEMALE,169,59,26,11,1986 56 | Ben,MALE,167,69,23,3,1963 57 | Nino,FEMALE,171,64,21,7,1979 58 | Matthew,MALE,159,55,8,12,1991 59 | Leandro,MALE,177,65,27,7,1985 60 | Jónas,MALE,178,69,16,8,1973 61 | Anna,FEMALE,182,76,9,4,1978 62 | Emilía,FEMALE,179,64,10,8,1972 63 | ,FEMALE,179,64,10,8,1972 64 | Maxim,MALE,177,65,11,5,1986 65 | Sarah,FEMALE,163,66,3,6,1972 66 | Emily,FEMALE,172,73,6,10,1964 67 | Alice,FEMALE,166,52,27,7,1995 68 | Lucía,FEMALE,176,77,19,10,1965 69 | Maria,FEMALE,173,62,18,4,1981 70 | Ivaana,FEMALE,177,62,12,11,1966 71 | Emma,FEMALE,169,54,1,11,1971 72 | Artyom,MALE,176,65,8,2,1966 73 | Maxim,MALE,177,68,17,9,1980 74 | Eliška,FEMALE,169,57,2,3,1994 75 | Sofia,FEMALE,167,50,2,8,1981 76 | Ben,MALE,171,73,15,12,1971 77 | Maria,FEMALE,161,57,12,6,1958 78 | Emma,FEMALE,166,46,13,9,1975 79 | Nathan,MALE,181,72,26,4,1964 80 | Luka,MALE,170,69,15,2,1976 81 | Matas,MALE,182,76,23,7,1976 82 | Markel,MALE,188,77,11,2,1961 83 | Mohamed,MALE,167,55,3,10,1968 84 | Anna,FEMALE,174,69,8,2,1978 85 | Lina,FEMALE,172,62,3,4,1972 86 | Anastasia,FEMALE,162,57,15,10,1974 87 | Daan,MALE,169,59,12,4,1962 88 | Luka,MALE,171,64,14,8,1962 89 | Emma,FEMALE,174,60,8,10,1972 90 | Maria,FEMALE,168,50,28,6,1978 91 | Lamija,FEMALE,163,58,11,10,1992 92 | Anastasia,FEMALE,162,62,11,6,1980 93 | Daniel,MALE,183,80,7,12,1982 94 | Jack,MALE,177,68,2,3,1986 95 | Alexander,MALE,184,84,23,10,1986 96 | Jakub,MALE,173,71,15,2,1985 97 | Emil,MALE,163,55,12,7,1971 98 | Gabriel,MALE,182,72,27,6,1979 99 | Jakub,MALE,184,71,11,11,1981 100 | Andrei,MALE,179,73,2,10,1976 101 | Lara,FEMALE,156,53,26,10,1990 102 | Lucas,MALE,181,62,1,8,1962 103 | Sofia,FEMALE,181,72,9,10,1968 104 | Milan,MALE,186,69,9,2,1946 105 | Lena,FEMALE,164,61,14,1,1975 106 | Alina,FEMALE,168,67,17,9,1972 107 | Annalena,FEMALE,175,61,21,2,1972 108 | Noel,MALE,199,83,27,10,1974 109 | Anna,FEMALE,167,61,4,10,1972 110 | Mathéo,MALE,180,64,22,9,1966 111 | Malik,MALE,175,67,6,8,1967 112 | Gabriel,MALE,175,58,7,8,1977 113 | Léa,FEMALE,163,55,11,6,1968 114 | Artem,MALE,186,76,4,11,1974 115 | ,MALE,186,76,4,11,1974 116 | Victor,MALE,179,73,25,3,1975 117 | Amelia,FEMALE,166,57,16,5,1961 118 | Ane,FEMALE,173,59,14,6,1957 119 | Zahra,FEMALE,167,61,19,4,1979 120 | Sophie,FEMALE,160,51,24,5,1980 121 | Aleksandar,MALE,179,73,6,2,1966 122 | Mia,FEMALE,159,60,25,5,1965 123 | Julia,FEMALE,169,54,25,6,1972 124 | Maria,FEMALE,166,63,1,12,1971 125 | Ali,MALE,177,59,23,3,1974 126 | Julia,FEMALE,173,59,18,4,1978 127 | Emilija,FEMALE,174,75,15,12,1993 128 | Amar,MALE,183,83,20,8,1967 129 | Yanis,MALE,178,82,3,11,1957 130 | Emma,FEMALE,168,59,24,2,1977 131 | Marc,MALE,185,82,10,4,1975 132 | Sofia,FEMALE,169,62,12,2,1953 133 | Lucija,FEMALE,166,66,2,11,1970 134 | Hanna,FEMALE,168,62,26,7,1967 135 | Roberts,MALE,183,66,24,7,1986 136 | Eliza,FEMALE,168,62,15,7,1968 137 | James,MALE,177,75,9,4,1969 138 | Ella,FEMALE,168,59,13,1,1980 139 | Bence,MALE,178,72,28,3,1981 140 | Jack,MALE,177,68,5,6,1989 141 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J01_HelloWorldTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import static java.util.stream.Collectors.toList; 9 | import static org.fest.assertions.api.Assertions.assertThat; 10 | 11 | /** 12 | * - Smoke test, make sure it compiles, runs and passes. 13 | */ 14 | public class J01_HelloWorldTest { 15 | 16 | @Test 17 | public void hello() { 18 | final List input = Arrays.asList(2, 3, 5, 7, 11); 19 | 20 | final List output = input. 21 | stream(). 22 | map(i -> i * 2). 23 | collect(toList()); 24 | 25 | assertThat(output).containsExactly(4, 6, 10, 14, 22); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J02_InterfacesTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.interfaces.Encrypter; 4 | import com.nurkiewicz.java8.interfaces.ReverseEncrypter; 5 | import com.nurkiewicz.java8.interfaces.RotEncrypter; 6 | import com.nurkiewicz.java8.interfaces.XorEncrypter; 7 | import junitparams.JUnitParamsRunner; 8 | import junitparams.Parameters; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | 12 | import java.io.ByteArrayInputStream; 13 | import java.io.IOException; 14 | import java.io.StringReader; 15 | 16 | import static java.nio.charset.StandardCharsets.UTF_8; 17 | import static junitparams.JUnitParamsRunner.$; 18 | import static org.fest.assertions.api.Assertions.assertThat; 19 | 20 | /** 21 | * - Improve encrypter to use default methods to avoid code duplication. 22 | */ 23 | @RunWith(JUnitParamsRunner.class) 24 | public class J02_InterfacesTest { 25 | 26 | @Test 27 | @Parameters 28 | public void testAllMethods(Encrypter encrypter, byte[] expected) throws IOException { 29 | final byte[] input = new byte[]{90, 100, 110}; 30 | final char[] charInput = new char[]{'Z', 'd', 'n'}; 31 | 32 | assertThat(encrypter.encode(input)).isEqualTo(expected); 33 | assertThat(encrypter.encode(new String(input), UTF_8)).isEqualTo(expected); 34 | assertThat(encrypter.encode(charInput, UTF_8)).isEqualTo(expected); 35 | assertThat(encrypter.encode(new StringReader(new String(charInput)), UTF_8)).isEqualTo(expected); 36 | assertThat(encrypter.encode(new ByteArrayInputStream(input))).isEqualTo(expected); 37 | } 38 | 39 | private Object[] parametersForTestAllMethods() { 40 | return $( 41 | $(new ReverseEncrypter(), new byte[]{-91, -101, -111}), 42 | $(new RotEncrypter(), new byte[]{103, 113, 123}), 43 | $(new XorEncrypter(), new byte[]{-106, -88, -94}) 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J02b_ConflictingDefaultMethodsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.defmethods.Engine; 4 | import com.nurkiewicz.java8.defmethods.Job; 5 | import com.nurkiewicz.java8.defmethods.Lifecycle; 6 | import com.nurkiewicz.java8.defmethods.RuleEngine; 7 | import org.junit.Ignore; 8 | import org.junit.Test; 9 | 10 | import static org.fest.assertions.api.Assertions.assertThat; 11 | 12 | /** 13 | * Conflicting default methods 14 | * First let {@link RuleEngine} implement all three interfaces. 15 | * Then decide which of the conflicting implementations should be chosen. 16 | */ 17 | @Ignore 18 | public class J02b_ConflictingDefaultMethodsTest { 19 | 20 | private final RuleEngine ruleEngine = new RuleEngine(); 21 | 22 | @Test 23 | public void shouldExtendFewInterfaces() { 24 | assertThat(ruleEngine).isInstanceOf(Job.class); 25 | assertThat(ruleEngine).isInstanceOf(Engine.class); 26 | assertThat(ruleEngine).isInstanceOf(Lifecycle.class); 27 | } 28 | 29 | @Test 30 | public void shouldReturnValueFromJob() { 31 | assertThat(ruleEngine.start()).isEqualTo("Job"); 32 | } 33 | 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J03_FunctionTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import org.mockito.InOrder; 6 | 7 | import java.util.Date; 8 | import java.util.function.Consumer; 9 | import java.util.function.Function; 10 | import java.util.function.LongConsumer; 11 | import java.util.function.Predicate; 12 | import java.util.function.Supplier; 13 | 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | import static org.fest.assertions.data.Offset.offset; 16 | import static org.mockito.Mockito.inOrder; 17 | import static org.mockito.Mockito.mock; 18 | 19 | /** 20 | * - Use explicit Function, Predicate, Supplier, Consumer (like Guava) 21 | * - Higher order functions - returning lambdas 22 | * - Change Encrypter to class taking Function 23 | * - Turning Function, Supplier and Producer into lambda 24 | * - Method references (method, static method, constructor) 25 | */ 26 | @Ignore 27 | public class J03_FunctionTest { 28 | 29 | @Test 30 | public void shouldPrependHello() { 31 | final Function fun = null; 32 | 33 | assertThat(fun.apply(42)).isEqualTo("Answer is 42"); 34 | } 35 | 36 | @Test 37 | public void shouldProduceAnswer() { 38 | final Supplier answerFun = null; 39 | 40 | assertThat(answerFun.get()).isEqualTo(42); 41 | } 42 | 43 | @Test 44 | public void shouldDecideIfNegative() { 45 | final Predicate isNegative = null; 46 | 47 | assertThat(isNegative.test(3.0)).isFalse(); 48 | assertThat(isNegative.test(0.0)).isFalse(); 49 | assertThat(isNegative.test(-1.1)).isTrue(); 50 | } 51 | 52 | @Test 53 | public void shouldCallOtherClassInConsumer() { 54 | final Date dateMock = mock(Date.class); 55 | 56 | final Consumer consumer = null; 57 | 58 | consumer.accept(1000L); 59 | consumer.accept(2000L); 60 | 61 | final InOrder order = inOrder(dateMock); 62 | order.verify(dateMock).setTime(1000L); 63 | order.verify(dateMock).setTime(2000L); 64 | } 65 | 66 | @Test 67 | public void shouldCallOtherClassInPrimitiveConsumer() { 68 | final Date dateMock = mock(Date.class); 69 | 70 | final LongConsumer consumer = null; 71 | 72 | consumer.accept(1000L); 73 | consumer.accept(2000L); 74 | 75 | final InOrder order = inOrder(dateMock); 76 | order.verify(dateMock).setTime(1000L); 77 | order.verify(dateMock).setTime(2000L); 78 | } 79 | 80 | @Test 81 | public void shouldInvokeReturnedLambdas() throws Exception { 82 | //given 83 | final Function strLenFun = createStringLenFunction(); 84 | final Function tripleFun = multiplyFun(3.0); 85 | final String input = "abcd"; 86 | 87 | //when 88 | final int strLen = strLenFun.apply(input); 89 | final double tripled = tripleFun.apply(4); 90 | 91 | //then 92 | assertThat(strLen).isEqualTo(4); 93 | assertThat(tripled).isEqualTo(4 * 3.0, offset(0.01)); 94 | } 95 | 96 | @Test 97 | public void shouldComposeFunctionsInVariousWays() throws Exception { 98 | //given 99 | final Function strLenFun = createStringLenFunction(); 100 | final Function tripleFun = multiplyFun(3.0); 101 | final Function andThenFun = strLenFun.andThen(tripleFun); 102 | final Function composeFun = tripleFun.compose(strLenFun); 103 | final String input = "abcd"; 104 | 105 | //when 106 | final double naiveResult = tripleFun.apply(strLenFun.apply(input)); 107 | final double andThenResult = andThenFun.apply(input); 108 | final double composeResult = composeFun.apply(input); 109 | 110 | //then 111 | assertThat(naiveResult).isEqualTo(4 * 3.0, offset(0.01)); 112 | assertThat(andThenResult).isEqualTo(4 * 3.0, offset(0.01)); 113 | assertThat(composeResult).isEqualTo(4 * 3.0, offset(0.01)); 114 | } 115 | 116 | private Function multiplyFun(double times) { 117 | throw new UnsupportedOperationException("multiplyFun()"); 118 | } 119 | 120 | private Function createStringLenFunction() { 121 | throw new UnsupportedOperationException("createStringLenFunction()"); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J04_FunctionalInterfacesTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | 6 | import java.awt.event.ActionListener; 7 | import java.util.Comparator; 8 | import java.util.Date; 9 | import java.util.Random; 10 | import java.util.function.Supplier; 11 | 12 | import static org.fest.assertions.api.Assertions.assertThat; 13 | import static org.mockito.Mockito.mock; 14 | import static org.mockito.Mockito.verify; 15 | 16 | /** 17 | * What is a functional interface? @FunctionalInterface 18 | * Using lambdas instead of plain old Java classes (JButton) 19 | * - Implement functional interfaces using lambda syntax 20 | */ 21 | @Ignore 22 | public class J04_FunctionalInterfacesTest { 23 | 24 | private final Random random = new Random(); 25 | 26 | @Test 27 | public void testActionListenerLambda() { 28 | //given 29 | final Date dateMock = mock(Date.class); 30 | final ActionListener listener = null; 31 | 32 | //when 33 | listener.actionPerformed(null); 34 | 35 | //then 36 | verify(dateMock).setTime(1000L); 37 | } 38 | 39 | @Test 40 | public void testRunnableLambda() { 41 | //given 42 | final Date dateMock = mock(Date.class); 43 | Runnable block = null; 44 | 45 | //when 46 | block.run(); 47 | 48 | //then 49 | verify(dateMock).setTime(1000L); 50 | } 51 | 52 | @Test 53 | public void testComparatorLambda() { 54 | final Comparator strLenComparator = null; 55 | 56 | assertThat(strLenComparator.compare("abc", "def")).isZero(); 57 | assertThat(strLenComparator.compare("abc", "defg")).isLessThan(0); 58 | assertThat(strLenComparator.compare("abc", "de")).isGreaterThan(0); 59 | } 60 | 61 | @Test 62 | public void testCustomFunctionalInterface() { 63 | final RandomSource source = null; 64 | 65 | Supplier sourceSupplier = null; 66 | 67 | assertThat(source.oneOrMinusOne()).isIn(-1, 1); 68 | assertThat(sourceSupplier.get()).isIn(-1, 1); 69 | } 70 | 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J05_MultiRunnerTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | 6 | import java.util.Arrays; 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | import java.util.concurrent.atomic.LongAdder; 10 | import java.util.stream.IntStream; 11 | 12 | import static com.jayway.awaitility.Awaitility.await; 13 | import static com.jayway.awaitility.Awaitility.to; 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | import static org.hamcrest.CoreMatchers.is; 16 | 17 | /** 18 | * Implement simple utility methods for running blocks of code in multiple threads 19 | */ 20 | @Ignore 21 | public class J05_MultiRunnerTest { 22 | 23 | @Test 24 | public void shouldExecuteTasksInMultipleThreads() throws Exception { 25 | //given 26 | final Map threads = new ConcurrentHashMap<>(); 27 | 28 | //when 29 | IntStream.range(0, 100).forEach(i -> 30 | MultiRunner.runMultiThreaded(() -> { 31 | final Thread thread = Thread.currentThread(); 32 | threads.put(thread.getId(), thread.getName()); 33 | }) 34 | ); 35 | 36 | //then 37 | await().until(() -> threads.size() == MultiRunner.THREAD_COUNT); 38 | assertThat(threads).doesNotContainKey(Thread.currentThread().getId()); 39 | } 40 | 41 | @Test 42 | public void shouldRunMultipleBlocks() throws Exception { 43 | //given 44 | final LongAdder counter = new LongAdder(); 45 | 46 | //when 47 | MultiRunner.runMultiThreaded(Arrays.asList( 48 | () -> counter.add(1), 49 | () -> counter.add(2), 50 | () -> counter.add(3) 51 | )); 52 | 53 | //then 54 | await().untilCall(to(counter).sum(), is(1L + 2L + 3L)); 55 | } 56 | 57 | @Test 58 | public void shouldRunTheSameTaskMultipleTimes() throws Exception { 59 | //given 60 | final LongAdder counter = new LongAdder(); 61 | 62 | //when 63 | MultiRunner.runMultiThreaded(3, () -> counter.add(7)); 64 | 65 | //then 66 | await().untilCall(to(counter).sum(), is(7L + 7L + 7L)); 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J06_OptionalTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.people.Person; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.time.LocalDate; 8 | import java.time.Month; 9 | import java.util.Optional; 10 | 11 | import static com.nurkiewicz.java8.people.Sex.MALE; 12 | import static org.fest.assertions.api.Assertions.assertThat; 13 | 14 | /** 15 | * Transform old-fashioned code using nulls with Optional 16 | * Hint: use map/filter/flatMap/ifPresent 17 | */ 18 | @Ignore 19 | public class J06_OptionalTest { 20 | 21 | private static final int PERSON_ID_WITH_NO_ADDRESS = 1; 22 | private static final int PERSON_ID_WITH_ADDRESS = 2; 23 | private static final int UNAVAILABLE_PERSON_ID = 0; 24 | 25 | private Person findPersonOrNull(int id) { 26 | switch(id) { 27 | case PERSON_ID_WITH_NO_ADDRESS: 28 | return new Person("James", MALE, 62, 169, LocalDate.of(2007, Month.DECEMBER, 21)); 29 | case PERSON_ID_WITH_ADDRESS: 30 | return new Person("John", MALE, 62, 169, LocalDate.of(1985, Month.DECEMBER, 21)); 31 | case UNAVAILABLE_PERSON_ID: 32 | return null; 33 | default: 34 | return null; 35 | } 36 | } 37 | 38 | private String lookupAddressOrNull(Person person) { 39 | if (person.getDateOfBirth().isAfter(LocalDate.of(2000, Month.JANUARY, 1))) { 40 | return ""; 41 | } 42 | if (person.getDateOfBirth().isAfter(LocalDate.of(1980, Month.JANUARY, 1))) { 43 | return " Some St. "; 44 | } 45 | return null; 46 | } 47 | 48 | private String lookupAddressByIdOrNull(int id) { 49 | final Person personOrNull = findPersonOrNull(id); 50 | if (personOrNull != null) { 51 | if (personOrNull.getSex() == MALE) { 52 | final String addressOrNull = lookupAddressOrNull(personOrNull); 53 | if (addressOrNull != null && !addressOrNull.isEmpty()) { 54 | return addressOrNull.trim(); 55 | } else { 56 | return null; 57 | } 58 | } 59 | } 60 | return null; 61 | } 62 | 63 | /** 64 | * Don't change, call from {@link #tryLookupAddressById(int)} 65 | */ 66 | private Optional tryFindPerson(int id) { 67 | return Optional.ofNullable(findPersonOrNull(id)); 68 | } 69 | 70 | /** 71 | * Don't change, call from {@link #tryLookupAddressById(int)} 72 | */ 73 | private Optional tryLookupAddress(Person person) { 74 | return Optional.ofNullable(lookupAddressOrNull(person)); 75 | } 76 | 77 | /** 78 | * TODO: Copy and refactor code from {@link #lookupAddressByIdOrNull}, but avoid nulls 79 | */ 80 | private Optional tryLookupAddressById(int id) { 81 | return Optional.empty(); // tryFindPerson(id). 82 | } 83 | 84 | @Test 85 | public void nulls() { 86 | assertThat(lookupAddressByIdOrNull(UNAVAILABLE_PERSON_ID)).isNull(); 87 | assertThat(lookupAddressByIdOrNull(PERSON_ID_WITH_NO_ADDRESS)).isNull(); 88 | assertThat(lookupAddressByIdOrNull(PERSON_ID_WITH_ADDRESS)).isEqualTo("Some St."); 89 | } 90 | 91 | @Test 92 | public void optionals() { 93 | assertThat(tryLookupAddressById(UNAVAILABLE_PERSON_ID).isPresent()).isFalse(); 94 | assertThat(tryLookupAddressById(PERSON_ID_WITH_NO_ADDRESS).isPresent()).isFalse(); 95 | assertThat(tryLookupAddressById(PERSON_ID_WITH_ADDRESS).get()).isEqualTo("Some St."); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J07_StreamsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.people.Person; 4 | import com.nurkiewicz.java8.people.Phone; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.time.LocalDate; 9 | import java.time.Month; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.Iterator; 13 | import java.util.List; 14 | import java.util.Optional; 15 | import java.util.function.Consumer; 16 | 17 | import static com.nurkiewicz.java8.people.Sex.FEMALE; 18 | import static com.nurkiewicz.java8.people.Sex.MALE; 19 | import static java.util.Collections.emptyList; 20 | import static java.util.stream.Collectors.toList; 21 | import static org.fest.assertions.api.Assertions.assertThat; 22 | 23 | /** 24 | * - What is Stream 25 | * - More complex operations on Stream, (map, filter, forEach, sorted) 26 | * - Only toList() Collector 27 | */ 28 | @Ignore 29 | public class J07_StreamsTest { 30 | 31 | public static final List PEOPLE = Arrays.asList( 32 | new Person("Jane", FEMALE, 62, 169, LocalDate.of(1986, Month.DECEMBER, 21), new Phone(10, 555100200)), 33 | new Person("Bob", MALE, 71, 183, LocalDate.of(1982, Month.FEBRUARY, 5), new Phone(10, 555100201)), 34 | new Person("Steve", MALE, 85, 191, LocalDate.of(1980, Month.MAY, 4), new Phone(11, 555100200), new Phone(11, 555100201), new Phone(11, 555100202)), 35 | new Person("Alice", FEMALE, 54, 178, LocalDate.of(1984, Month.AUGUST, 17), new Phone(12, 555100202)), 36 | new Person("Eve", FEMALE, 61, 176, LocalDate.of(1987, Month.FEBRUARY, 9), new Phone(10, 555100200)) 37 | ); 38 | 39 | @Test 40 | public void doesAnyFemaleExist() { 41 | final boolean anyFemale = PEOPLE. 42 | stream(). 43 | anyMatch(p -> p.getSex() == FEMALE); 44 | 45 | assertThat(anyFemale).isTrue(); 46 | } 47 | 48 | @Test 49 | public void shouldReturnNamesSorted() { 50 | final List names = PEOPLE. 51 | stream(). 52 | map(Person::getName). 53 | sorted(). 54 | collect(toList()); 55 | 56 | assertThat(names).containsExactly("Alice", "Bob", "Eve", "Jane", "Steve"); 57 | } 58 | 59 | /** 60 | * Are all people below 80 kg? 61 | */ 62 | @Test 63 | public void areAllPeopleSlim() { 64 | final boolean allSlim = true; // PEOPLE.stream().allMatch() 65 | 66 | assertThat(allSlim).isFalse(); 67 | } 68 | 69 | /** 70 | * Are all people above 80 kg? 71 | */ 72 | @Test 73 | public void areAllPeopleNotSlim() { 74 | final boolean allNotSlim = true; 75 | 76 | assertThat(allNotSlim).isFalse(); 77 | } 78 | 79 | @Test 80 | public void findTallestPerson() { 81 | final Optional max = Optional.empty(); 82 | 83 | assertThat(max.isPresent()).isTrue(); 84 | assertThat(max.get()).isEqualTo(PEOPLE.get(2)); 85 | } 86 | 87 | @Test 88 | public void countMales() { 89 | final long malesCount = 0; 90 | 91 | assertThat(malesCount).isEqualTo(2); 92 | } 93 | 94 | /** 95 | * Hint: use limit(2) 96 | */ 97 | @Test 98 | public void twoOldestPeople() { 99 | final List oldest = emptyList(); 100 | 101 | assertThat(oldest).containsExactly(PEOPLE.get(2), PEOPLE.get(1)); 102 | } 103 | 104 | /** 105 | * Hint: PEOPLE.stream()...mapToInt()...sum() 106 | */ 107 | @Test 108 | public void totalWeight() { 109 | final int totalWeight = 0; 110 | 111 | assertThat(totalWeight).isEqualTo(333); 112 | } 113 | 114 | @Test 115 | public void findUniqueCountryCodes() { 116 | final List distinctCountryCodes = emptyList(); // PEOPLE.stream()...flatMap()...distinct() 117 | 118 | assertThat(distinctCountryCodes).containsExactly(10, 11, 12); 119 | } 120 | 121 | /** 122 | * For each person born after LocalDate.of(1985, Month.DECEMBER, 25), add name to 'names' 123 | */ 124 | @Test 125 | public void forEachYoungPerson() { 126 | List names = new ArrayList<>(); 127 | 128 | // PEOPLE.stream()...forEach() 129 | 130 | assertThat(names).containsExactly("Jane", "Eve"); 131 | } 132 | 133 | /** 134 | * @see Iterator#forEachRemaining(Consumer) 135 | */ 136 | @Test 137 | public void shouldRunOverIterator() throws Exception { 138 | //given 139 | final Iterator iter = Arrays.asList(1, 2, 3).iterator(); 140 | final StringBuilder sb = new StringBuilder(); 141 | 142 | //when 143 | //use iter... here 144 | 145 | //then 146 | assertThat(sb.toString()).isEqualToIgnoringCase("123"); 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J07b_StreamReduceTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | import static org.fest.assertions.api.Assertions.assertThat; 10 | 11 | @Ignore 12 | public class J07b_StreamReduceTest { 13 | 14 | @Test 15 | public void shouldAddNumbersUsingReduce() throws Exception { 16 | //given 17 | final List input = Arrays.asList(2, 3, 5, 7); 18 | 19 | //when 20 | final int sum = input.stream().reduce(0, (acc, x) -> acc + x); 21 | 22 | //then 23 | assertThat(sum).isEqualTo(2 + 3 + 5 + 7); 24 | } 25 | 26 | @Test 27 | public void shouldConcatNumbers() throws Exception { 28 | //given 29 | final List input = Arrays.asList(2, 3, 5, 7); 30 | 31 | //when 32 | final String result = input 33 | .stream() 34 | .reduce( 35 | new StringBuilder(), 36 | (acc, x) -> acc.append(x), 37 | (sb1, sb2) -> sb1.append(sb2)) 38 | .toString(); 39 | 40 | //then 41 | assertThat(result).isEqualToIgnoringCase("2357"); 42 | } 43 | 44 | @Test 45 | public void shouldFindMaxUsingReduce() throws Exception { 46 | //given 47 | final List input = Arrays.asList(4, 2, 6, 3, 8, 1); 48 | 49 | //when 50 | final int max = 0; //input.stream()... 51 | 52 | //then 53 | assertThat(max).isEqualTo(8); 54 | } 55 | 56 | @Test 57 | public void shouldSimulateMapUsingReduce() throws Exception { 58 | //given 59 | final List input = Arrays.asList(2, 3, 5, 7); 60 | 61 | //when 62 | final List doubledPrimes = null; //input.stream()... 63 | 64 | //then 65 | assertThat(doubledPrimes).containsExactly(2 * 2, 3 * 2, 5 * 2, 7 * 2); 66 | } 67 | 68 | @Test 69 | public void shouldSimulateFilterUsingReduce() throws Exception { 70 | //given 71 | final List input = Arrays.asList(2, 3, 4, 5, 6); 72 | 73 | //when 74 | final List onlyEvenNumbers = null; //input.stream()... 75 | 76 | //then 77 | assertThat(onlyEvenNumbers).containsExactly(2, 4, 6); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J07c_StreamInfiniteTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.util.PrimeUtil; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.util.List; 8 | import java.util.stream.LongStream; 9 | import java.util.stream.Stream; 10 | 11 | import static org.fest.assertions.api.Assertions.assertThat; 12 | import static org.fest.assertions.api.Assertions.offset; 13 | 14 | /** 15 | * @see PrimeUtil 16 | */ 17 | @Ignore 18 | public class J07c_StreamInfiniteTest { 19 | 20 | @Test 21 | public void shouldGenerateNaturalNumbersAndSumFirstThousand() throws Exception { 22 | //given 23 | final LongStream naturals = LongStream.iterate(1, x -> x + 1); 24 | 25 | //when 26 | final long sum = naturals.limit(1000).sum(); 27 | 28 | //then 29 | assertThat(sum).isEqualTo(500500); 30 | } 31 | 32 | @Test 33 | public void shouldCheckForPrimes() throws Exception { 34 | assertThat(PrimeUtil.isPrime(2)).isTrue(); 35 | assertThat(PrimeUtil.isPrime(3)).isTrue(); 36 | assertThat(PrimeUtil.isPrime(4)).isFalse(); 37 | assertThat(PrimeUtil.isPrime(5)).isTrue(); 38 | assertThat(PrimeUtil.isPrime(6)).isFalse(); 39 | assertThat(PrimeUtil.isPrime(7)).isTrue(); 40 | assertThat(PrimeUtil.isPrime(8)).isFalse(); 41 | assertThat(PrimeUtil.isPrime(9)).isFalse(); 42 | assertThat(PrimeUtil.isPrime(10)).isFalse(); 43 | assertThat(PrimeUtil.isPrime(11)).isTrue(); 44 | } 45 | 46 | @Test 47 | public void shouldFindNextPrime() throws Exception { 48 | assertThat(PrimeUtil.nextPrimeAfter(2)).isEqualTo(3); 49 | assertThat(PrimeUtil.nextPrimeAfter(3)).isEqualTo(5); 50 | assertThat(PrimeUtil.nextPrimeAfter(4)).isEqualTo(5); 51 | assertThat(PrimeUtil.nextPrimeAfter(5)).isEqualTo(7); 52 | assertThat(PrimeUtil.nextPrimeAfter(6)).isEqualTo(7); 53 | assertThat(PrimeUtil.nextPrimeAfter(7)).isEqualTo(11); 54 | assertThat(PrimeUtil.nextPrimeAfter(8)).isEqualTo(11); 55 | assertThat(PrimeUtil.nextPrimeAfter(9)).isEqualTo(11); 56 | assertThat(PrimeUtil.nextPrimeAfter(10)).isEqualTo(11); 57 | assertThat(PrimeUtil.nextPrimeAfter(11)).isEqualTo(13); 58 | } 59 | 60 | @Test 61 | public void shouldCalculateProductOfFirstFivePrimes() throws Exception { 62 | //given 63 | LongStream primes = LongStream.iterate(2, null); 64 | 65 | //when 66 | final long product = primes.limit(5).reduce(1, (acc, x) -> acc * x); 67 | 68 | //then 69 | assertThat(product).isEqualTo(2 * 3 * 5 * 7 * 11); 70 | } 71 | 72 | @Test 73 | public void shouldGenerateGrowingStrings() throws Exception { 74 | //given 75 | final Stream starStream = Stream.iterate("", null); 76 | 77 | //when 78 | List strings = null; 79 | 80 | //then 81 | assertThat(strings).containsExactly( 82 | "", 83 | "*", 84 | "**", 85 | "***", 86 | "****", 87 | "*****", 88 | "******"); 89 | } 90 | 91 | /** 92 | * This method tries to estimate Pi number by randomly generating points on a 2x2 square. 93 | * Then it calculates what's the distance of each point to the center of the square. 94 | * The proportion of points closer than 1 to all of them approximates Pi. 95 | * The more points you take, better approximation you get. 96 | * @see Wikipedia 97 | */ 98 | @Test 99 | public void shouldEstimatePi() throws Exception { 100 | //given 101 | Stream randomPoints = null; 102 | 103 | //when 104 | final double piDividedByFour = 0; 105 | 106 | //then 107 | assertThat(piDividedByFour * 4).isEqualTo(Math.PI, offset(0.001)); 108 | } 109 | 110 | } 111 | 112 | class Point { 113 | private final double x; 114 | private final double y; 115 | 116 | Point(double x, double y) { 117 | this.x = x; 118 | this.y = y; 119 | } 120 | 121 | public static Point random() { 122 | return new Point(Math.random() * 2 - 1, Math.random() * 2 - 1); 123 | } 124 | 125 | public double distance() { 126 | return Math.sqrt(x * x + y * y); 127 | } 128 | 129 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J07d_CustomCollectorTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.util.Arrays; 8 | import java.util.Collections; 9 | import java.util.List; 10 | import java.util.Set; 11 | import java.util.stream.LongStream; 12 | import java.util.stream.Stream; 13 | 14 | import static java.util.stream.Collectors.toSet; 15 | import static org.fest.assertions.api.Assertions.assertThat; 16 | 17 | /** 18 | * Implement custom Collector to ImmutableSet from Guava 19 | * @see ImmutableSet#builder() 20 | */ 21 | @Ignore 22 | public class J07d_CustomCollectorTest { 23 | 24 | @Test 25 | public void shouldReturnEmptyImmutableSet() throws Exception { 26 | //given 27 | final Set items = Collections.emptySet(); 28 | 29 | //when 30 | final ImmutableSet set = null; //items.stream().collect(new ImmutableSetCollector<>()); 31 | 32 | //then 33 | assertThat(set).isEmpty(); 34 | } 35 | 36 | @Test 37 | public void shouldReturnImmutableSetWithJustOneElement() throws Exception { 38 | //given 39 | final List items = Collections.singletonList(42); 40 | 41 | //when 42 | final ImmutableSet set = null; //items.stream().collect(new ImmutableSetCollector<>()); 43 | 44 | //then 45 | assertThat(set).containsExactly(42); 46 | } 47 | 48 | @Test 49 | public void shouldCollectToImmutableSet() throws Exception { 50 | //given 51 | final List items = Arrays.asList(3, 5, 2, 4, 7, 5, 3, 9, 2); 52 | 53 | //when 54 | final ImmutableSet set = null; //items.stream().collect(new ImmutableSetCollector<>()); 55 | 56 | //then 57 | assertThat(set).containsOnly(2, 3, 4, 5, 7, 9); 58 | } 59 | 60 | @Test 61 | public void shouldWorkInConcurrentEnvironment() throws Exception { 62 | //given 63 | final Stream longsWithDuplicates = LongStream 64 | .range(0, 100_000) 65 | .parallel() 66 | .mapToObj(x -> x / 2); 67 | 68 | //when 69 | final ImmutableSet set = null; //longsWithDuplicates.collect(new ImmutableSetCollector<>()); 70 | 71 | //then 72 | final Set expected = LongStream 73 | .range(0, 100_000 / 2) 74 | .mapToObj(Long::valueOf) 75 | .collect(toSet()); 76 | assertThat(set).isEqualTo(expected); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J08_FilesTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.people.Person; 4 | import com.nurkiewicz.java8.people.PersonDao; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | import java.nio.file.Files; 10 | import java.nio.file.Path; 11 | import java.nio.file.Paths; 12 | import java.util.List; 13 | import java.util.Optional; 14 | import java.util.stream.Stream; 15 | 16 | import static java.util.stream.Collectors.toList; 17 | import static org.fest.assertions.api.Assertions.assertThat; 18 | 19 | /** 20 | * - BufferedReader.lines() 21 | * - Comparator improvements 22 | */ 23 | @Ignore 24 | public class J08_FilesTest { 25 | 26 | private final PersonDao dao = new PersonDao(); 27 | 28 | @Test 29 | public void shouldLoadAllPeople() throws IOException { 30 | final List people = dao.loadPeopleDatabase(); 31 | 32 | assertThat(people).hasSize(137); 33 | } 34 | 35 | @Test 36 | public void shouldSortByName() throws IOException { 37 | final List people = dao.loadPeopleDatabase(); 38 | 39 | final List names = people.stream(). 40 | map(Person::getName). 41 | distinct(). 42 | collect(toList()); 43 | 44 | assertThat(names).startsWith("Aleksandar", "Alexander", "Alexandra", "Ali", "Alice"); 45 | } 46 | 47 | /** 48 | * Hint: Comparator.comparing() 49 | */ 50 | @Test 51 | public void shouldSortFemalesByHeightDesc() throws IOException { 52 | final List people = dao.loadPeopleDatabase(); 53 | 54 | final List names = people.stream() 55 | .map(Person::getName) 56 | .collect(toList()); 57 | 58 | assertThat(names).startsWith("Mia", "Sevinj", "Anna", "Sofia"); 59 | } 60 | 61 | @Test 62 | public void shouldSortByDateOfBirthWhenSameNames() throws IOException { 63 | final List people = dao.loadPeopleDatabase(); 64 | 65 | final List names = people.stream(). 66 | map(p -> p.getName() + '-' + p.getDateOfBirth().getYear()). 67 | collect(toList()); 68 | 69 | assertThat(names).startsWith("Aleksandar-1966", "Alexander-1986", "Alexander-1987", "Alexandra-1988", "Ali-1974"); 70 | } 71 | 72 | /** 73 | * @see Files#list(Path) 74 | * @throws Exception 75 | */ 76 | @Test 77 | public void shouldGenerateStreamOfAllFilesIncludingSubdirectoriesRecursively() throws Exception { 78 | //given 79 | final String fileToSearch = J08_FilesTest.class.getSimpleName() + ".java"; 80 | 81 | //when 82 | final Optional found = filesInDir(Paths.get(".")) 83 | .filter(path -> path.endsWith(fileToSearch)) 84 | .findAny(); 85 | 86 | //then 87 | assertThat(found.isPresent()).isTrue(); 88 | } 89 | 90 | private static Stream filesInDir(Path dir) { 91 | throw new UnsupportedOperationException("filesInDir()"); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J08_LocalDateTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.holidays.Holidays; 4 | import com.nurkiewicz.java8.holidays.PolishHolidays; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.time.LocalDate; 9 | import java.time.LocalTime; 10 | import java.time.Period; 11 | import java.time.ZoneId; 12 | import java.time.ZonedDateTime; 13 | import java.time.temporal.TemporalAdjuster; 14 | import java.time.temporal.TemporalAdjusters; 15 | import java.util.stream.Stream; 16 | 17 | import static java.time.Month.DECEMBER; 18 | import static java.time.Month.MAY; 19 | import static java.time.Month.SEPTEMBER; 20 | import static org.fest.assertions.api.Assertions.assertThat; 21 | 22 | @Ignore 23 | public class J08_LocalDateTest { 24 | 25 | private final Holidays holidays = new PolishHolidays(); 26 | 27 | /** 28 | * Hint: consider iterate(), limit() and filter() 29 | * @throws Exception 30 | */ 31 | @Test 32 | public void shouldCountNumberOfHolidaysIn2014() throws Exception { 33 | //given 34 | final Stream holidaysIn2014 = null; 35 | 36 | //when 37 | final long numberOfHolidays = holidaysIn2014.count(); 38 | 39 | //then 40 | assertThat(numberOfHolidays).isEqualTo(113); 41 | } 42 | 43 | /** 44 | * @see TemporalAdjusters 45 | */ 46 | @Test 47 | public void shouldApplyBuiltIntTemporalAdjuster() throws Exception { 48 | //given 49 | final LocalDate today = LocalDate.of(2014, MAY, 12); 50 | 51 | //when 52 | final LocalDate previousWednesday = today; 53 | 54 | //then 55 | assertThat(previousWednesday).isEqualTo(LocalDate.of(2014, MAY, 7)); 56 | } 57 | 58 | @Test 59 | public void shouldApplyCustomTemporalAdjuster() throws Exception { 60 | //given 61 | final LocalDate today = LocalDate.of(2014, MAY, 12); 62 | 63 | //when 64 | final LocalDate nextHoliday = today.with(nextHoliday()); 65 | 66 | //then 67 | assertThat(nextHoliday).isEqualTo(LocalDate.of(2014, MAY, 17)); 68 | } 69 | 70 | public TemporalAdjuster nextHoliday() { 71 | throw new UnsupportedOperationException("nextHoliday()"); 72 | } 73 | 74 | /** 75 | * - Calculate time after billion seconds from given date 76 | * - What will be the hour in Asia/Tokyo" 77 | * - See how period can be calculated 78 | * @throws Exception 79 | */ 80 | @Test 81 | public void shouldFindWhenIhaveBillionthSecondBirthday() throws Exception { 82 | //given 83 | final LocalDate dateOfBirth = LocalDate.of(1985, DECEMBER, 25); 84 | final LocalTime timeOfBirth = LocalTime.of(22, 10); 85 | final ZonedDateTime birth = ZonedDateTime.of(dateOfBirth, timeOfBirth, ZoneId.of("Europe/Warsaw")); 86 | 87 | //when 88 | final ZonedDateTime billionSecondsLater = birth; 89 | final int hourInTokyo = billionSecondsLater.getHour(); 90 | 91 | //then 92 | final Period periodToBillionth = Period.between( 93 | LocalDate.of(2014, MAY, 12), 94 | billionSecondsLater.toLocalDate()); 95 | assertThat(billionSecondsLater.toLocalDate()).isEqualTo(LocalDate.of(2017, SEPTEMBER, 3)); 96 | assertThat(hourInTokyo).isEqualTo(7); 97 | assertThat(periodToBillionth.getYears()).isEqualTo(3); 98 | assertThat(periodToBillionth.getMonths()).isEqualTo(3); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J08_NewMapMethodsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.util.LoremIpsum; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import static org.fest.assertions.api.Assertions.assertThat; 11 | import static org.fest.assertions.api.Assertions.entry; 12 | 13 | @Ignore 14 | public class J08_NewMapMethodsTest { 15 | 16 | @Test 17 | public void shouldReturnWordCount() throws Exception { 18 | //given 19 | final String loremIpsum = LoremIpsum.text(); 20 | 21 | //when 22 | Map wordCount = LoremIpsum.wordCount(loremIpsum); 23 | 24 | //then 25 | assertThat(wordCount) 26 | .hasSize(140) 27 | .contains( 28 | entry("eget", 12), 29 | entry("sit", 9), 30 | entry("amet", 9), 31 | entry("et", 8) 32 | ); 33 | 34 | assertThat(wordCount.getOrDefault("kot", 0)).isZero(); 35 | } 36 | 37 | @Test 38 | public void shouldReturnTotalWords() throws Exception { 39 | //given 40 | final String loremIpsum = LoremIpsum.text(); 41 | Map wordCount = LoremIpsum.wordCount(loremIpsum); 42 | 43 | //when 44 | int totalWords = 0; //wordCount... 45 | 46 | //then 47 | assertThat(totalWords).isEqualTo(441); 48 | } 49 | 50 | @Test 51 | public void shouldReturnFiveMostCommonWords() throws Exception { 52 | final String loremIpsum = LoremIpsum.text(); 53 | Map wordCount = LoremIpsum.wordCount(loremIpsum); 54 | 55 | //when 56 | final Set fiveMostCommon = null; //wordCount... 57 | 58 | //then 59 | assertThat(fiveMostCommon).containsOnly("eget", "sit", "amet", "et", "sed"); 60 | } 61 | 62 | @Test 63 | public void shouldReturnWordsThatOccurOnlyOnce() throws Exception { 64 | final String loremIpsum = LoremIpsum.text(); 65 | Map wordCount = LoremIpsum.wordCount(loremIpsum); 66 | 67 | //when 68 | final Set uniqueWords = null; //wordCount... 69 | 70 | //then 71 | assertThat(uniqueWords) 72 | .hasSize(37) 73 | .contains("tempor", "laoreet", "netus"); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J09_CollectorsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.people.Person; 4 | import com.nurkiewicz.java8.people.PersonDao; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | import java.util.Collections; 10 | import java.util.IntSummaryStatistics; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | import static org.fest.assertions.data.Offset.offset; 16 | 17 | /** 18 | * Explore different Collectors.* implementations 19 | * - Various collectors, grouping, average, toList, etc. 20 | */ 21 | @Ignore 22 | public class J09_CollectorsTest { 23 | 24 | private final PersonDao dao = new PersonDao(); 25 | 26 | @Test 27 | public void calculateAverageHeight() throws IOException { 28 | final List people = dao.loadPeopleDatabase(); 29 | 30 | final Double averageHeight = 0.0; // people.stream(). 31 | 32 | assertThat(averageHeight).isEqualTo(174, offset(0.5)); 33 | } 34 | 35 | @Test 36 | public void partitionByPeopleAboveAndBelow180CmHeight() throws IOException { 37 | final List people = dao.loadPeopleDatabase(); 38 | 39 | final Map> peopleByHeight = Collections.emptyMap(); // people.stream(). 40 | 41 | final List tallPeople = peopleByHeight.get(true); 42 | assertThat(tallPeople).hasSize(33); 43 | 44 | final List shortPeople = peopleByHeight.get(false); 45 | assertThat(shortPeople).hasSize(104); 46 | } 47 | 48 | @Test 49 | public void groupPeopleByWeight() throws IOException { 50 | final List people = dao.loadPeopleDatabase(); 51 | 52 | final Map> peopleByWeight = Collections.emptyMap(); // people.stream(). 53 | 54 | assertThat(peopleByWeight.get(46)).hasSize(1); 55 | assertThat(peopleByWeight.get(70)).hasSize(2); 56 | assertThat(peopleByWeight.get(92)).hasSize(1); 57 | } 58 | 59 | @Test 60 | public void weightStatistics() throws IOException { 61 | final List people = dao.loadPeopleDatabase(); 62 | 63 | final IntSummaryStatistics stats = new IntSummaryStatistics(); // people.stream(). 64 | 65 | assertThat(stats.getCount()).isEqualTo(137); 66 | assertThat(stats.getMin()).isEqualTo(46); 67 | assertThat(stats.getMax()).isEqualTo(92); 68 | assertThat(stats.getSum()).isEqualTo(8998); 69 | assertThat(stats.getAverage()).isEqualTo(65.8, offset(0.5)); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J09_StringsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | import static org.fest.assertions.api.Assertions.assertThat; 10 | 11 | /** 12 | * Hint: String.chars() 13 | */ 14 | @Ignore 15 | public class J09_StringsTest { 16 | 17 | @Test 18 | public void arrAllCharactersDigits() throws Exception { 19 | assertThat(onlyDigits("+12 345-678 (90)")).isFalse(); 20 | assertThat(onlyDigits("100 200 300")).isFalse(); 21 | assertThat(onlyDigits("1234567890")).isTrue(); 22 | } 23 | 24 | private boolean onlyDigits(String phone) { 25 | return true; 26 | } 27 | 28 | @Test 29 | public void hasAnyNonAlphabeticCharacters() throws Exception { 30 | assertThat(anyNonAlphabetic("abc")).isFalse(); 31 | assertThat(anyNonAlphabetic("CamelCase")).isFalse(); 32 | assertThat(anyNonAlphabetic("_underscore")).isTrue(); 33 | assertThat(anyNonAlphabetic("Big bang!")).isTrue(); 34 | assertThat(anyNonAlphabetic("#%@")).isTrue(); 35 | } 36 | 37 | private boolean anyNonAlphabetic(String s) { 38 | return true; 39 | } 40 | 41 | /** 42 | * Hint: String.join() 43 | */ 44 | @Test 45 | public void shouldJoinMultipleStringsIntoString() throws Exception { 46 | //given 47 | final List ids = Arrays.asList("1", "2", "3", "4"); 48 | 49 | //when 50 | final String joined = ""; 51 | 52 | //then 53 | assertThat(joined).isEqualTo("1, 2, 3, 4"); 54 | } 55 | 56 | @Test 57 | public void shouldJoinMultipleIntsIntoString() throws Exception { 58 | //given 59 | final List ids = Arrays.asList(1, 2, 3, 4); 60 | 61 | //when 62 | final String joined = ""; 63 | 64 | //then 65 | assertThat(joined).isEqualTo("1, 2, 3, 4"); 66 | } 67 | 68 | /** 69 | * Hint: StringJoiner 70 | */ 71 | @Test 72 | public void shouldJoinSeparateStrings() throws Exception { 73 | //given 74 | String x = "X"; 75 | String y = "Y"; 76 | String z = "Z"; 77 | 78 | //when 79 | String joined = ""; 80 | 81 | //then 82 | assertThat(joined).isEqualTo(""); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J10_ParallelStreamsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.people.Person; 4 | import com.nurkiewicz.java8.people.PersonDao; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | import static java.util.stream.Collectors.toList; 12 | import static org.fest.assertions.api.Assertions.assertThat; 13 | 14 | /** 15 | * - run time difference 16 | * - unspecified order 17 | * - commonPool() 18 | */ 19 | @Ignore 20 | public class J10_ParallelStreamsTest { 21 | 22 | private final PersonDao dao = new PersonDao(); 23 | 24 | @Test 25 | public void parallel() throws IOException { 26 | final List veryTallParallel = dao.loadPeopleDatabase() 27 | .parallelStream() 28 | .filter(p -> p.getHeight() > 190) 29 | .collect(toList()); 30 | final List veryTall = dao.loadPeopleDatabase() 31 | .stream() 32 | .filter(p -> p.getHeight() > 190) 33 | .collect(toList()); 34 | 35 | assertThat(veryTallParallel).isEqualTo(veryTall); 36 | } 37 | 38 | 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J11_AtomicTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.atomic.EventCounter; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import static com.jayway.awaitility.Awaitility.await; 8 | import static com.jayway.awaitility.Awaitility.to; 9 | import static org.fest.assertions.api.Assertions.assertThat; 10 | import static org.hamcrest.CoreMatchers.is; 11 | 12 | /** 13 | * *Adder 14 | * *Accumulator 15 | * Atomic* improvements 16 | * - Decide which atomic.* class best suits given requirements 17 | * @see Java Concurrent Counters By Numbers 18 | */ 19 | @Ignore 20 | public class J11_AtomicTest { 21 | 22 | @Test 23 | public void shouldCountMultipleEvents() throws Exception { 24 | //given 25 | final EventCounter counter = new EventCounter(); 26 | 27 | //when 28 | counter.incBy(1); 29 | counter.incBy(3); 30 | counter.incBy(2); 31 | 32 | //then 33 | assertThat(counter.longValue()).isEqualTo(1 + 3 + 2); 34 | } 35 | 36 | @Test 37 | public void shouldResetAndRememberOldValue() throws Exception { 38 | //given 39 | final EventCounter counter = new EventCounter(); 40 | 41 | //when 42 | counter.incBy(1); 43 | counter.incBy(2); 44 | final long last = counter.reset(); 45 | 46 | //then 47 | assertThat(counter.longValue()).isZero(); 48 | assertThat(last).isEqualTo(1 + 2); 49 | } 50 | 51 | @Test 52 | public void shouldCountEventsInMultipleThreads() throws Exception { 53 | //given 54 | final EventCounter counter = new EventCounter(); 55 | 56 | //when 57 | MultiRunner.runMultiThreaded(1000, () -> counter.incBy(1)); 58 | 59 | //then 60 | await().untilCall(to(counter).longValue(), is(1000L)); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J11b_AtomicTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.atomic.RangeCollector; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import static com.jayway.awaitility.Awaitility.await; 8 | import static com.jayway.awaitility.Awaitility.to; 9 | import static org.fest.assertions.api.Assertions.assertThat; 10 | import static org.fest.assertions.api.Assertions.offset; 11 | import static org.hamcrest.Matchers.closeTo; 12 | 13 | /** 14 | * *Adder 15 | * *Accumulator 16 | * Atomic* improvements 17 | * - Decide which atomic.* class best suits given requirements 18 | */ 19 | @Ignore 20 | public class J11b_AtomicTest { 21 | 22 | @Test 23 | public void shouldHaveExtremeRangesInTheBeginning() throws Exception { 24 | //given 25 | final RangeCollector range = new RangeCollector(); 26 | 27 | //when 28 | final double min = range.getMin(); 29 | final double max = range.getMax(); 30 | 31 | //then 32 | assertThat(min).isEqualTo(Double.MAX_VALUE); 33 | assertThat(max).isEqualTo(Double.MIN_VALUE); 34 | } 35 | 36 | @Test 37 | public void shouldCountSingleValueAsBothMinAndMax() throws Exception { 38 | //given 39 | final RangeCollector range = new RangeCollector(); 40 | final int someValue = 42; 41 | 42 | //when 43 | range.save(someValue); 44 | 45 | //then 46 | assertThat(range.getMin()).isEqualTo(someValue, offset(0.1)); 47 | assertThat(range.getMax()).isEqualTo(someValue, offset(0.1)); 48 | } 49 | 50 | @Test 51 | public void shouldRememberMinAndMaxOfMultipleValues() throws Exception { 52 | //given 53 | final RangeCollector range = new RangeCollector(); 54 | 55 | //when 56 | range.save(3); 57 | range.save(1); 58 | range.save(5); 59 | range.save(-1); 60 | range.save(2); 61 | 62 | //then 63 | assertThat(range.getMin()).isEqualTo(-1, offset(0.1)); 64 | assertThat(range.getMax()).isEqualTo(5, offset(0.1)); 65 | } 66 | 67 | @Test 68 | public void shouldRememberMinAndMaxInMultipleThreads() throws Exception { 69 | //given 70 | final RangeCollector range = new RangeCollector(); 71 | 72 | //when 73 | MultiRunner.runMultiThreaded(1000, () -> range.save(randomDigit())); 74 | 75 | //then 76 | await().untilCall(to(range).getMin(), closeTo(0, 0.01)); 77 | await().untilCall(to(range).getMax(), closeTo(9, 0.01)); 78 | } 79 | 80 | private int randomDigit() { 81 | return (int) (Math.random() * 10); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J11c_AtomicTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.atomic.SafeCalculator; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.util.stream.IntStream; 8 | 9 | import static com.jayway.awaitility.Awaitility.await; 10 | import static com.jayway.awaitility.Awaitility.to; 11 | import static org.fest.assertions.api.Assertions.assertThat; 12 | import static org.fest.assertions.api.Assertions.offset; 13 | import static org.hamcrest.Matchers.closeTo; 14 | 15 | /** 16 | * *Adder 17 | * *Accumulator 18 | * Atomic* improvements 19 | * - Decide which atomic.* class best suits given requirements 20 | */ 21 | @Ignore 22 | public class J11c_AtomicTest { 23 | 24 | @Test 25 | public void shouldReturnZeroWhenNoPreviousInteractionsWithTheCalulator() throws Exception { 26 | //given 27 | final SafeCalculator calculator = new SafeCalculator(); 28 | 29 | //when 30 | final double result = calculator.doubleValue(); 31 | 32 | //then 33 | assertThat(result).isEqualTo(0.0, offset(0.1)); 34 | } 35 | 36 | @Test 37 | public void shouldCorrectlyApplyAllOperations() throws Exception { 38 | //given 39 | final SafeCalculator calculator = new SafeCalculator(); 40 | 41 | //when 42 | final int i1 = calculator.add(3); //0 -> 3 43 | final int i2 = calculator.sub(1); //3 -> 2 44 | final int i3 = calculator.mul(4); //2 -> 8 45 | final int i4 = calculator.div(2); //8 -> 4 46 | 47 | //then 48 | assertThat(i1).isZero(); 49 | assertThat(i2).isEqualTo(3); 50 | assertThat(i3).isEqualTo(2); 51 | assertThat(i4).isEqualTo(8); 52 | assertThat(calculator.intValue()).isEqualTo(4); 53 | } 54 | 55 | @Test 56 | public void shouldResetToGivenValueAndReturnPrevious() throws Exception { 57 | //given 58 | final SafeCalculator calculator = new SafeCalculator(); 59 | 60 | //when 61 | calculator.add(4); //4 62 | calculator.sub(-1); //5 63 | final double tmp = calculator.set(3); //3 64 | calculator.mul(2); //6 65 | calculator.div(3); //2 66 | 67 | //then 68 | assertThat(tmp).isEqualTo(5.0, offset(0.1)); 69 | assertThat(calculator.doubleValue()).isEqualTo(2.0, offset(0.1)); 70 | } 71 | 72 | @Test 73 | public void shouldCalculateInMultipleThreads() throws Exception { 74 | //given 75 | final SafeCalculator calculator = new SafeCalculator(); 76 | 77 | //when 78 | IntStream.range(1, 5000).forEach(i -> 79 | MultiRunner.runMultiThreaded(() -> calculator.add(i))); 80 | 81 | //then 82 | final int expectedSum = IntStream.range(1, 5000).sum(); 83 | await().untilCall(to(calculator).doubleValue(), closeTo(expectedSum, 0.01)); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J12_BigDecimalAccumulatorTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.atomic.BigDecimalAccumulator; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.math.BigDecimal; 8 | 9 | import static com.jayway.awaitility.Awaitility.await; 10 | import static org.fest.assertions.api.Assertions.assertThat; 11 | 12 | /** 13 | * Implement {@link BigDecimalAccumulator} so that it satisfies tests below. 14 | */ 15 | @Ignore 16 | public class J12_BigDecimalAccumulatorTest { 17 | 18 | @Test 19 | public void shouldFirstReturnInitialValue() { 20 | //given 21 | final BigDecimalAccumulator accumulator = new BigDecimalAccumulator(BigDecimal.ZERO, (a, x) -> a.add(x)); 22 | 23 | //when 24 | final BigDecimal initial = accumulator.get(); 25 | 26 | //then 27 | assertThat(initial).isEqualByComparingTo(BigDecimal.ZERO); 28 | } 29 | 30 | @Test 31 | public void shouldResetToInitialValue() throws Exception { 32 | //given 33 | final BigDecimalAccumulator accumulator = new BigDecimalAccumulator(BigDecimal.ONE, (a, x) -> a.multiply(x)); 34 | 35 | //when 36 | accumulator.reset(); 37 | 38 | //then 39 | assertThat(accumulator.get()).isEqualByComparingTo(BigDecimal.ONE); 40 | } 41 | 42 | @Test 43 | public void shouldReturnAndResetToInitialValue() throws Exception { 44 | //given 45 | final BigDecimalAccumulator accumulator = new BigDecimalAccumulator(BigDecimal.ONE, (a, x) -> a.multiply(x)); 46 | 47 | //when 48 | final BigDecimal initial = accumulator.getAndReset(); 49 | 50 | //then 51 | assertThat(initial).isEqualByComparingTo(BigDecimal.ONE); 52 | } 53 | 54 | @Test 55 | public void shouldAccumulateOneValue() throws Exception { 56 | //given 57 | final BigDecimalAccumulator accumulator = new BigDecimalAccumulator(BigDecimal.ZERO, (a, x) -> a.add(x)); 58 | 59 | //when 60 | accumulator.accumulate(BigDecimal.TEN); 61 | 62 | //then 63 | assertThat(accumulator.get()).isEqualByComparingTo(BigDecimal.TEN); 64 | } 65 | 66 | @Test 67 | public void shouldAccumulateMultipleValues() throws Exception { 68 | //given 69 | final BigDecimalAccumulator accumulator = new BigDecimalAccumulator(BigDecimal.ZERO, (a, x) -> a.add(x)); 70 | 71 | //when 72 | accumulator.accumulate(BigDecimal.valueOf(1)); 73 | accumulator.accumulate(BigDecimal.valueOf(3)); 74 | accumulator.accumulate(BigDecimal.valueOf(2)); 75 | 76 | //then 77 | assertThat(accumulator.get()).isEqualByComparingTo(BigDecimal.valueOf(1 + 3 + 2)); 78 | } 79 | 80 | @Test 81 | public void shouldAccumulateMaximum() throws Exception { 82 | //given 83 | final BigDecimalAccumulator accumulator = new BigDecimalAccumulator(BigDecimal.ZERO, (a, x) -> a.max(x)); 84 | 85 | //when 86 | accumulator.accumulate(BigDecimal.valueOf(1)); 87 | accumulator.accumulate(BigDecimal.valueOf(7)); 88 | accumulator.accumulate(BigDecimal.valueOf(2)); 89 | accumulator.accumulate(BigDecimal.valueOf(3)); 90 | 91 | //then 92 | assertThat(accumulator.get()).isEqualByComparingTo(BigDecimal.valueOf(7)); 93 | } 94 | 95 | @Test 96 | public void shouldCorrectlyAccumulateFromMultipleThreads() throws Exception { 97 | //given 98 | final BigDecimalAccumulator accumulator = new BigDecimalAccumulator(BigDecimal.ZERO, (a, x) -> a.add(x)); 99 | final int count = 1000; 100 | 101 | //when 102 | MultiRunner.runMultiThreaded(count, () -> accumulator.accumulate(BigDecimal.ONE)); 103 | 104 | //then 105 | await().until(() -> accumulator.get().intValue() == count); 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J13_AsyncAgentTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.agent.Agent; 4 | import org.junit.After; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import java.math.BigInteger; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Set; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.stream.IntStream; 16 | 17 | import static com.jayway.awaitility.Awaitility.await; 18 | import static com.jayway.awaitility.Awaitility.to; 19 | import static java.util.stream.Collectors.toList; 20 | import static org.fest.assertions.api.Assertions.assertThat; 21 | import static org.hamcrest.CoreMatchers.is; 22 | import static org.hamcrest.Matchers.hasSize; 23 | import static org.hamcrest.Matchers.not; 24 | 25 | @Ignore 26 | public class J13_AsyncAgentTest { 27 | 28 | private ExecutorService pool = Executors.newFixedThreadPool(100); 29 | 30 | @After 31 | public void stopPool() { 32 | pool.shutdown(); 33 | } 34 | 35 | public void newAgentShouldHaveInitialValue() { 36 | //given 37 | final Agent agent = Agent.create(42); 38 | 39 | //when 40 | final int actual = agent.get(); 41 | 42 | //then 43 | assertThat(actual).isEqualTo(42); 44 | } 45 | 46 | @Test 47 | public void shouldApplyTwoChanges() { 48 | //given 49 | final Agent agent = Agent.create(BigInteger.ONE); 50 | 51 | //when 52 | agent.send(x -> x.add(BigInteger.ONE)); 53 | agent.send(x -> x.add(BigInteger.TEN)); 54 | 55 | //then 56 | await().until(() -> agent.get().equals(BigInteger.valueOf(1 + 1 + 10))); 57 | } 58 | 59 | @Test 60 | public void shouldApplyChangesFromOneThreadInOrder() { 61 | //given 62 | final Agent agent = Agent.create(""); 63 | 64 | //when 65 | agent.send(s -> s + "A"); 66 | agent.send(s -> s + "B"); 67 | agent.send(s -> s + "C"); 68 | agent.send(String::toLowerCase); 69 | agent.send(s -> "D" + s); 70 | 71 | //then 72 | await().untilCall(to(agent).get(), is("Dabc")); 73 | } 74 | 75 | @Test 76 | public void shouldRunInDifferentThread() { 77 | //given 78 | final long mainThreadId = Thread.currentThread().getId(); 79 | final Agent agent = Agent.create(mainThreadId); 80 | 81 | //when 82 | agent.send(x -> Thread.currentThread().getId()); 83 | 84 | //then 85 | await().untilCall(to(agent).get(), is(not(mainThreadId))); 86 | } 87 | 88 | @Test 89 | public void aLotOfAgents() throws InterruptedException { 90 | //given 91 | final int totalAgents = 50_000; 92 | final List> agents = IntStream 93 | .range(0, totalAgents) 94 | .boxed() 95 | .map(i -> Agent.create("")) 96 | .collect(toList()); 97 | 98 | //when 99 | agents.forEach(a -> { 100 | a.send(s -> s + "a"); 101 | a.send(s -> s + "b"); 102 | a.send(s -> s + "c"); 103 | a.send(s -> s + "d"); 104 | a.send(s -> s + "e"); 105 | a.send(s -> s + "f"); 106 | }); 107 | 108 | //then 109 | agents.forEach(this::waitForCorrectResult); 110 | } 111 | 112 | private void waitForCorrectResult(Agent a) { 113 | await() 114 | .pollInterval(1, TimeUnit.MILLISECONDS) 115 | .pollDelay(1, TimeUnit.NANOSECONDS) 116 | .until(a::get, is("abcdef")); 117 | } 118 | 119 | @Test 120 | public void shouldMutateObjectInsideAgent() throws Exception { 121 | //given 122 | final Agent> agent = Agent.create(new HashSet<>()); 123 | final int total = 10_000; 124 | 125 | //when 126 | IntStream 127 | .range(0, total) 128 | .forEach(i -> 129 | agent.send(set -> { 130 | set.add(i); 131 | return set; 132 | })); 133 | 134 | //then 135 | await().untilCall(to(agent).get(), hasSize(total)); 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J21_FuturesIntroductionTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.stackoverflow.LoadFromStackOverflowTask; 4 | import com.nurkiewicz.java8.util.AbstractFuturesTest; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.concurrent.Callable; 11 | import java.util.concurrent.Future; 12 | 13 | @Ignore 14 | public class J21_FuturesIntroductionTest extends AbstractFuturesTest { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(J21_FuturesIntroductionTest.class); 17 | 18 | @Test 19 | public void blockingCall() throws Exception { 20 | final String title = client.mostRecentQuestionAbout("java"); 21 | log.debug("Most recent Java question: '{}'", title); 22 | } 23 | 24 | @Test 25 | public void executorService() throws Exception { 26 | final Callable task = () -> client.mostRecentQuestionAbout("java"); 27 | final Future javaQuestionFuture = executorService.submit(task); 28 | final String javaQuestion = javaQuestionFuture.get(); 29 | log.debug("Found: '{}'", javaQuestion); 30 | } 31 | 32 | @Test 33 | public void waitForFirstOrAll() throws Exception { 34 | final Future java = findQuestionsAbout("java"); 35 | final Future scala = findQuestionsAbout("scala"); 36 | 37 | //??? 38 | } 39 | 40 | @Test 41 | public void runWhenFirstFinished() throws Exception { 42 | final Future java = findQuestionsAbout("java"); 43 | final Future scala = findQuestionsAbout("scala"); 44 | //??? 45 | } 46 | 47 | private Future findQuestionsAbout(String tag) { 48 | final Callable task = new LoadFromStackOverflowTask(client, tag); 49 | return executorService.submit(task); 50 | } 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J22_CreatingTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.util.AbstractFuturesTest; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.concurrent.CompletableFuture; 10 | 11 | @Ignore 12 | public class J22_CreatingTest extends AbstractFuturesTest { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(J22_CreatingTest.class); 15 | 16 | @Test 17 | public void supplyAsync() throws Exception { 18 | final CompletableFuture java = CompletableFuture.supplyAsync(() -> 19 | client.mostRecentQuestionAbout("java") 20 | ); 21 | log.debug("Found: '{}'", java.get()); 22 | } 23 | 24 | @Test 25 | public void supplyAsyncWithCustomExecutor() throws Exception { 26 | final CompletableFuture java = CompletableFuture.supplyAsync(() -> 27 | client.mostRecentQuestionAbout("java"), 28 | executorService); 29 | log.debug("Found: '{}'", java.get()); 30 | } 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J23_MapTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.util.AbstractFuturesTest; 4 | import org.jsoup.nodes.Document; 5 | import org.jsoup.nodes.Element; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.util.concurrent.CompletableFuture; 12 | 13 | @Ignore 14 | public class J23_MapTest extends AbstractFuturesTest { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(J23_MapTest.class); 17 | 18 | @Test 19 | public void oldSchool() throws Exception { 20 | final CompletableFuture java = CompletableFuture.supplyAsync(() -> 21 | client.mostRecentQuestionsAbout("java"), 22 | executorService); 23 | 24 | final Document document = java.get(); //blocks 25 | final Element element = document.select("a.question-hyperlink").get(0); 26 | final String title = element.text(); 27 | final int length = title.length(); 28 | log.debug("Length: {}", length); 29 | } 30 | 31 | @Test 32 | public void thenApply() throws Exception { 33 | final CompletableFuture java = CompletableFuture.supplyAsync(() -> 34 | client.mostRecentQuestionsAbout("java"), 35 | executorService); 36 | 37 | final CompletableFuture titleElement = 38 | java.thenApply((Document doc) -> doc.select("a.question-hyperlink").get(0)); 39 | 40 | final CompletableFuture titleText = 41 | titleElement.thenApply(Element::text); 42 | 43 | final CompletableFuture length = 44 | titleText.thenApply(String::length); 45 | 46 | log.debug("Length: {}", length.get()); 47 | } 48 | 49 | @Test 50 | public void thenApplyChained() throws Exception { 51 | final CompletableFuture java = CompletableFuture.supplyAsync(() -> 52 | client.mostRecentQuestionsAbout("java"), 53 | executorService); 54 | 55 | final CompletableFuture length = java. 56 | thenApply(doc -> doc.select("a.question-hyperlink").get(0)). 57 | thenApply(Element::text). 58 | thenApply(String::length); 59 | 60 | log.debug("Length: {}", length.get()); 61 | } 62 | 63 | @Test 64 | public void thenApplySingleStep() throws Exception { 65 | final CompletableFuture java = CompletableFuture.supplyAsync(() -> 66 | client.mostRecentQuestionsAbout("java"), 67 | executorService); 68 | 69 | final CompletableFuture length = java. 70 | thenApply(doc -> 71 | doc.select("a.question-hyperlink"). 72 | get(0). 73 | text(). 74 | length()); 75 | 76 | log.debug("Length: {}", length.get()); 77 | } 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J24_FlatMapTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.stackoverflow.Question; 4 | import com.nurkiewicz.java8.util.AbstractFuturesTest; 5 | import org.jsoup.nodes.Document; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.http.HttpStatus; 11 | 12 | import java.util.concurrent.CompletableFuture; 13 | import java.util.concurrent.ExecutorService; 14 | import java.util.concurrent.Executors; 15 | 16 | @Ignore 17 | public class J24_FlatMapTest extends AbstractFuturesTest { 18 | 19 | private static final Logger log = LoggerFactory.getLogger(J24_FlatMapTest.class); 20 | 21 | private CompletableFuture javaQuestions() { 22 | return CompletableFuture.supplyAsync(() -> 23 | client.mostRecentQuestionsAbout("java"), 24 | executorService); 25 | } 26 | 27 | private CompletableFuture findMostInterestingQuestion(Document document) { 28 | return CompletableFuture.completedFuture(new Question()); 29 | } 30 | 31 | private CompletableFuture googleAnswer(Question q) { 32 | return CompletableFuture.completedFuture("42"); 33 | } 34 | 35 | private CompletableFuture postAnswer(String answer) { 36 | return CompletableFuture.completedFuture(200); 37 | } 38 | 39 | @Test 40 | public void thenApplyIsWrong() throws Exception { 41 | final CompletableFuture> future = 42 | javaQuestions().thenApply(this::findMostInterestingQuestion); 43 | } 44 | 45 | @Test 46 | public void thenAcceptIsPoor() throws Exception { 47 | javaQuestions().thenAccept(document -> { 48 | findMostInterestingQuestion(document).thenAccept(question -> { 49 | googleAnswer(question).thenAccept(answer -> { 50 | postAnswer(answer).thenAccept(status -> { 51 | if (status == HttpStatus.OK.value()) { 52 | log.debug("OK"); 53 | } else { 54 | log.error("Wrong status code: {}", status); 55 | } 56 | }); 57 | }); 58 | }); 59 | }); 60 | } 61 | 62 | @Test 63 | public void thenCompose() throws Exception { 64 | final CompletableFuture java = javaQuestions(); 65 | 66 | final CompletableFuture questionFuture = 67 | java.thenCompose(this::findMostInterestingQuestion); 68 | 69 | final CompletableFuture answerFuture = 70 | questionFuture.thenCompose(this::googleAnswer); 71 | 72 | final CompletableFuture httpStatusFuture = 73 | answerFuture.thenCompose(this::postAnswer); 74 | 75 | httpStatusFuture.thenAccept(status -> { 76 | if (status == HttpStatus.OK.value()) { 77 | log.debug("OK"); 78 | } else { 79 | log.error("Wrong status code: {}", status); 80 | } 81 | }); 82 | } 83 | 84 | @Test 85 | public void chained() throws Exception { 86 | 87 | ExecutorService pool = 88 | Executors.newFixedThreadPool(10); 89 | 90 | CompletableFuture future = 91 | CompletableFuture.supplyAsync(() -> 92 | loadWebPage("www.wikipedia.org"), 93 | pool); 94 | 95 | future. 96 | thenApply(this::parse). 97 | thenCompose(this::keywords). 98 | thenAccept(System.out::println); 99 | 100 | } 101 | 102 | private String loadWebPage(String s) { 103 | return null; 104 | } 105 | 106 | Document parse(String html) { 107 | return null; 108 | } 109 | 110 | CompletableFuture keywords(Document doc) { 111 | //... 112 | return null; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J25_ZipTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.util.AbstractFuturesTest; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.concurrent.CompletableFuture; 10 | 11 | @Ignore 12 | public class J25_ZipTest extends AbstractFuturesTest { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(J25_ZipTest.class); 15 | 16 | @Test 17 | public void thenCombine() throws Exception { 18 | final CompletableFuture java = questions("java"); 19 | final CompletableFuture scala = questions("scala"); 20 | 21 | final CompletableFuture both = java. 22 | thenCombine(scala, (String javaTitle, String scalaTitle) -> 23 | javaTitle.length() + scalaTitle.length() 24 | ); 25 | 26 | both.thenAccept(length -> log.debug("Total length: {}", length)); 27 | 28 | 29 | final CompletableFuture f1 = null; //... 30 | final CompletableFuture f2 = null; //... 31 | 32 | final CompletableFuture sum = f1.thenCombine(f2, (i1, i2) -> (i1 + i2 / 2.0)); 33 | 34 | f1.acceptEither(f2, System.out::println); 35 | } 36 | 37 | @Test 38 | public void either() throws Exception { 39 | final CompletableFuture java = questions("java"); 40 | final CompletableFuture scala = questions("scala"); 41 | 42 | final CompletableFuture both = java. 43 | applyToEither(scala, String::toUpperCase); 44 | 45 | both.thenAccept(title -> log.debug("First: {}", title)); 46 | } 47 | 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J26_AllAnyTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.util.AbstractFuturesTest; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.concurrent.ExecutionException; 11 | 12 | @Ignore 13 | public class J26_AllAnyTest extends AbstractFuturesTest { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(J26_AllAnyTest.class); 16 | 17 | @Test 18 | public void allOf() throws Exception { 19 | final CompletableFuture java = questions("java"); 20 | final CompletableFuture scala = questions("scala"); 21 | final CompletableFuture clojure = questions("clojure"); 22 | final CompletableFuture groovy = questions("groovy"); 23 | 24 | final CompletableFuture allCompleted = CompletableFuture.allOf( 25 | java, scala, clojure, groovy 26 | ); 27 | 28 | allCompleted.thenRun(() -> { 29 | try { 30 | log.debug("Loaded: {}", java.get()); 31 | log.debug("Loaded: {}", scala.get()); 32 | log.debug("Loaded: {}", clojure.get()); 33 | log.debug("Loaded: {}", groovy.get()); 34 | } catch (InterruptedException | ExecutionException e) { 35 | log.error("", e); 36 | } 37 | }); 38 | } 39 | 40 | @Test 41 | public void anyOf() throws Exception { 42 | final CompletableFuture java = questions("java"); 43 | final CompletableFuture scala = questions("scala"); 44 | final CompletableFuture clojure = questions("clojure"); 45 | final CompletableFuture groovy = questions("groovy"); 46 | 47 | final CompletableFuture firstCompleted = CompletableFuture.anyOf( 48 | java, scala, clojure, groovy 49 | ); 50 | 51 | firstCompleted.thenAccept((Object result) -> { 52 | log.debug("First: {}", result); 53 | }); 54 | } 55 | 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J27_PromisesTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.util.AbstractFuturesTest; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.IOException; 10 | import java.nio.file.FileSystems; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import java.nio.file.StandardWatchEventKinds; 14 | import java.nio.file.WatchEvent; 15 | import java.nio.file.WatchKey; 16 | import java.nio.file.WatchService; 17 | import java.util.List; 18 | import java.util.concurrent.CompletableFuture; 19 | 20 | @Ignore 21 | public class J27_PromisesTest extends AbstractFuturesTest { 22 | 23 | private static final Logger log = LoggerFactory.getLogger(J27_PromisesTest.class); 24 | 25 | @Test 26 | public void promises() throws Exception { 27 | final CompletableFuture future = newFilePromise(); 28 | 29 | log.debug("New file found on desktop {}", future.get()); 30 | } 31 | 32 | private CompletableFuture newFilePromise() { 33 | final CompletableFuture promise = new CompletableFuture<>(); 34 | waitForNewFileInSeparateThread(promise); 35 | return promise; 36 | } 37 | 38 | private void waitForNewFileInSeparateThread(final CompletableFuture promise) { 39 | new Thread("FileSystemWatcher") { 40 | @Override 41 | public void run() { 42 | try { 43 | promise.complete(waitForNewFileOnDesktop()); 44 | } catch (Exception e) { 45 | promise.completeExceptionally(e); 46 | } 47 | } 48 | }.start(); 49 | } 50 | 51 | private Path waitForNewFileOnDesktop() throws IOException, InterruptedException { 52 | WatchService watchService = FileSystems.getDefault().newWatchService(); 53 | final WatchKey key = Paths. 54 | get(System.getProperty("user.home"), "Desktop"). 55 | register(watchService, StandardWatchEventKinds.ENTRY_CREATE); 56 | while (!Thread.currentThread().isInterrupted()) { 57 | final List> events = key.pollEvents(); 58 | if (!events.isEmpty()) { 59 | return (Path) events.get(0).context(); 60 | } 61 | key.reset(); 62 | } 63 | throw new InterruptedException(); 64 | } 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J28_CustomFutureOperatorsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.After; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.time.Duration; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.concurrent.CompletableFuture; 11 | import java.util.concurrent.ExecutorService; 12 | import java.util.concurrent.Executors; 13 | import java.util.concurrent.Future; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.concurrent.TimeoutException; 16 | import java.util.concurrent.atomic.AtomicBoolean; 17 | import java.util.function.BiFunction; 18 | 19 | import static com.jayway.awaitility.Awaitility.await; 20 | import static java.util.concurrent.CompletableFuture.completedFuture; 21 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 22 | import static java.util.concurrent.TimeUnit.SECONDS; 23 | import static org.fest.assertions.api.Assertions.assertThat; 24 | import static org.fest.assertions.api.Assertions.failBecauseExceptionWasNotThrown; 25 | import static org.hamcrest.core.Is.is; 26 | 27 | @Ignore 28 | public class J28_CustomFutureOperatorsTest { 29 | 30 | private final ExecutorService pool = Executors.newFixedThreadPool(10); 31 | 32 | @After 33 | public void closePool() { 34 | pool.shutdownNow(); 35 | } 36 | 37 | @Test 38 | public void shouldTimeoutIfUnderlyingFutureDoesNotResponse() throws Exception { 39 | //given 40 | CompletableFuture never = FutureOps.never(); 41 | 42 | //when 43 | try { 44 | never.get(100, MILLISECONDS); 45 | failBecauseExceptionWasNotThrown(TimeoutException.class); 46 | } catch (TimeoutException e) { 47 | //then 48 | } 49 | } 50 | 51 | /** 52 | * If primary future does not complete in given time, {@link CompletableFuture#handle(BiFunction)} timeout and return special value. 53 | */ 54 | @Test 55 | public void shouldTimeoutAfterSpecifiedTime() throws Exception { 56 | //given 57 | CompletableFuture primary = FutureOps.never(); 58 | CompletableFuture timeout = FutureOps.timeoutAfter(Duration.ofMillis(100)); 59 | CompletableFuture any = null; //... 60 | 61 | //when 62 | final String fallback = any.get(1, SECONDS); 63 | 64 | //then 65 | assertThat(fallback).isEqualTo("Fallback"); 66 | } 67 | 68 | @Test 69 | public void shouldConvertOldFutureToCompletableFuture() throws Exception { 70 | //given 71 | final Future answer = pool.submit(() -> 42); 72 | 73 | //when 74 | final CompletableFuture completableAnswer = FutureOps.toCompletable(answer); 75 | 76 | //then 77 | AtomicBoolean condition = new AtomicBoolean(); 78 | completableAnswer.thenRun(() -> condition.set(true)); 79 | await().untilAtomic(condition, is(true)); 80 | } 81 | 82 | @Test 83 | public void shouldIgnoreFailures() throws Exception { 84 | //given 85 | final CompletableFuture failed = FutureOps.failed(new UnsupportedOperationException("Don't panic!")); 86 | final CompletableFuture first = completedFuture(42); 87 | final CompletableFuture second = completedFuture(45); 88 | final CompletableFuture broken = FutureOps.failed(new UnsupportedOperationException("Simulated")); 89 | 90 | //when 91 | final CompletableFuture> succeeded = FutureOps.ignoreFailures(Arrays.asList(failed, first, second, broken)); 92 | 93 | //then 94 | assertThat(succeeded.get(1, TimeUnit.SECONDS)).containsExactly(42, 45); 95 | } 96 | 97 | /** 98 | * If it takes more than a second for future to complete, ignore it 99 | */ 100 | @Test 101 | public void shouldIgnoreFuturesRunningForTooLong() throws Exception { 102 | //given 103 | final CompletableFuture later = FutureOps.delay(completedFuture(42), Duration.ofMillis(500)); 104 | final CompletableFuture tooLate = FutureOps.delay(completedFuture(17), Duration.ofDays(1)); 105 | final CompletableFuture immediately = completedFuture(45); 106 | final CompletableFuture never = FutureOps.never(); 107 | 108 | final List> futures = Arrays.asList(later, tooLate, immediately, never); 109 | 110 | //when 111 | CompletableFuture> fastAndSuccess = null; 112 | 113 | //then 114 | assertThat(fastAndSuccess.get(1, TimeUnit.SECONDS)).containsExactly(42, 45); 115 | } 116 | 117 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J29_AsyncAgentFuturesTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import com.nurkiewicz.java8.agent.Agent; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | 7 | import java.util.concurrent.CompletableFuture; 8 | import java.util.concurrent.ExecutionException; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.concurrent.TimeoutException; 11 | 12 | import static org.fest.assertions.api.Assertions.assertThat; 13 | 14 | @Ignore 15 | public class J29_AsyncAgentFuturesTest { 16 | 17 | @Test 18 | public void shouldCompleteFutureWhenSendDone() throws ExecutionException, InterruptedException { 19 | //given 20 | final Agent agent = Agent.create(1); 21 | 22 | //when 23 | final CompletableFuture future = agent.sendAndGet(x -> x + 2); 24 | 25 | //then 26 | assertThat(future.get()).isEqualTo(1 + 2); 27 | } 28 | 29 | @Test 30 | public void shouldCompleteWhenAllPendingFuturesAreDone() throws ExecutionException, InterruptedException { 31 | //given 32 | final Agent agent = Agent.create(""); 33 | 34 | //when 35 | agent.send(s -> s + "1"); 36 | agent.send(s -> s + "2"); 37 | final CompletableFuture future = agent.sendAndGet(s -> s + "3"); 38 | 39 | //then 40 | assertThat(future.get()).isEqualTo("123"); 41 | } 42 | 43 | @Test 44 | public void shouldWaitUntilConditionIsMetOnTwoAgents() throws ExecutionException, InterruptedException, TimeoutException { 45 | //given 46 | final Agent agentOne = Agent.create("Abc"); 47 | final Agent agentTwo = Agent.create("Def"); 48 | 49 | //when 50 | final CompletableFuture futureOne = agentOne.completeIf(String::isEmpty); 51 | final CompletableFuture futureTwo = agentTwo.completeIf(String::isEmpty); 52 | agentOne.send(s -> ""); 53 | agentTwo.send(s -> ""); 54 | 55 | //then 56 | futureOne.get(1, TimeUnit.SECONDS); 57 | futureTwo.get(1, TimeUnit.SECONDS); 58 | assertThat(agentOne.get()).isEmpty(); 59 | assertThat(agentTwo.get()).isEmpty(); 60 | } 61 | 62 | @Test 63 | public void shouldWaitForTwoAgents() throws ExecutionException, InterruptedException, TimeoutException { 64 | //given 65 | final Agent agentOne = Agent.create(""); 66 | final Agent agentTwo = Agent.create(""); 67 | 68 | //when 69 | final CompletableFuture futureOne = agentOne.sendAndGet(s -> s + "One"); 70 | final CompletableFuture futureTwo = agentTwo.sendAndGet(s -> s + "Two"); 71 | 72 | //then 73 | CompletableFuture both = null; 74 | assertThat(both.get(1, TimeUnit.SECONDS)).isEqualTo("OneTwo"); 75 | } 76 | 77 | @Test 78 | public void shouldReflectAllPriorChangesWhenAsyncGet() throws ExecutionException, InterruptedException, TimeoutException { 79 | //given 80 | final Agent agent = Agent.create(1); 81 | 82 | //when 83 | agent.send(x -> x + 2); 84 | final CompletableFuture future = agent.getAsync(); 85 | 86 | //then 87 | assertThat(future.get(1, TimeUnit.SECONDS)).isEqualTo(1 + 2); 88 | } 89 | 90 | @Test 91 | public void shouldNotSeeChangesMadeAfterAsyncGet() throws ExecutionException, InterruptedException, TimeoutException { 92 | //given 93 | final Agent agent = Agent.create(1); 94 | 95 | //when 96 | agent.send(x -> x + 2); 97 | final CompletableFuture future = agent.getAsync(); 98 | agent.send(x -> x + 3); 99 | 100 | //then 101 | assertThat(future.get(1, TimeUnit.SECONDS)).isEqualTo(1 + 2); 102 | } 103 | 104 | @Test 105 | public void shouldCompleteWhenConditionIsMet() throws ExecutionException, InterruptedException, TimeoutException { 106 | //given 107 | final Agent agent = Agent.create(""); 108 | 109 | //when 110 | final CompletableFuture future = agent.completeIf(s -> s.length() > 2); 111 | agent.send(s -> s + "1"); 112 | agent.send(s -> s + "2"); 113 | agent.send(s -> s + "3"); 114 | 115 | //then 116 | assertThat(future.get(1, TimeUnit.SECONDS)).isEqualTo("12"); 117 | } 118 | 119 | @Test 120 | public void shouldCompleteImmediatelyIfConditionAlreadyMet() throws ExecutionException, InterruptedException, TimeoutException { 121 | //given 122 | final Agent agent = Agent.create(""); 123 | 124 | //when 125 | final CompletableFuture future = agent.completeIf(String::isEmpty); 126 | agent.send(s -> s + "1"); 127 | 128 | //then 129 | assertThat(future.get(1, TimeUnit.SECONDS)).isEmpty(); 130 | } 131 | 132 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/J60_CovarianceTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.List; 9 | import java.util.concurrent.ExecutionException; 10 | 11 | /** 12 | * - covariance of arrays 13 | * - input/output 14 | * - function 15 | */ 16 | @Ignore 17 | public class J60_CovarianceTest { 18 | 19 | @Test 20 | public void variance() throws ExecutionException, InterruptedException { 21 | } 22 | 23 | public double sum(List numbers) { 24 | return numbers 25 | .stream() 26 | .mapToDouble(Number::doubleValue) 27 | .sum(); 28 | } 29 | 30 | public static void sort(List list, Comparator c) { 31 | Collections.sort(list, c); 32 | } 33 | } 34 | 35 | class NumberComparator implements Comparator { 36 | 37 | @Override 38 | public int compare(Number o1, Number o2) { 39 | return Double.compare(o1.doubleValue(), o2.doubleValue()); 40 | } 41 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/holidays/EasterTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import junitparams.JUnitParamsRunner; 4 | import junitparams.Parameters; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | 8 | import java.time.MonthDay; 9 | import java.time.Year; 10 | 11 | import static java.time.Month.APRIL; 12 | import static java.time.Month.MARCH; 13 | import static junitparams.JUnitParamsRunner.$; 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | 16 | @RunWith(JUnitParamsRunner.class) 17 | public class EasterTest { 18 | 19 | @Test 20 | @Parameters 21 | public void shouldCalculateEasterSunday(int year, MonthDay easterDate) { 22 | assertThat(Easter.sundayFor(Year.of(year))).isEqualTo(easterDate.atYear(year)); 23 | } 24 | 25 | private Object[] parametersForShouldCalculateEasterSunday() { 26 | return $( 27 | $(1994, MonthDay.of(APRIL, 3)), 28 | $(1995, MonthDay.of(APRIL, 16)), 29 | $(1996, MonthDay.of(APRIL, 7)), 30 | $(1997, MonthDay.of(MARCH, 30)), 31 | $(1998, MonthDay.of(APRIL, 12)), 32 | $(1999, MonthDay.of(APRIL, 4)), 33 | $(2000, MonthDay.of(APRIL, 23)), 34 | $(2001, MonthDay.of(APRIL, 15)), 35 | $(2002, MonthDay.of(MARCH, 31)), 36 | $(2003, MonthDay.of(APRIL, 20)), 37 | $(2004, MonthDay.of(APRIL, 11)), 38 | $(2005, MonthDay.of(MARCH, 27)), 39 | $(2006, MonthDay.of(APRIL, 16)), 40 | $(2007, MonthDay.of(APRIL, 8)), 41 | $(2008, MonthDay.of(MARCH, 23)), 42 | $(2009, MonthDay.of(APRIL, 12)), 43 | $(2010, MonthDay.of(APRIL, 4)), 44 | $(2011, MonthDay.of(APRIL, 24)), 45 | $(2012, MonthDay.of(APRIL, 8)), 46 | $(2013, MonthDay.of(MARCH, 31)), 47 | $(2014, MonthDay.of(APRIL, 20)), 48 | $(2015, MonthDay.of(APRIL, 5)), 49 | $(2016, MonthDay.of(MARCH, 27)), 50 | $(2017, MonthDay.of(APRIL, 16)), 51 | $(2018, MonthDay.of(APRIL, 1)), 52 | $(2019, MonthDay.of(APRIL, 21)), 53 | $(2020, MonthDay.of(APRIL, 12)), 54 | $(2021, MonthDay.of(APRIL, 4)), 55 | $(2022, MonthDay.of(APRIL, 17)), 56 | $(2023, MonthDay.of(APRIL, 9)), 57 | $(2024, MonthDay.of(MARCH, 31)), 58 | $(2025, MonthDay.of(APRIL, 20)), 59 | $(2026, MonthDay.of(APRIL, 5)), 60 | $(2027, MonthDay.of(MARCH, 28)), 61 | $(2028, MonthDay.of(APRIL, 16)), 62 | $(2029, MonthDay.of(APRIL, 1)), 63 | $(2030, MonthDay.of(APRIL, 21)), 64 | $(2031, MonthDay.of(APRIL, 13)), 65 | $(2032, MonthDay.of(MARCH, 28)), 66 | $(2033, MonthDay.of(APRIL, 17)), 67 | $(2034, MonthDay.of(APRIL, 9)) 68 | ); 69 | } 70 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/holidays/HolidaysFactoryTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Locale; 6 | 7 | import static org.fest.assertions.api.Assertions.assertThat; 8 | 9 | public class HolidaysFactoryTest { 10 | 11 | @Test 12 | public void shouldReturnPolishHolidays() { 13 | //given 14 | final Locale poland = new Locale("pl", "PL"); 15 | 16 | //when 17 | final Holidays holidays = HolidaysFactory.of(poland); 18 | 19 | //then 20 | assertThat(holidays).isInstanceOf(PolishHolidays.class); 21 | } 22 | 23 | @Test 24 | public void shouldReturnAmericanHolidays() { 25 | //given 26 | final Locale america = Locale.US; 27 | 28 | //when 29 | final Holidays holidays = HolidaysFactory.of(america); 30 | 31 | //then 32 | assertThat(holidays).isInstanceOf(AmericanHolidays.class); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/holidays/PolishHolidaysTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.holidays; 2 | 3 | import org.junit.Test; 4 | 5 | import java.time.LocalDate; 6 | 7 | import static java.time.Month.APRIL; 8 | import static java.time.Month.AUGUST; 9 | import static java.time.Month.DECEMBER; 10 | import static java.time.Month.JANUARY; 11 | import static java.time.Month.JUNE; 12 | import static java.time.Month.MAY; 13 | import static java.time.Month.NOVEMBER; 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | 16 | /** 17 | * Tasks: 18 | * - move duplicated code to default methods in interface 19 | * - move factory to static interface method 20 | * - refactor nextWorkingDayAfter/nextHolidayAfter to avoid duplication 21 | */ 22 | public class PolishHolidaysTest { 23 | 24 | private final Holidays holidays = new PolishHolidays(); 25 | 26 | @Test 27 | public void shouldIdentifyFixedPolishHolidays() { 28 | assertHoliday(LocalDate.of(2014, JANUARY, 1)); 29 | assertHoliday(LocalDate.of(2014, JANUARY, 6)); 30 | assertHoliday(LocalDate.of(2014, MAY, 1)); 31 | assertHoliday(LocalDate.of(2014, MAY, 3)); 32 | assertHoliday(LocalDate.of(2014, AUGUST, 15)); 33 | assertHoliday(LocalDate.of(2014, NOVEMBER, 1)); 34 | assertHoliday(LocalDate.of(2014, NOVEMBER, 11)); 35 | assertHoliday(LocalDate.of(2014, DECEMBER, 25)); 36 | assertHoliday(LocalDate.of(2014, DECEMBER, 26)); 37 | } 38 | 39 | @Test 40 | public void shouldIdentifyWeekends() { 41 | assertWorkingDay(LocalDate.of(2014, APRIL, 25)); 42 | assertHoliday(LocalDate.of(2014, APRIL, 26)); 43 | assertHoliday(LocalDate.of(2014, APRIL, 27)); 44 | assertWorkingDay(LocalDate.of(2014, APRIL, 28)); 45 | } 46 | 47 | @Test 48 | public void shouldIdentifyMovingHolidays() { 49 | assertThat(holidays.isHoliday(LocalDate.of(2014, APRIL, 21))).isTrue(); 50 | assertThat(holidays.isHoliday(LocalDate.of(2014, JUNE, 19))).isTrue(); 51 | } 52 | 53 | @Test 54 | public void shouldFindNextWorkingDay() { 55 | assertThat(holidays.nextWorkingDayAfter(LocalDate.of(2014, APRIL, 24))).isEqualTo(LocalDate.of(2014, APRIL, 25)); 56 | assertThat(holidays.nextWorkingDayAfter(LocalDate.of(2014, APRIL, 25))).isEqualTo(LocalDate.of(2014, APRIL, 28)); 57 | assertThat(holidays.nextWorkingDayAfter(LocalDate.of(2014, APRIL, 26))).isEqualTo(LocalDate.of(2014, APRIL, 28)); 58 | assertThat(holidays.nextWorkingDayAfter(LocalDate.of(2014, APRIL, 28))).isEqualTo(LocalDate.of(2014, APRIL, 29)); 59 | assertThat(holidays.nextWorkingDayAfter(LocalDate.of(2014, APRIL, 30))).isEqualTo(LocalDate.of(2014, MAY, 2)); 60 | } 61 | 62 | @Test 63 | public void shouldFindNextHoliday() { 64 | assertThat(holidays.nextHolidayAfter(LocalDate.of(2014, APRIL, 24))).isEqualTo(LocalDate.of(2014, APRIL, 26)); 65 | assertThat(holidays.nextHolidayAfter(LocalDate.of(2014, APRIL, 25))).isEqualTo(LocalDate.of(2014, APRIL, 26)); 66 | assertThat(holidays.nextHolidayAfter(LocalDate.of(2014, APRIL, 26))).isEqualTo(LocalDate.of(2014, APRIL, 27)); 67 | assertThat(holidays.nextHolidayAfter(LocalDate.of(2014, APRIL, 28))).isEqualTo(LocalDate.of(2014, MAY, 1)); 68 | assertThat(holidays.nextHolidayAfter(LocalDate.of(2014, MAY, 1))).isEqualTo(LocalDate.of(2014, MAY, 3)); 69 | } 70 | 71 | private void assertHoliday(LocalDate date) { 72 | assertThat(holidays.isHoliday(date)).isTrue(); 73 | assertThat(holidays.isWorkingDay(date)).isFalse(); 74 | } 75 | 76 | private void assertWorkingDay(LocalDate date) { 77 | assertThat(holidays.isHoliday(date)).isFalse(); 78 | assertThat(holidays.isWorkingDay(date)).isTrue(); 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/java8/util/AbstractFuturesTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.java8.util; 2 | 3 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 4 | import com.nurkiewicz.java8.stackoverflow.ArtificialSleepWrapper; 5 | import com.nurkiewicz.java8.stackoverflow.FallbackStubClient; 6 | import com.nurkiewicz.java8.stackoverflow.HttpStackOverflowClient; 7 | import com.nurkiewicz.java8.stackoverflow.InjectErrorsWrapper; 8 | import com.nurkiewicz.java8.stackoverflow.LoggingWrapper; 9 | import com.nurkiewicz.java8.stackoverflow.StackOverflowClient; 10 | import org.junit.After; 11 | import org.junit.Before; 12 | import org.junit.Rule; 13 | import org.junit.rules.TestName; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.util.concurrent.CompletableFuture; 18 | import java.util.concurrent.ExecutorService; 19 | import java.util.concurrent.Executors; 20 | import java.util.concurrent.ThreadFactory; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | public abstract class AbstractFuturesTest { 24 | 25 | private static final Logger log = LoggerFactory.getLogger(AbstractFuturesTest.class); 26 | 27 | protected final ExecutorService executorService = Executors.newFixedThreadPool(10, threadFactory()); 28 | 29 | @Rule 30 | public TestName testName = new TestName(); 31 | 32 | private ThreadFactory threadFactory() { 33 | return new ThreadFactoryBuilder() 34 | .setNameFormat("Custom-pool-%d").build(); 35 | } 36 | 37 | protected final StackOverflowClient client = 38 | new FallbackStubClient( 39 | new InjectErrorsWrapper( 40 | new LoggingWrapper( 41 | new ArtificialSleepWrapper( 42 | new HttpStackOverflowClient() 43 | ) 44 | ), "php" 45 | ) 46 | ); 47 | 48 | @Before 49 | public void logTestStart() { 50 | log.debug("Starting: {}", testName.getMethodName()); 51 | } 52 | 53 | @After 54 | public void stopPool() throws InterruptedException { 55 | executorService.shutdown(); 56 | executorService.awaitTermination(10, TimeUnit.SECONDS); 57 | } 58 | 59 | protected CompletableFuture questions(String tag) { 60 | return CompletableFuture.supplyAsync(() -> 61 | client.mostRecentQuestionAbout(tag), 62 | executorService 63 | ); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R41_IntroductionTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.nurkiewicz.rxjava.weather.Weather; 4 | import com.nurkiewicz.rxjava.weather.WeatherStation; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import rx.Observable; 10 | import rx.Subscription; 11 | 12 | import java.util.concurrent.TimeUnit; 13 | 14 | @Ignore 15 | public class R41_IntroductionTest { 16 | 17 | private static final Logger log = LoggerFactory.getLogger(R41_IntroductionTest.class); 18 | 19 | final WeatherStation station = WeatherStation.find("WAW"); 20 | final Observable observable = station.observations(); 21 | 22 | /** 23 | * Observable.subscribe() 24 | */ 25 | @Test 26 | public void subscribingToObservable() throws InterruptedException { 27 | final Subscription subscription = 28 | observable.subscribe((Weather w) -> 29 | log.debug("Weather changed: {}", w.getTemperature()) 30 | ); 31 | 32 | TimeUnit.SECONDS.sleep(10); 33 | subscription.unsubscribe(); 34 | } 35 | 36 | /** 37 | * - map() and filter() 38 | * - show immutability 39 | */ 40 | @Test 41 | public void mapAndFilter() { 42 | final Observable temperatures = observable. 43 | map(Weather::getTemperature); 44 | 45 | final Observable highTemp = temperatures.filter(t -> t > 30.0); 46 | final Observable lowTemp = temperatures.filter(t -> t < 15.0); 47 | } 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R42_CreatingTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import rx.Observable; 8 | import rx.Subscriber; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | @Ignore 13 | public class R42_CreatingTest { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(R42_CreatingTest.class); 16 | 17 | /** 18 | * Observable.from(Iterable) 19 | * - subscribe and see execution Thread in logger 20 | */ 21 | @Test 22 | public void fromCollection() { 23 | final Observable obs = Observable.from(1, 2, 3, 4, 5); 24 | obs. 25 | map(i -> i * 10). //10, 20, 30... 50 26 | filter(i -> i > 20). //30...50 27 | flatMap(i -> Observable.from(i, -i)). //30, -30... 28 | map(Object::toString). 29 | subscribe(log::debug); 30 | } 31 | 32 | @Test 33 | public void range() throws InterruptedException { 34 | Observable.range(1, 100). 35 | map(i -> i * 10). 36 | filter(i -> i > 20). 37 | flatMap(i -> Observable.from(i, -i)). 38 | map(Object::toString). 39 | take(10). 40 | subscribe(log::debug); 41 | } 42 | 43 | @Test 44 | public void interval() throws Exception { 45 | Observable.interval(1, TimeUnit.SECONDS). 46 | map(i -> i * 10). 47 | flatMap(i -> Observable.from(i, -i)). 48 | map(Object::toString). 49 | subscribe(log::debug); 50 | 51 | TimeUnit.MINUTES.sleep(1); 52 | } 53 | 54 | @Test 55 | public void fromFunction() throws Exception { 56 | final Observable obs = Observable.create((Subscriber subscriber) -> { 57 | log.debug("Someone subscribed"); 58 | subscriber.onNext(1); 59 | subscriber.onNext(2); 60 | subscriber.onNext(3); 61 | subscriber.onCompleted(); 62 | }); 63 | 64 | obs.subscribe(i -> log.debug("" + i)); 65 | obs.subscribe(i -> log.debug("" + i)); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R43_ListeningTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import rx.Observable; 8 | 9 | import java.util.List; 10 | 11 | @Ignore 12 | public class R43_ListeningTest { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(R43_ListeningTest.class); 15 | 16 | @Test 17 | public void subscribe() throws Exception { 18 | Observable.from(1, 2, 3, 4, 5). 19 | map(i -> i * 10). 20 | map(Object::toString). 21 | subscribe(log::debug); 22 | } 23 | 24 | @Test 25 | public void advancedSubscribe() throws Exception { 26 | Observable.from(1, 2, 3, 4, 5). 27 | map(i -> i * 10). 28 | subscribe( 29 | (Integer i) -> log.debug("Int: {}", i), 30 | (Throwable t) -> log.error("Error", t), 31 | () -> log.debug("Done")); 32 | } 33 | 34 | @Test 35 | public void toList() throws Exception { 36 | final Observable from = Observable.from(1, 2, 3, 4, 5); 37 | final Observable> listObservable = from. 38 | map(i -> i * 10). 39 | toList(); 40 | listObservable.subscribe((List i) -> 41 | log.debug("All: {}", i)); 42 | } 43 | 44 | @Test 45 | public void blocking() throws Exception { 46 | Observable.from(1, 2, 3, 4, 5). 47 | map(i -> i * 10). 48 | toBlockingObservable(). 49 | forEach( 50 | i -> log.debug("Int: {}", i)); 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R45_FilteringTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.nurkiewicz.rxjava.util.HeartBeat; 4 | import com.nurkiewicz.rxjava.weather.Weather; 5 | import com.nurkiewicz.rxjava.weather.WeatherStation; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import rx.Observable; 11 | import rx.schedulers.TimeInterval; 12 | 13 | import java.util.concurrent.TimeUnit; 14 | 15 | @Ignore 16 | public class R45_FilteringTest { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(R45_FilteringTest.class); 19 | 20 | /** 21 | * sample/throttleFirst/throttleLast 22 | */ 23 | @Test 24 | public void sample() throws Exception { 25 | final Observable observable = WeatherStation.find("WAW").observations(); 26 | 27 | observable. 28 | sample(1, TimeUnit.SECONDS). 29 | map(Weather::getTemperature). 30 | take(10). 31 | toBlockingObservable(). 32 | forEach(p -> log.debug("" + p)); 33 | } 34 | 35 | @Test 36 | public void distinctUntilChanged() throws Exception { 37 | WeatherStation.find("WAW").observations(). 38 | map(w -> (int) w.getTemperature()). 39 | distinctUntilChanged(). 40 | map(Object::toString). 41 | toBlockingObservable(). 42 | forEach(log::debug); 43 | } 44 | 45 | @Test 46 | public void throttleWithTimeout() throws Exception { 47 | WeatherStation.find("WAW").observations(). 48 | throttleWithTimeout(1, TimeUnit.SECONDS). 49 | map(Weather::getTemperature). 50 | toBlockingObservable(). 51 | forEach(s -> log.debug("Temp: {}", s)); 52 | } 53 | 54 | @Test 55 | public void timeout() throws Exception { 56 | final Observable observable = HeartBeat.monitorServer("foo"); 57 | observable. 58 | timeout(1, TimeUnit.SECONDS). 59 | toBlockingObservable(). 60 | forEach(h -> log.debug("Heart beat: {}", h)); 61 | } 62 | 63 | @Test 64 | public void timeInterval() throws Exception { 65 | //given 66 | final Observable observable = HeartBeat.monitorServer("foo") 67 | .timeout(1, TimeUnit.SECONDS); 68 | 69 | //when 70 | final Observable> intervals = observable.timeInterval(); 71 | 72 | //then 73 | intervals.toBlockingObservable() 74 | .forEach((TimeInterval i) -> { 75 | log.debug("Since last {}ms", i.getIntervalInMilliseconds()); 76 | }); 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R46_ComposingTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.nurkiewicz.rxjava.weather.Weather; 5 | import com.nurkiewicz.rxjava.weather.WeatherStation; 6 | import org.junit.Ignore; 7 | import org.junit.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import rx.Observable; 11 | 12 | import java.util.List; 13 | 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | 16 | @Ignore 17 | public class R46_ComposingTest { 18 | 19 | private static final Logger log = LoggerFactory.getLogger(R46_ComposingTest.class); 20 | 21 | private final Observable warsaw = WeatherStation.find("WAW").observations(); 22 | private final Observable krakow = WeatherStation.find("KRA").observations(); 23 | 24 | @Test 25 | public void merge() throws Exception { 26 | Observable.merge(warsaw, krakow). 27 | map(w -> w.getStationId() + ":\t" + w.getTemperature()). 28 | take(100). 29 | toBlockingObservable(). 30 | forEach(log::debug); 31 | } 32 | 33 | @Test 34 | public void zip() throws Exception { 35 | final Observable averageTemp = Observable.zip( 36 | warsaw.map(Weather::getTemperature), 37 | krakow.map(Weather::getTemperature), 38 | (w, k) -> (w + k) / 2 39 | ); 40 | } 41 | 42 | @Test 43 | public void combineLatest() throws Exception { 44 | final Observable averageTemp = Observable.combineLatest( 45 | warsaw.map(Weather::getTemperature), 46 | krakow.map(Weather::getTemperature), 47 | (w, k) -> (w + k) / 2 48 | ); 49 | } 50 | 51 | @Test 52 | public void shouldConcatTwoStreams() throws Exception { 53 | //given 54 | final Observable first = Observable.from("A", "B", "C"); 55 | Observable second = Observable.range(0, 3).map(Object::toString); 56 | 57 | //when 58 | final Observable joined = Observable.concat(first, second); 59 | 60 | //then 61 | List joinedList = Lists.newArrayList( 62 | joined.toBlockingObservable().toIterable()); 63 | assertThat(joinedList).containsExactly("A", "B", "C", "0", "1", "2"); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R47_IndexingTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.nurkiewicz.rxjava.weather.Weather; 4 | import com.nurkiewicz.rxjava.weather.WeatherStation; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import rx.Observable; 10 | import rx.schedulers.Timestamped; 11 | 12 | import java.time.Instant; 13 | 14 | @Ignore 15 | public class R47_IndexingTest { 16 | 17 | private static final Logger log = LoggerFactory.getLogger(R47_IndexingTest.class); 18 | 19 | @Test 20 | public void timestamped() throws Exception { 21 | final Observable> waw = WeatherStation.find("WAW").observations(). 22 | timestamp(); 23 | waw. 24 | map((Timestamped stamped) -> 25 | Instant.ofEpochMilli(stamped.getTimestampMillis()) + "\t" + stamped.getValue().getTemperature()). 26 | take(100). 27 | toBlockingObservable(). 28 | forEach(log::debug); 29 | } 30 | 31 | @Test 32 | public void cache() throws Exception { 33 | final Observable cached = WeatherStation.find("WAW"). 34 | observations(). 35 | cache(); 36 | 37 | cached. 38 | timestamp(). 39 | map(t -> Instant.ofEpochMilli(t.getTimestampMillis()) + "\t" + t.getValue().getTemperature()). 40 | take(5). 41 | toBlockingObservable(). 42 | forEach(log::debug); 43 | 44 | cached. 45 | timestamp(). 46 | map(t -> Instant.ofEpochMilli(t.getTimestampMillis()) + "\t" + t.getValue().getTemperature()). 47 | take(5). 48 | toBlockingObservable(). 49 | forEach(log::debug); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R48_CompletableFutureAndObservable.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.nurkiewicz.java8.FutureOps; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | import rx.Observable; 7 | 8 | import java.util.List; 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.atomic.AtomicBoolean; 12 | 13 | import static com.jayway.awaitility.Awaitility.await; 14 | import static java.util.concurrent.TimeUnit.SECONDS; 15 | import static org.fest.assertions.api.Assertions.assertThat; 16 | import static org.fest.assertions.api.Assertions.failBecauseExceptionWasNotThrown; 17 | import static org.hamcrest.core.Is.is; 18 | 19 | @Ignore 20 | public class R48_CompletableFutureAndObservable { 21 | 22 | @Test 23 | public void shouldWrapAlreadyFinishedFutureIntoObservable() throws Exception { 24 | //given 25 | final CompletableFuture future = CompletableFuture.completedFuture("Foo"); 26 | 27 | //when 28 | final Observable observable = ObservableOps.toObservable(future); 29 | 30 | //then 31 | final Iterable resultOfFuture = observable.toBlockingObservable().toIterable(); 32 | assertThat(resultOfFuture).containsExactly("Foo"); 33 | } 34 | 35 | @Test 36 | public void shouldPropagateFutureExceptionIntoObservable() throws Exception { 37 | //given 38 | final CompletableFuture future = FutureOps.failed(new UnsupportedOperationException("Don't panic!")); 39 | 40 | //when 41 | final Observable observable = ObservableOps.toObservable(future); 42 | 43 | //then 44 | AtomicBoolean flag = new AtomicBoolean(); 45 | observable.subscribe(s -> {}, th -> flag.set(true)); 46 | await().atMost(1, SECONDS).untilAtomic(flag, is(true)); 47 | } 48 | 49 | @Test 50 | public void shouldTransformEmptyObservableToFutureWithEmptyList() throws Exception { 51 | //given 52 | final Observable observable = Observable.empty(); 53 | 54 | //when 55 | final CompletableFuture> future = ObservableOps.toCompletableFuture(observable); 56 | 57 | //then 58 | assertThat(future.get(1, SECONDS)).isEmpty(); 59 | } 60 | 61 | @Test 62 | public void shouldTransformObservableWithFewItemsToList() throws Exception { 63 | //given 64 | final Observable observable = Observable.from("A", "B"); 65 | 66 | //when 67 | final CompletableFuture> future = ObservableOps.toCompletableFuture(observable); 68 | 69 | //then 70 | assertThat(future.get(1, SECONDS)).containsExactly("A", "B"); 71 | } 72 | 73 | @Test 74 | public void shouldPropagateErrorFromObservable() throws Exception { 75 | //given 76 | final Observable observable = Observable.error(new UnsupportedOperationException("Don't panic!")); 77 | 78 | //when 79 | final CompletableFuture> future = ObservableOps.toCompletableFuture(observable); 80 | 81 | //then 82 | try { 83 | future.get(1, SECONDS); 84 | failBecauseExceptionWasNotThrown(ExecutionException.class); 85 | } catch (ExecutionException e) { 86 | assertThat(e.getCause()).hasMessageContaining("panic"); 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R49_TransformingTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import rx.Observable; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import static org.fest.assertions.api.Assertions.assertThat; 11 | 12 | @Ignore 13 | public class R49_TransformingTest { 14 | 15 | @Test 16 | public void shouldGroupItemsInBatchesOfSameSize() throws Exception { 17 | //given 18 | final Observable observable = Observable.range(1, 10); 19 | 20 | //when 21 | final Observable> grouped = null; //observable... 22 | 23 | //then 24 | final Iterable> groups = grouped.toBlockingObservable().toIterable(); 25 | assertThat(groups).containsExactly( 26 | Arrays.asList(1, 2, 3), 27 | Arrays.asList(4, 5, 6), 28 | Arrays.asList(7, 8, 9), 29 | Arrays.asList(10) 30 | ); 31 | } 32 | 33 | @Test 34 | public void shouldGenerateSlidingWindowOverItems() throws Exception { 35 | //given 36 | final Observable observable = Observable.range(1, 5); 37 | 38 | //when 39 | final Observable> grouped = null; //observable... 40 | 41 | //then 42 | final Iterable> groups = grouped.toBlockingObservable().toIterable(); 43 | 44 | groups.forEach(System.out::println); 45 | assertThat(groups).containsExactly( 46 | Arrays.asList(1, 2, 3), 47 | Arrays.asList(2, 3, 4), 48 | Arrays.asList(3, 4, 5), 49 | Arrays.asList(4, 5), 50 | Arrays.asList(5) 51 | ); 52 | } 53 | 54 | @Test 55 | public void shouldAccumulateValues() throws Exception { 56 | //given 57 | final Observable observable = Observable.range(1, 4); 58 | 59 | //when 60 | final Observable accumulated = null; //observable... 61 | 62 | //then 63 | final Iterable result = accumulated.toBlockingObservable().toIterable(); 64 | assertThat(result).containsExactly( 65 | 1, 66 | 1 + 2, 67 | 1 + 2 + 3, 68 | 1 + 2 + 3 + 4); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R50_OperatorsTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.google.common.collect.Lists; 4 | import org.junit.Ignore; 5 | import org.junit.Test; 6 | import rx.Observable; 7 | import rx.Subscriber; 8 | 9 | import java.util.List; 10 | import java.util.function.Predicate; 11 | 12 | import static org.fest.assertions.api.Assertions.assertThat; 13 | 14 | @Ignore 15 | public class R50_OperatorsTest { 16 | 17 | @Test 18 | public void shouldRejectItemsNotGreaterThanMaxSoFar() throws Exception { 19 | //given 20 | final Observable observable = Observable.from(1, 2, 3, 2, 5, 4, 7, 5, 6, 7, 8, 9, 5, 6, 9, 10, 9, 12); 21 | 22 | //when 23 | final Observable maxObservable = observable; //TODO 24 | 25 | //then 26 | final List filtered = Lists.newArrayList(maxObservable.toBlockingObservable().toIterable()); 27 | assertThat(filtered).containsExactly(1, 2, 3, 5, 7, 8, 9, 10, 12); 28 | } 29 | 30 | @Test 31 | public void shouldFilterUsingCustomOperator() throws Exception { 32 | final Observable observable = Observable.from(1, 2, 3, 2, 5, 4, 7, 5, 6, 7, 8, 9, 5, 6, 9, 10, 9, 12); 33 | 34 | //when 35 | final Observable maxObservable = observable.lift(myFilter(x -> x < 5)); 36 | 37 | //then 38 | final List filtered = Lists.newArrayList(maxObservable.toBlockingObservable().toIterable()); 39 | assertThat(filtered).containsExactly(1, 2, 3, 2, 4); 40 | } 41 | 42 | private Observable.Operator myFilter(Predicate predicate) { 43 | return new MyFilterOperator(predicate); 44 | } 45 | 46 | @Test 47 | public void shouldRejectItemsNotGreaterThanMaxSoFarUsingCustomOperator() throws Exception { 48 | //given 49 | final Observable observable = Observable.from(1, 2, 3, 2, 5, 4, 7, 5, 6, 7, 8, 9, 5, 6, 9, 10, 9, 12); 50 | 51 | //when 52 | final Observable maxObservable = observable.lift(onlyGreater()); 53 | 54 | //then 55 | final List filtered = Lists.newArrayList(maxObservable.toBlockingObservable().toIterable()); 56 | assertThat(filtered).containsExactly(1, 2, 3, 5, 7, 8, 9, 10, 12); 57 | } 58 | 59 | private Observable.Operator onlyGreater() { 60 | throw new UnsupportedOperationException("onlyGreater()"); 61 | } 62 | 63 | } 64 | 65 | class MyFilterOperator implements Observable.Operator { 66 | public MyFilterOperator(Predicate predicate) { 67 | } 68 | 69 | @Override 70 | public Subscriber call(Subscriber subscriber) { 71 | return new Subscriber() { 72 | @Override 73 | public void onCompleted() { 74 | subscriber.onCompleted(); 75 | } 76 | 77 | @Override 78 | public void onError(Throwable e) { 79 | subscriber.onError(e); 80 | } 81 | 82 | @Override 83 | public void onNext(Integer integer) { 84 | subscriber.onNext(integer); 85 | } 86 | }; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/R51_InfiniteObservableTest.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.nurkiewicz.rxjava.util.Indexed; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | import rx.Observable; 8 | 9 | import java.util.ArrayList; 10 | import java.util.function.UnaryOperator; 11 | import java.util.stream.Stream; 12 | 13 | import static com.nurkiewicz.rxjava.ObservableOps.withIndex; 14 | import static org.fest.assertions.api.Assertions.assertThat; 15 | 16 | /** 17 | *

Implement infinite Observable similar to {@link Stream#iterate(Object, UnaryOperator)} 18 | *

Use this stream to map from {@link Observable} of type T to {@link Observable} of type Indexed<T> 19 | *

Use custom Observable operator to implement Indexed<T> as well 20 | */ 21 | @Ignore 22 | public class R51_InfiniteObservableTest { 23 | 24 | @Test 25 | public void shouldCreateObservableByIteratingOverInitialElement() throws Exception { 26 | //given 27 | final Observable iterate = ObservableOps.iterate(1, x -> x * 2); 28 | 29 | //when 30 | final Observable stream = iterate.take(5); 31 | 32 | //then 33 | final ArrayList items = Lists.newArrayList(stream.toBlockingObservable().toIterable()); 34 | assertThat(items).containsExactly(1, 2, 4, 8, 16); 35 | } 36 | 37 | @Test 38 | public void shouldCreateInfiniteSequenceOfNaturalNumbers() throws Exception { 39 | //given 40 | final Observable iterate = ObservableOps.iterate("", s -> s + "*"); 41 | 42 | //when 43 | final Observable stream = iterate.take(5); 44 | 45 | //then 46 | final ArrayList items = Lists.newArrayList(stream.toBlockingObservable().toIterable()); 47 | assertThat(items).containsExactly("", "*", "**", "***", "****"); 48 | } 49 | 50 | @Test 51 | public void shouldGenerateNaturalNumbers() throws Exception { 52 | //given 53 | final Observable naturals = ObservableOps.naturals(); 54 | 55 | //when 56 | Observable stream = naturals.take(5); 57 | 58 | //then 59 | final ArrayList items = Lists.newArrayList(stream.toBlockingObservable().toIterable()); 60 | assertThat(items).containsExactly(0, 1, 2, 3, 4); 61 | } 62 | 63 | @Test 64 | public void shouldSkipFirstThousandNaturalNumbersAndThenSkipEven() throws Exception { 65 | //given 66 | final Observable naturals = ObservableOps.naturals(); 67 | 68 | //when 69 | final Observable stream = naturals 70 | //TODO 71 | .take(5); 72 | 73 | //then 74 | final ArrayList items = Lists.newArrayList(stream.toBlockingObservable().toIterable()); 75 | assertThat(items).containsExactly(1000, 1002, 1004, 1006, 1008); 76 | } 77 | 78 | @Test 79 | public void shouldIndexInputStream() throws Exception { 80 | //given 81 | final Observable input = Observable.from("A", "B", "C"); 82 | 83 | //when 84 | final Observable> indexed = ObservableOps.index(input); 85 | final Observable joined = indexed.map(i -> i.getValue() + ":" + i.getIndex()); 86 | 87 | //then 88 | final ArrayList items = Lists.newArrayList(joined.toBlockingObservable().toIterable()); 89 | assertThat(items).containsExactly("A:0", "B:1", "C:2"); 90 | } 91 | 92 | @Test 93 | public void shouldIndexInputSequencyByApplyingCustomOperator() throws Exception { 94 | //given 95 | final Observable infinite = Observable.from("X", "Y", "Z").repeat(); 96 | 97 | //when 98 | final Observable> indexed = infinite.lift(withIndex()); 99 | final Observable joined = indexed.map(i -> i.getValue() + ":" + i.getIndex()).take(7); 100 | 101 | //then 102 | final ArrayList items = Lists.newArrayList(joined.toBlockingObservable().toIterable()); 103 | assertThat(items).containsExactly("X:0", "Y:1", "Z:2", "X:3", "Y:4", "Z:5", "X:6"); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/util/HeartBeat.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava.util; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import rx.Observable; 7 | import rx.subscriptions.Subscriptions; 8 | 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.concurrent.atomic.AtomicInteger; 11 | 12 | public class HeartBeat { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(HeartBeat.class); 15 | 16 | private static final AtomicInteger COUNTER = new AtomicInteger(); 17 | 18 | private final int id = COUNTER.incrementAndGet(); 19 | 20 | public static Observable monitorServer(String name) { 21 | return Observable.create((Observable.OnSubscribe)subscriber -> { 22 | Thread t = new Thread("HeartBeat") { 23 | @Override 24 | public void run() { 25 | for (int i = 1; i <= 20; ++i) { 26 | try { 27 | TimeUnit.MILLISECONDS.sleep(i * 100); 28 | subscriber.onNext(new HeartBeat()); 29 | } catch (InterruptedException e) { 30 | log.warn("Interrupted"); 31 | } 32 | } 33 | } 34 | }; 35 | t.setDaemon(true); 36 | t.start(); 37 | subscriber.add(Subscriptions.create(t::interrupt)); 38 | }); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "HeartBeat{id=" + id + '}'; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/weather/Weather.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava.weather; 2 | 3 | import com.google.common.base.Objects; 4 | 5 | public class Weather { 6 | 7 | private final String stationId; 8 | private final float temperature; 9 | private final float wind; 10 | private final float humidity; 11 | 12 | public Weather(String stationId, float temperature, float wind, float humidity) { 13 | this.stationId = stationId; 14 | this.temperature = temperature; 15 | this.wind = wind; 16 | this.humidity = humidity; 17 | } 18 | 19 | public String getStationId() { 20 | return stationId; 21 | } 22 | 23 | public float getTemperature() { 24 | return temperature; 25 | } 26 | 27 | public float getWind() { 28 | return wind; 29 | } 30 | 31 | public float getHumidity() { 32 | return humidity; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return Objects.toStringHelper(this). 38 | add("stationId", stationId). 39 | add("temperature", temperature). 40 | add("wind", wind). 41 | add("humidity", humidity). 42 | toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/weather/WeatherStation.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava.weather; 2 | 3 | import rx.Observable; 4 | 5 | import java.util.concurrent.CompletableFuture; 6 | import java.util.function.Consumer; 7 | 8 | public interface WeatherStation { 9 | 10 | static WeatherStation find(String stationId) { 11 | return new WeatherStationStub(stationId); 12 | } 13 | 14 | Weather getLast(); 15 | 16 | Weather waitForNext(); 17 | 18 | CompletableFuture next(); 19 | 20 | void listen(Consumer consumer); 21 | 22 | javax.jms.ConnectionFactory jmsConnection(); 23 | 24 | Observable observations(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/com/nurkiewicz/rxjava/weather/WeatherStationStub.java: -------------------------------------------------------------------------------- 1 | package com.nurkiewicz.rxjava.weather; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import rx.Observable; 6 | import rx.Observer; 7 | import rx.Subscriber; 8 | import rx.subscriptions.Subscriptions; 9 | 10 | import javax.jms.ConnectionFactory; 11 | import java.util.Random; 12 | import java.util.concurrent.CompletableFuture; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.ScheduledExecutorService; 15 | import java.util.concurrent.TimeUnit; 16 | import java.util.function.Consumer; 17 | 18 | public class WeatherStationStub implements WeatherStation { 19 | 20 | private static final Logger log = LoggerFactory.getLogger(WeatherStationStub.class); 21 | 22 | private final Random random = new Random(); 23 | 24 | private final long createdTime = System.currentTimeMillis(); 25 | 26 | private final String id; 27 | 28 | private final float updatesPerMinute = 30 + random.nextInt(60); 29 | 30 | public WeatherStationStub(String id) { 31 | this.id = id; 32 | } 33 | 34 | @Override 35 | public Weather getLast() { 36 | throw new UnsupportedOperationException(); 37 | } 38 | 39 | @Override 40 | public Weather waitForNext() { 41 | throw new UnsupportedOperationException(); 42 | } 43 | 44 | @Override 45 | public CompletableFuture next() { 46 | throw new UnsupportedOperationException(); 47 | } 48 | 49 | @Override 50 | public void listen(Consumer consumer) { 51 | throw new UnsupportedOperationException(); 52 | } 53 | 54 | @Override 55 | public ConnectionFactory jmsConnection() { 56 | throw new UnsupportedOperationException(); 57 | } 58 | 59 | @Override 60 | public Observable observations() { 61 | log.debug("Bulding Observable"); 62 | return Observable.create((Subscriber subscriber) -> { 63 | log.debug("Subscribed to Observable"); 64 | final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); 65 | scheduleRandomly(subscriber, executor); 66 | subscriber.add(Subscriptions.create(() -> { 67 | log.debug("Unsubscribing"); 68 | executor.shutdownNow(); 69 | })); 70 | }); 71 | } 72 | 73 | private void scheduleRandomly(Observer subscriber, ScheduledExecutorService executor) { 74 | executor.schedule(() -> { 75 | subscriber.onNext(randomWeather()); 76 | scheduleRandomly(subscriber, executor); 77 | }, (int) gaussian(60_000.0f / updatesPerMinute, 500.0f), TimeUnit.MILLISECONDS); 78 | } 79 | 80 | private float gaussian(float expected, float stdDev) { 81 | return (float) (expected + random.nextGaussian() * stdDev); 82 | } 83 | 84 | private Weather randomWeather() { 85 | final double cycle = (((System.currentTimeMillis() - createdTime) % 30_000) / 30_000f) * Math.PI * 2; 86 | final float expectedTemperature = (float) (10 + Math.sin(cycle) * 10); 87 | return new Weather(id, gaussian(expectedTemperature, 1), gaussian(5, 2), gaussian(60, 5)); 88 | } 89 | } 90 | --------------------------------------------------------------------------------