├── .gitignore ├── _config.yml ├── basics.md ├── readme.md └── src ├── Algorithms ├── BFS.java ├── BinarySearch.java ├── DFS.java ├── MergeSortDemo.java ├── QuickSortDemo.java └── SequentialSort.java ├── Datastructures ├── ArrayDemo.java ├── BinarySearchTree.java ├── BinaryTree.java ├── Graph.java ├── LRUCacheDemo.java ├── LinkedListDemo.java ├── Node.java ├── QueueDemo.java ├── StackDemo.java ├── TreeNode.java ├── Trie.java └── TrieNode.java ├── DateTime └── LocalDateTimeDemo.java ├── Leetcode ├── BinaryTreeLevelOrder.java ├── ClimbStairs.java ├── ConcatStringStream.java ├── FizzBuzz.java ├── InvertTree.java ├── LinkedListRandomPtr.java ├── MaximumPathSum.java ├── MinStack.java ├── MoveZeroesDemo.java ├── NumberOfIslands.java ├── Power.java ├── RandomDemo.java ├── SpiralDemo.java └── TwoSum.java └── test └── DateTime └── LocalDateTimeTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | 3 | # Compiled class file 4 | *.class 5 | 6 | # Log file 7 | *.log 8 | 9 | # BlueJ files 10 | *.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | # Built application files 27 | *.apk 28 | *.ap_ 29 | 30 | # Files for the ART/Dalvik VM 31 | *.dex 32 | 33 | 34 | # Generated files 35 | bin/ 36 | gen/ 37 | out/ 38 | 39 | # Gradle files 40 | .gradle/ 41 | build/ 42 | 43 | # Local configuration file (sdk path, etc) 44 | local.properties 45 | 46 | # Proguard folder generated by Eclipse 47 | proguard/ 48 | 49 | 50 | # Android Studio Navigation editor temp files 51 | .navigation/ 52 | 53 | # Android Studio captures folder 54 | captures/ 55 | 56 | # Intellij 57 | *.iml 58 | .idea/workspace.xml 59 | 60 | # Keystore files 61 | *.jks 62 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /basics.md: -------------------------------------------------------------------------------- 1 | # Java 2 | 3 | ## Datatypes 4 | 5 | - Identifiers 6 | - Assignment 7 | - Datatypes 8 | - boolean 9 | - byte - 8 bit 10 | - short - 16 11 | - int - 32 12 | - octal - starts with 0 13 | - long - 64L 14 | - hexadeximal - starts with 0x 15 | - float - 32 F or f 16 | - double - 64 17 | - infinity, NAN 18 | - char literals - 16 (0-65536) - ASCII 19 | 20 | ### Strings 21 | 22 | String literals - Char Sequence 23 | 24 | - concat using + 25 | - equals() - check object equality 26 | - == checks for reference equality 27 | 28 | 29 | ### String Builder 30 | 31 | ``` 32 | public static void main(String[] args) { 33 | 34 | // Create an empty StringBuffer 35 | StringBuilder sb = new StringBuilder(); 36 | printDetails(sb); 37 | 38 | // Append "good" 39 | sb.append("good"); 40 | printDetails(sb); 41 | 42 | // Insert "Hi " in the beginning 43 | sb.insert(0, "Hi "); 44 | printDetails(sb); 45 | 46 | // Delete the first o 47 | sb.deleteCharAt(1); 48 | printDetails(sb); 49 | 50 | // Append " be with you" 51 | sb.append(" be with you"); 52 | printDetails(sb); 53 | 54 | // Set the length to 3 55 | sb.setLength(3); 56 | printDetails(sb); 57 | 58 | // Reverse the content 59 | sb.reverse(); 60 | printDetails(sb); 61 | } 62 | 63 | ``` 64 | 65 | 66 | ### Arrays 67 | 68 | - `int[] myIntArray; or int myIntArray[];` 69 | - `int a1[] = new int[3]; or int[] a2 = new int[3];` 70 | - `arrayName.length` 71 | - `int[] primes = {2, 3, 5, 7, 11, 13, 17}; // An array of 7 elements ` 72 | - Indexing - `primes[2] // 5` 73 | - `int twoD[][] = new int[4][5];` 74 | 75 | ``` 76 | for (i = 0; i < 5; i++) 77 | result = result + nums[i]; 78 | ``` 79 | 80 | ``` 81 | int days[] = {1, 2, 3,}; 82 | for(int i:days){ 83 | System.out.println(i); 84 | } 85 | ``` 86 | 87 | ``` 88 | int twoD[][] = new int[4][5]; 89 | for (int i = 0; i < 4; i++) { 90 | for (int j = 0; j < 5; j++) { 91 | twoD[i][j] = i*j; 92 | } 93 | } 94 | ``` 95 | 96 | ``` 97 | int nums[][] = new int[3][5]; 98 | 99 | // give nums some values 100 | for (int i = 0; i < 3; i++) 101 | for (int j = 0; j < 5; j++) 102 | nums[i][j] = (i + 1) * (j + 1); 103 | 104 | // use for-each for to display and sum the values 105 | for (int x[] : nums) { 106 | for (int y : x) { 107 | System.out.println("Value is: " + y); 108 | sum += y; 109 | } 110 | } 111 | ``` 112 | 113 | ``` 114 | double m[][] = { 115 | { 0, 1, 2, 3 }, 116 | { 0, 1, 2, 3 }, 117 | { 0, 1, 2, 3 }, 118 | { 0, 1, 2, 3 } 119 | }; 120 | ``` 121 | 122 | ##### Array Declaration 123 | 124 | ``` 125 | // salary can hold multiple float values 126 | float[] salary; 127 | 128 | // name can hold multiple references to String objects 129 | String[] name; 130 | 131 | // emp can hold multiple references to Employee objects 132 | Employee[] emp; 133 | ``` 134 | 135 | ##### Array Creation 136 | 137 | ``` 138 | 139 | // Create an array object 140 | int[] myID = new int[5]; 141 | ``` 142 | 143 | ##### Explicit Array Initialization 144 | 145 | ``` 146 | // Initialize the array at the time of declaration 147 | int[] myID = {1, 2, 3, 4, 5}; 148 | 149 | // A comma after the last value 5 is valid. 150 | int[] myID = {1, 2, 3, 4, 5, }; 151 | 152 | // Also valid 153 | int[] myID = new int[]{1, 2, 3, 4, 5}; 154 | 155 | String[] names = {new String("A"), new String("B")}; 156 | 157 | String[] names = {"C", "D"}; 158 | 159 | ``` 160 | 161 | ##### Length of an Array 162 | 163 | ``` 164 | int[] myID = new int[5]; // Create an array of length 5 165 | int len = myID.length; // 5 will be assigned to len 166 | ``` 167 | 168 | ##### Copy an Array 169 | 170 | ``` 171 | public static void arraycopy(Object sourceArray, 172 | int sourceStartPosition, 173 | Object destinationArray, 174 | int destinationStartPosition, 175 | int lengthToBeCopied) 176 | 177 | Called as: System.arraycopy (sourse, 0, dest, 0, noofelementsToCopy); 178 | ``` 179 | 180 | 181 | 182 | ### Increment and Decrement 183 | 184 | - `x = x + 1; or x++; ` 185 | 186 | | Initial Value of x | Expression | Final Value of y | Final Value of x | 187 | | --- | --- | --- | --- | 188 | |5| y = x++| 5 |6 | 189 | |5 |y = ++x| 6 | 6 | 190 | |5 |y = x--| 5 | 4 | 191 | |5 |y = --x| 4| 4 | 192 | 193 | ### Java Logical Operators Shortcut 194 | 195 | The OR operator results in true when one operand is true, no matter what the second operand is. The AND operator results in false when one operand is false, no matter what the second operand is. If you use the || and &&, Java will not evaluate the right-hand operand when the outcome can be determined by the left operand alone. 196 | 197 | ### If - else 198 | 199 | ``` 200 | if(condition) 201 | statement; 202 | else if(condition) 203 | statement; 204 | else if(condition) 205 | statement; 206 | . 207 | . 208 | else 209 | statement; 210 | ``` 211 | 212 | ### Switch 213 | 214 | ``` 215 | switch (expression) { 216 | case value1: 217 | statement sequence 218 | break; 219 | case value2: 220 | statement sequence 221 | break; 222 | . 223 | . 224 | . 225 | case valueN: 226 | statement sequence 227 | break; 228 | default: 229 | default statement sequence 230 | } 231 | ``` 232 | 233 | ### Class 234 | 235 | A class in Java may consist of five components: 236 | 237 | * Fields 238 | * Methods 239 | * Constructors 240 | * Static initializers 241 | * Instance initializers 242 | 243 | Fields and methods are also known as members of the class. 244 | 245 | Classes and interfaces can also be members of a class. 246 | 247 | A class can have zero or more class members. 248 | 249 | Constructors are used to create objects of a class. We must have at least one constructor for a class. 250 | 251 | Initializers are used to initialize fields of a class. We can have zero or more initializers of static or instance types. 252 | 253 | ### Static and Instance methods 254 | 255 | ``` 256 | // A static or class method 257 | static void aClassMethod() { 258 | 259 | } 260 | 261 | Called as: Classname.aClassMethod() 262 | 263 | // A non-static or instance method 264 | void anInstanceMethod() { 265 | 266 | } 267 | 268 | Called as: Instancename.anInstanceMethod() 269 | ``` 270 | 271 | ### This 272 | 273 | Java has a keyword called this. It is a reference to the current instance of a class. 274 | 275 | It can be used only in the context of an instance. 276 | 277 | ### Initialization Block 278 | 279 | - An instance initialization block is used to initialize objects of a class. - Once for every instance 280 | 281 | - A static initialization block is also known as a static initializer. It is similar to an instance initialization block. It is used to initialize a class. An instance initializer is executed once per object whereas a static initializer is executed only once for a class when the class definition is loaded into JVM. 282 | 283 | ``` 284 | public class Main { 285 | private static int num; 286 | 287 | // An instance initializer 288 | { 289 | System.out.println("Inside instance initializer."); 290 | } 291 | 292 | // A static initializer. Note the use of the keyword static below. 293 | static { 294 | num = 2014; 295 | System.out.println("Inside static initializer."); 296 | } 297 | 298 | // Constructor 299 | public Main() { 300 | System.out.println("Inside constructor."); 301 | } 302 | } 303 | 304 | ``` 305 | 306 | 307 | ### Immutable objects 308 | 309 | An object whose state cannot be changed after it is created is called an immutable object. 310 | 311 | A class whose objects are immutable is called an immutable class. 312 | 313 | An immutable object can be shared by different areas of a program without worrying about its state changes. 314 | 315 | An immutable object is inherently thread-safe. 316 | 317 | ``` 318 | // Immutable class for int 319 | public class IntWrapper { 320 | private final int value; 321 | 322 | public IntWrapper(int value) { 323 | this.value = value; 324 | } 325 | public int getValue() { 326 | return value; 327 | } 328 | } 329 | 330 | >> IntWrapper wrapper = new IntWrapper(101); 331 | 332 | ``` 333 | 334 | 335 | ``` 336 | class Box { 337 | int width; 338 | int height; 339 | int depth; 340 | } 341 | public class Main { 342 | public static void main(String args[]) { 343 | Box myBox = new Box(); 344 | myBox.width = 10; 345 | 346 | System.out.println("myBox.width:"+myBox.width); 347 | } 348 | } 349 | ``` 350 | - object instanceof class 351 | 352 | 353 | ### Methods and constructors 354 | 355 | ``` 356 | class Box { 357 | int width; 358 | int height; 359 | int depth; 360 | 361 | Box(Box ob) { // pass object to constructor 362 | width = ob.width; 363 | height = ob.height; 364 | } 365 | 366 | Box(int w, int h) { 367 | width = w; 368 | height = h; 369 | } 370 | 371 | // constructor used when no dimensions specified 372 | Box() { 373 | width = -1; // use -1 to indicate 374 | height = -1; // an uninitialized 375 | } 376 | 377 | // initialize a and b to the same value 378 | Box(int i) { 379 | this(i, i); // invokes Box(i, i) 380 | } 381 | 382 | // constructor used when cube is created 383 | Box(int len) { 384 | width = height = len; 385 | } 386 | 387 | void setDim(int w, int h) { // Method with parameters 388 | width = w; 389 | height = h; 390 | } 391 | 392 | int calculateVolume() { 393 | return width * height * depth; 394 | } 395 | } 396 | 397 | public class Main { 398 | 399 | public static void main(String args[]) { 400 | Box mybox1 = new Box(); 401 | mybox1.width = 10; 402 | mybox1.height = 20; 403 | mybox1.depth = 15; 404 | 405 | int vol = mybox1.calculateVolume(); 406 | 407 | } 408 | } 409 | ``` 410 | 411 | ### Testing 412 | 413 | Test suite knows more about the code than us in the long run 414 | 415 | #### 10 rules for writing great testcases 416 | 417 | 418 | 419 | ### Annotations 420 | 421 | A retention policy determines at what point an annotation is discarded. 422 | 423 | Java defines three such policies:SOURCE, CLASS, and RUNTIME. 424 | 425 | SOURCE is retained only in the source file and is discarded during compilation. 426 | CLASS is stored in the .class file during compilation. It is not available through the JVM during run time. 427 | RUNTIME is stored in the .class file and is available through the JVM during run time. 428 | 429 | **Built-In Annotations** 430 | 431 | Java defines many built-in annotations. Most are specialized, but seven are general purpose. 432 | 433 | * @Retention 434 | * @Documented 435 | * @Target 436 | * @Inherited 437 | * @Override 438 | * @Deprecated 439 | * @SuppressWarnings 440 | 441 | 442 | ### Collection 443 | 444 | ``` 445 | 446 | public class CollectionsDemo { 447 | 448 | public static void main(String[] args) { 449 | 450 | List arrayList = new ArrayList<>(); 451 | 452 | List linkedList = new LinkedList<>(); 453 | 454 | Iterator alIterator = arrayList.iterator(); 455 | 456 | ListIterator stringIterator = linkedList.listIterator(); 457 | 458 | HashSet integerHashSet = new HashSet<>(); 459 | 460 | HashSet linkedHashSet = new LinkedHashSet<>(); 461 | 462 | TreeSet stringTreeSet = new TreeSet<>(); 463 | 464 | Queue queue = new LinkedList<>(); 465 | 466 | Queue priorityQueue = new PriorityQueue(); 467 | 468 | Deque deque = new ArrayDeque<>(); 469 | 470 | // one null keys, multiple null vals 471 | HashMap stringHashMap = new HashMap<>(); 472 | 473 | // one null keys, multiple null vals 474 | HashMap intHashMap = new LinkedHashMap<>(); 475 | 476 | // No null keys 477 | TreeMap intTreeMap = new TreeMap<>(); 478 | 479 | stringHashMap.put("Naren", "Manoharan"); 480 | stringHashMap.put("Shri", "Manoharan"); 481 | stringHashMap.put(null, "HEllo"); 482 | 483 | stringHashMap.entrySet() 484 | .stream() 485 | .forEach(entry -> System.out.println("Key: " + entry.getKey() + " " + "Val: " + entry.getValue())); 486 | 487 | 488 | // No null keys or vals 489 | Hashtable hashtable = new Hashtable(); 490 | 491 | } 492 | 493 | } 494 | 495 | ``` 496 | 497 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Java 8 2 | 3 | [![codebeat badge](https://codebeat.co/badges/d2a74038-4494-414a-a76a-aa226bb3f416)](https://codebeat.co/projects/github-com-narenkmanoharan-java-cheatsheet-master) 4 | 5 | * [Default Methods for Interfaces](#default-methods-for-interfaces) 6 | * [Lambda expressions](#lambda-expressions) 7 | * [Functional Interfaces](#functional-interfaces) 8 | * [Method and Constructor References](#method-and-constructor-references) 9 | * [Lambda Scopes](#lambda-scopes) 10 | * [Accessing local variables](#accessing-local-variables) 11 | * [Accessing fields and static variables](#accessing-fields-and-static-variables) 12 | * [Accessing Default Interface Methods](#accessing-default-interface-methods) 13 | * [Built-in Functional Interfaces](#built-in-functional-interfaces) 14 | * [Predicates](#predicates) 15 | * [Functions](#functions) 16 | * [Suppliers](#suppliers) 17 | * [Consumers](#consumers) 18 | * [Comparators](#comparators) 19 | * [Optionals](#optionals) 20 | * [Streams](#streams) 21 | * [Filter](#filter) 22 | * [Sorted](#sorted) 23 | * [Map](#map) 24 | * [Match](#match) 25 | * [Count](#count) 26 | * [Reduce](#reduce) 27 | * [Parallel Streams](#parallel-streams) 28 | * [Sequential Sort](#sequential-sort) 29 | * [Parallel Sort](#parallel-sort) 30 | * [Maps](#maps) 31 | * [Date API](#date-api) 32 | * [Clock](#clock) 33 | * [Timezones](#timezones) 34 | * [LocalTime](#localtime) 35 | * [LocalDate](#localdate) 36 | * [LocalDateTime](#localdatetime) 37 | * [Annotations](#annotations) 38 | * [Where to go from here?](#where-to-go-from-here) 39 | 40 | ## Default Methods for Interfaces 41 | 42 | Java 8 enables us to add non-abstract method implementations to interfaces by utilizing the `default` keyword. This feature is also known as [virtual extension methods](http://stackoverflow.com/a/24102730). 43 | 44 | Here is our first example: 45 | 46 | ```java 47 | interface Formula { 48 | double calculate(int a); 49 | 50 | default double sqrt(int a) { 51 | return Math.sqrt(a); 52 | } 53 | } 54 | ``` 55 | 56 | Besides the abstract method `calculate` the interface `Formula` also defines the default method `sqrt`. Concrete classes only have to implement the abstract method `calculate`. The default method `sqrt` can be used out of the box. 57 | 58 | ```java 59 | Formula formula = new Formula() { 60 | @Override 61 | public double calculate(int a) { 62 | return sqrt(a * 100); 63 | } 64 | }; 65 | 66 | formula.calculate(100); // 100.0 67 | formula.sqrt(16); // 4.0 68 | ``` 69 | 70 | The formula is implemented as an anonymous object. The code is quite verbose: 6 lines of code for such a simple calculation of `sqrt(a * 100)`. As we'll see in the next section, there's a much nicer way of implementing single method objects in Java 8. 71 | 72 | 73 | ## Lambda expressions 74 | 75 | Let's start with a simple example of how to sort a list of strings in prior versions of Java: 76 | 77 | ```java 78 | List names = Arrays.asList("peter", "anna", "mike", "xenia"); 79 | 80 | Collections.sort(names, new Comparator() { 81 | @Override 82 | public int compare(String a, String b) { 83 | return b.compareTo(a); 84 | } 85 | }); 86 | ``` 87 | 88 | The static utility method `Collections.sort` accepts a list and a comparator in order to sort the elements of the given list. You often find yourself creating anonymous comparators and pass them to the sort method. 89 | 90 | Instead of creating anonymous objects all day long, Java 8 comes with a much shorter syntax, **lambda expressions**: 91 | 92 | ```java 93 | Collections.sort(names, (String a, String b) -> { 94 | return b.compareTo(a); 95 | }); 96 | ``` 97 | 98 | As you can see the code is much shorter and easier to read. But it gets even shorter: 99 | 100 | ```java 101 | Collections.sort(names, (String a, String b) -> b.compareTo(a)); 102 | ``` 103 | 104 | For one line method bodies you can skip both the braces `{}` and the `return` keyword. But it gets even shorter: 105 | 106 | ```java 107 | names.sort((a, b) -> b.compareTo(a)); 108 | ``` 109 | 110 | List now has a `sort` method. Also the java compiler is aware of the parameter types so you can skip them as well. Let's dive deeper into how lambda expressions can be used in the wild. 111 | 112 | 113 | ## Functional Interfaces 114 | 115 | How does lambda expressions fit into Java's type system? Each lambda corresponds to a given type, specified by an interface. A so called _functional interface_ must contain **exactly one abstract method** declaration. Each lambda expression of that type will be matched to this abstract method. Since default methods are not abstract you're free to add default methods to your functional interface. 116 | 117 | We can use arbitrary interfaces as lambda expressions as long as the interface only contains one abstract method. To ensure that your interface meet the requirements, you should add the `@FunctionalInterface` annotation. The compiler is aware of this annotation and throws a compiler error as soon as you try to add a second abstract method declaration to the interface. 118 | 119 | Example: 120 | 121 | ```java 122 | @FunctionalInterface 123 | interface Converter { 124 | T convert(F from); 125 | } 126 | ``` 127 | 128 | ```java 129 | Converter converter = (from) -> Integer.valueOf(from); 130 | Integer converted = converter.convert("123"); 131 | System.out.println(converted); // 123 132 | ``` 133 | 134 | Keep in mind that the code is also valid if the `@FunctionalInterface` annotation would be omitted. 135 | 136 | 137 | ## Method and Constructor References 138 | 139 | The above example code can be further simplified by utilizing static method references: 140 | 141 | ```java 142 | Converter converter = Integer::valueOf; 143 | Integer converted = converter.convert("123"); 144 | System.out.println(converted); // 123 145 | ``` 146 | 147 | Java 8 enables you to pass references of methods or constructors via the `::` keyword. The above example shows how to reference a static method. But we can also reference object methods: 148 | 149 | ```java 150 | class Something { 151 | String startsWith(String s) { 152 | return String.valueOf(s.charAt(0)); 153 | } 154 | } 155 | ``` 156 | 157 | ```java 158 | Something something = new Something(); 159 | Converter converter = something::startsWith; 160 | String converted = converter.convert("Java"); 161 | System.out.println(converted); // "J" 162 | ``` 163 | 164 | Let's see how the `::` keyword works for constructors. First we define an example class with different constructors: 165 | 166 | ```java 167 | class Person { 168 | String firstName; 169 | String lastName; 170 | 171 | Person() {} 172 | 173 | Person(String firstName, String lastName) { 174 | this.firstName = firstName; 175 | this.lastName = lastName; 176 | } 177 | } 178 | ``` 179 | 180 | Next we specify a person factory interface to be used for creating new persons: 181 | 182 | ```java 183 | interface PersonFactory

{ 184 | P create(String firstName, String lastName); 185 | } 186 | ``` 187 | 188 | Instead of implementing the factory manually, we glue everything together via constructor references: 189 | 190 | ```java 191 | PersonFactory personFactory = Person::new; 192 | Person person = personFactory.create("Peter", "Parker"); 193 | ``` 194 | 195 | We create a reference to the Person constructor via `Person::new`. The Java compiler automatically chooses the right constructor by matching the signature of `PersonFactory.create`. 196 | 197 | ## Lambda Scopes 198 | 199 | Accessing outer scope variables from lambda expressions is very similar to anonymous objects. You can access final variables from the local outer scope as well as instance fields and static variables. 200 | 201 | ### Accessing local variables 202 | 203 | We can read final local variables from the outer scope of lambda expressions: 204 | 205 | ```java 206 | final int num = 1; 207 | Converter stringConverter = 208 | (from) -> String.valueOf(from + num); 209 | 210 | stringConverter.convert(2); // 3 211 | ``` 212 | 213 | But different to anonymous objects the variable `num` does not have to be declared final. This code is also valid: 214 | 215 | ```java 216 | int num = 1; 217 | Converter stringConverter = 218 | (from) -> String.valueOf(from + num); 219 | 220 | stringConverter.convert(2); // 3 221 | ``` 222 | 223 | However `num` must be implicitly final for the code to compile. The following code does **not** compile: 224 | 225 | ```java 226 | int num = 1; 227 | Converter stringConverter = 228 | (from) -> String.valueOf(from + num); 229 | num = 3; 230 | ``` 231 | 232 | Writing to `num` from within the lambda expression is also prohibited. 233 | 234 | ### Accessing fields and static variables 235 | 236 | In contrast to local variables, we have both read and write access to instance fields and static variables from within lambda expressions. This behaviour is well known from anonymous objects. 237 | 238 | ```java 239 | class Lambda4 { 240 | static int outerStaticNum; 241 | int outerNum; 242 | 243 | void testScopes() { 244 | Converter stringConverter1 = (from) -> { 245 | outerNum = 23; 246 | return String.valueOf(from); 247 | }; 248 | 249 | Converter stringConverter2 = (from) -> { 250 | outerStaticNum = 72; 251 | return String.valueOf(from); 252 | }; 253 | } 254 | } 255 | ``` 256 | 257 | ### Accessing Default Interface Methods 258 | 259 | Remember the formula example from the first section? Interface `Formula` defines a default method `sqrt` which can be accessed from each formula instance including anonymous objects. This does not work with lambda expressions. 260 | 261 | Default methods **cannot** be accessed from within lambda expressions. The following code does not compile: 262 | 263 | ```java 264 | Formula formula = (a) -> sqrt(a * 100); 265 | ``` 266 | 267 | 268 | ## Built-in Functional Interfaces 269 | 270 | The JDK 1.8 API contains many built-in functional interfaces. Some of them are well known from older versions of Java like `Comparator` or `Runnable`. Those existing interfaces are extended to enable Lambda support via the `@FunctionalInterface` annotation. 271 | 272 | But the Java 8 API is also full of new functional interfaces to make your life easier. Some of those new interfaces are well known from the [Google Guava](https://code.google.com/p/guava-libraries/) library. Even if you're familiar with this library you should keep a close eye on how those interfaces are extended by some useful method extensions. 273 | 274 | ### Predicates 275 | 276 | Predicates are boolean-valued functions of one argument. The interface contains various default methods for composing predicates to complex logical terms (and, or, negate) 277 | 278 | ```java 279 | Predicate predicate = (s) -> s.length() > 0; 280 | 281 | predicate.test("foo"); // true 282 | predicate.negate().test("foo"); // false 283 | 284 | Predicate nonNull = Objects::nonNull; 285 | Predicate isNull = Objects::isNull; 286 | 287 | Predicate isEmpty = String::isEmpty; 288 | Predicate isNotEmpty = isEmpty.negate(); 289 | ``` 290 | 291 | ### Functions 292 | 293 | Functions accept one argument and produce a result. Default methods can be used to chain multiple functions together (compose, andThen). 294 | 295 | ```java 296 | Function toInteger = Integer::valueOf; 297 | Function backToString = toInteger.andThen(String::valueOf); 298 | 299 | backToString.apply("123"); // "123" 300 | ``` 301 | 302 | ### Suppliers 303 | 304 | Suppliers produce a result of a given generic type. Unlike Functions, Suppliers don't accept arguments. 305 | 306 | ```java 307 | Supplier personSupplier = Person::new; 308 | personSupplier.get(); // new Person 309 | ``` 310 | 311 | ### Consumers 312 | 313 | Consumers represent operations to be performed on a single input argument. 314 | 315 | ```java 316 | Consumer greeter = (p) -> System.out.println("Hello, " + p.firstName); 317 | greeter.accept(new Person("Luke", "Skywalker")); 318 | ``` 319 | 320 | ### Comparators 321 | 322 | Comparators are well known from older versions of Java. Java 8 adds various default methods to the interface. 323 | 324 | ```java 325 | Comparator comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName); 326 | 327 | Person p1 = new Person("John", "Doe"); 328 | Person p2 = new Person("Alice", "Wonderland"); 329 | 330 | comparator.compare(p1, p2); // > 0 331 | comparator.reversed().compare(p1, p2); // < 0 332 | ``` 333 | 334 | ## Optionals 335 | 336 | Optionals are not functional interfaces, but nifty utilities to prevent `NullPointerException`. It's an important concept for the next section, so let's have a quick look at how Optionals work. 337 | 338 | Optional is a simple container for a value which may be null or non-null. Think of a method which may return a non-null result but sometimes return nothing. Instead of returning `null` you return an `Optional` in Java 8. 339 | 340 | ```java 341 | Optional optional = Optional.of("bam"); 342 | 343 | optional.isPresent(); // true 344 | optional.get(); // "bam" 345 | optional.orElse("fallback"); // "bam" 346 | 347 | optional.ifPresent((s) -> System.out.println(s.charAt(0))); // "b" 348 | ``` 349 | 350 | ## Streams 351 | 352 | A `java.util.Stream` represents a sequence of elements on which one or more operations can be performed. Stream operations are either _intermediate_ or _terminal_. While terminal operations return a result of a certain type, intermediate operations return the stream itself so you can chain multiple method calls in a row. Streams are created on a source, e.g. a `java.util.Collection` like lists or sets (maps are not supported). Stream operations can either be executed sequentially or parallely. 353 | 354 | > Streams are extremely powerful, so I wrote a separate [Java 8 Streams Tutorial](http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/). You should also check out [Stream.js](https://github.com/winterbe/streamjs), a JavaScript port of the Java 8 Streams API. 355 | 356 | Let's first look how sequential streams work. First we create a sample source in form of a list of strings: 357 | 358 | ```java 359 | List stringCollection = new ArrayList<>(); 360 | stringCollection.add("ddd2"); 361 | stringCollection.add("aaa2"); 362 | stringCollection.add("bbb1"); 363 | stringCollection.add("aaa1"); 364 | stringCollection.add("bbb3"); 365 | stringCollection.add("ccc"); 366 | stringCollection.add("bbb2"); 367 | stringCollection.add("ddd1"); 368 | ``` 369 | 370 | Collections in Java 8 are extended so you can simply create streams either by calling `Collection.stream()` or `Collection.parallelStream()`. The following sections explain the most common stream operations. 371 | 372 | ### Filter 373 | 374 | Filter accepts a predicate to filter all elements of the stream. This operation is _intermediate_ which enables us to call another stream operation (`forEach`) on the result. ForEach accepts a consumer to be executed for each element in the filtered stream. ForEach is a terminal operation. It's `void`, so we cannot call another stream operation. 375 | 376 | ```java 377 | stringCollection 378 | .stream() 379 | .filter((s) -> s.startsWith("a")) 380 | .forEach(System.out::println); 381 | 382 | // "aaa2", "aaa1" 383 | ``` 384 | 385 | ### Sorted 386 | 387 | Sorted is an _intermediate_ operation which returns a sorted view of the stream. The elements are sorted in natural order unless you pass a custom `Comparator`. 388 | 389 | ```java 390 | stringCollection 391 | .stream() 392 | .sorted() 393 | .filter((s) -> s.startsWith("a")) 394 | .forEach(System.out::println); 395 | 396 | // "aaa1", "aaa2" 397 | ``` 398 | 399 | Keep in mind that `sorted` does only create a sorted view of the stream without manipulating the ordering of the backed collection. The ordering of `stringCollection` is untouched: 400 | 401 | ```java 402 | System.out.println(stringCollection); 403 | // ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1 404 | ``` 405 | 406 | ### Map 407 | 408 | The _intermediate_ operation `map` converts each element into another object via the given function. The following example converts each string into an upper-cased string. But you can also use `map` to transform each object into another type. The generic type of the resulting stream depends on the generic type of the function you pass to `map`. 409 | 410 | ```java 411 | stringCollection 412 | .stream() 413 | .map(String::toUpperCase) 414 | .sorted((a, b) -> b.compareTo(a)) 415 | .forEach(System.out::println); 416 | 417 | // "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1" 418 | ``` 419 | 420 | ### Match 421 | 422 | Various matching operations can be used to check whether a certain predicate matches the stream. All of those operations are _terminal_ and return a boolean result. 423 | 424 | ```java 425 | boolean anyStartsWithA = 426 | stringCollection 427 | .stream() 428 | .anyMatch((s) -> s.startsWith("a")); 429 | 430 | System.out.println(anyStartsWithA); // true 431 | 432 | boolean allStartsWithA = 433 | stringCollection 434 | .stream() 435 | .allMatch((s) -> s.startsWith("a")); 436 | 437 | System.out.println(allStartsWithA); // false 438 | 439 | boolean noneStartsWithZ = 440 | stringCollection 441 | .stream() 442 | .noneMatch((s) -> s.startsWith("z")); 443 | 444 | System.out.println(noneStartsWithZ); // true 445 | ``` 446 | 447 | #### Count 448 | 449 | Count is a _terminal_ operation returning the number of elements in the stream as a `long`. 450 | 451 | ```java 452 | long startsWithB = 453 | stringCollection 454 | .stream() 455 | .filter((s) -> s.startsWith("b")) 456 | .count(); 457 | 458 | System.out.println(startsWithB); // 3 459 | ``` 460 | 461 | 462 | ### Reduce 463 | 464 | This _terminal_ operation performs a reduction on the elements of the stream with the given function. The result is an `Optional` holding the reduced value. 465 | 466 | ```java 467 | Optional reduced = 468 | stringCollection 469 | .stream() 470 | .sorted() 471 | .reduce((s1, s2) -> s1 + "#" + s2); 472 | 473 | reduced.ifPresent(System.out::println); 474 | // "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2" 475 | ``` 476 | 477 | ## Parallel Streams 478 | 479 | As mentioned above streams can be either sequential or parallel. Operations on sequential streams are performed on a single thread while operations on parallel streams are performed concurrently on multiple threads. 480 | 481 | The following example demonstrates how easy it is to increase the performance by using parallel streams. 482 | 483 | First we create a large list of unique elements: 484 | 485 | ```java 486 | int max = 1000000; 487 | List values = new ArrayList<>(max); 488 | for (int i = 0; i < max; i++) { 489 | UUID uuid = UUID.randomUUID(); 490 | values.add(uuid.toString()); 491 | } 492 | ``` 493 | 494 | Now we measure the time it takes to sort a stream of this collection. 495 | 496 | ### Sequential Sort 497 | 498 | ```java 499 | long t0 = System.nanoTime(); 500 | 501 | long count = values.stream().sorted().count(); 502 | System.out.println(count); 503 | 504 | long t1 = System.nanoTime(); 505 | 506 | long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); 507 | System.out.println(String.format("sequential sort took: %d ms", millis)); 508 | 509 | // sequential sort took: 899 ms 510 | ``` 511 | 512 | ### Parallel Sort 513 | 514 | ```java 515 | long t0 = System.nanoTime(); 516 | 517 | long count = values.parallelStream().sorted().count(); 518 | System.out.println(count); 519 | 520 | long t1 = System.nanoTime(); 521 | 522 | long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0); 523 | System.out.println(String.format("parallel sort took: %d ms", millis)); 524 | 525 | // parallel sort took: 472 ms 526 | ``` 527 | 528 | As you can see both code snippets are almost identical but the parallel sort is roughly 50% faster. All you have to do is change `stream()` to `parallelStream()`. 529 | 530 | ## Maps 531 | 532 | As already mentioned maps do not directly support streams. There's no `stream()` method available on the `Map` interface itself, however you can create specialized streams upon the keys, values or entries of a map via `map.keySet().stream()`, `map.values().stream()` and `map.entrySet().stream()`. 533 | 534 | Furthermore maps support various new and useful methods for doing common tasks. 535 | 536 | ```java 537 | Map map = new HashMap<>(); 538 | 539 | for (int i = 0; i < 10; i++) { 540 | map.putIfAbsent(i, "val" + i); 541 | } 542 | 543 | map.forEach((id, val) -> System.out.println(val)); 544 | ``` 545 | 546 | The above code should be self-explaining: `putIfAbsent` prevents us from writing additional if null checks; `forEach` accepts a consumer to perform operations for each value of the map. 547 | 548 | This example shows how to compute code on the map by utilizing functions: 549 | 550 | ```java 551 | map.computeIfPresent(3, (num, val) -> val + num); 552 | map.get(3); // val33 553 | 554 | map.computeIfPresent(9, (num, val) -> null); 555 | map.containsKey(9); // false 556 | 557 | map.computeIfAbsent(23, num -> "val" + num); 558 | map.containsKey(23); // true 559 | 560 | map.computeIfAbsent(3, num -> "bam"); 561 | map.get(3); // val33 562 | ``` 563 | 564 | Next, we learn how to remove entries for a given key, only if it's currently mapped to a given value: 565 | 566 | ```java 567 | map.remove(3, "val3"); 568 | map.get(3); // val33 569 | 570 | map.remove(3, "val33"); 571 | map.get(3); // null 572 | ``` 573 | 574 | Another helpful method: 575 | 576 | ```java 577 | map.getOrDefault(42, "not found"); // not found 578 | ``` 579 | 580 | Merging entries of a map is quite easy: 581 | 582 | ```java 583 | map.merge(9, "val9", (value, newValue) -> value.concat(newValue)); 584 | map.get(9); // val9 585 | 586 | map.merge(9, "concat", (value, newValue) -> value.concat(newValue)); 587 | map.get(9); // val9concat 588 | ``` 589 | 590 | Merge either put the key/value into the map if no entry for the key exists, or the merging function will be called to change the existing value. 591 | 592 | 593 | ## Date API 594 | 595 | Java 8 contains a brand new date and time API under the package `java.time`. The new Date API is comparable with the [Joda-Time](http://www.joda.org/joda-time/) library, however it's [not the same](http://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html). The following examples cover the most important parts of this new API. 596 | 597 | ### Clock 598 | 599 | Clock provides access to the current date and time. Clocks are aware of a timezone and may be used instead of `System.currentTimeMillis()` to retrieve the current time in milliseconds since Unix EPOCH. Such an instantaneous point on the time-line is also represented by the class `Instant`. Instants can be used to create legacy `java.util.Date` objects. 600 | 601 | ```java 602 | Clock clock = Clock.systemDefaultZone(); 603 | long millis = clock.millis(); 604 | 605 | Instant instant = clock.instant(); 606 | Date legacyDate = Date.from(instant); // legacy java.util.Date 607 | ``` 608 | 609 | ### Timezones 610 | 611 | Timezones are represented by a `ZoneId`. They can easily be accessed via static factory methods. Timezones define the offsets which are important to convert between instants and local dates and times. 612 | 613 | ```java 614 | System.out.println(ZoneId.getAvailableZoneIds()); 615 | // prints all available timezone ids 616 | 617 | ZoneId zone1 = ZoneId.of("Europe/Berlin"); 618 | ZoneId zone2 = ZoneId.of("Brazil/East"); 619 | System.out.println(zone1.getRules()); 620 | System.out.println(zone2.getRules()); 621 | 622 | // ZoneRules[currentStandardOffset=+01:00] 623 | // ZoneRules[currentStandardOffset=-03:00] 624 | ``` 625 | 626 | ### LocalTime 627 | 628 | LocalTime represents a time without a timezone, e.g. 10pm or 17:30:15. The following example creates two local times for the timezones defined above. Then we compare both times and calculate the difference in hours and minutes between both times. 629 | 630 | ```java 631 | LocalTime now1 = LocalTime.now(zone1); 632 | LocalTime now2 = LocalTime.now(zone2); 633 | 634 | System.out.println(now1.isBefore(now2)); // false 635 | 636 | long hoursBetween = ChronoUnit.HOURS.between(now1, now2); 637 | long minutesBetween = ChronoUnit.MINUTES.between(now1, now2); 638 | 639 | System.out.println(hoursBetween); // -3 640 | System.out.println(minutesBetween); // -239 641 | ``` 642 | 643 | LocalTime comes with various factory methods to simplify the creation of new instances, including parsing of time strings. 644 | 645 | ```java 646 | LocalTime late = LocalTime.of(23, 59, 59); 647 | System.out.println(late); // 23:59:59 648 | 649 | DateTimeFormatter germanFormatter = 650 | DateTimeFormatter 651 | .ofLocalizedTime(FormatStyle.SHORT) 652 | .withLocale(Locale.GERMAN); 653 | 654 | LocalTime leetTime = LocalTime.parse("13:37", germanFormatter); 655 | System.out.println(leetTime); // 13:37 656 | ``` 657 | 658 | ### LocalDate 659 | 660 | LocalDate represents a distinct date, e.g. 2014-03-11. It's immutable and works exactly analog to LocalTime. The sample demonstrates how to calculate new dates by adding or subtracting days, months or years. Keep in mind that each manipulation returns a new instance. 661 | 662 | ```java 663 | LocalDate today = LocalDate.now(); 664 | LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS); 665 | LocalDate yesterday = tomorrow.minusDays(2); 666 | 667 | LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4); 668 | DayOfWeek dayOfWeek = independenceDay.getDayOfWeek(); 669 | System.out.println(dayOfWeek); // FRIDAY 670 | ``` 671 | 672 | Parsing a LocalDate from a string is just as simple as parsing a LocalTime: 673 | 674 | ```java 675 | DateTimeFormatter germanFormatter = 676 | DateTimeFormatter 677 | .ofLocalizedDate(FormatStyle.MEDIUM) 678 | .withLocale(Locale.GERMAN); 679 | 680 | LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter); 681 | System.out.println(xmas); // 2014-12-24 682 | ``` 683 | 684 | ### LocalDateTime 685 | 686 | LocalDateTime represents a date-time. It combines date and time as seen in the above sections into one instance. `LocalDateTime` is immutable and works similar to LocalTime and LocalDate. We can utilize methods for retrieving certain fields from a date-time: 687 | 688 | ```java 689 | LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59); 690 | 691 | DayOfWeek dayOfWeek = sylvester.getDayOfWeek(); 692 | System.out.println(dayOfWeek); // WEDNESDAY 693 | 694 | Month month = sylvester.getMonth(); 695 | System.out.println(month); // DECEMBER 696 | 697 | long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY); 698 | System.out.println(minuteOfDay); // 1439 699 | ``` 700 | 701 | With the additional information of a timezone it can be converted to an instant. Instants can easily be converted to legacy dates of type `java.util.Date`. 702 | 703 | ```java 704 | Instant instant = sylvester 705 | .atZone(ZoneId.systemDefault()) 706 | .toInstant(); 707 | 708 | Date legacyDate = Date.from(instant); 709 | System.out.println(legacyDate); // Wed Dec 31 23:59:59 CET 2014 710 | ``` 711 | 712 | Formatting date-times works just like formatting dates or times. Instead of using pre-defined formats we can create formatters from custom patterns. 713 | 714 | ```java 715 | DateTimeFormatter formatter = 716 | DateTimeFormatter 717 | .ofPattern("MMM dd, yyyy - HH:mm"); 718 | 719 | LocalDateTime parsed = LocalDateTime.parse("Nov 03, 2014 - 07:13", formatter); 720 | String string = formatter.format(parsed); 721 | System.out.println(string); // Nov 03, 2014 - 07:13 722 | ``` 723 | 724 | Unlike `java.text.NumberFormat` the new `DateTimeFormatter` is immutable and **thread-safe**. 725 | 726 | For details on the pattern syntax read [here](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html). 727 | 728 | 729 | ## Annotations 730 | 731 | Annotations in Java 8 are repeatable. Let's dive directly into an example to figure that out. 732 | 733 | First, we define a wrapper annotation which holds an array of the actual annotations: 734 | 735 | ```java 736 | @interface Hints { 737 | Hint[] value(); 738 | } 739 | 740 | @Repeatable(Hints.class) 741 | @interface Hint { 742 | String value(); 743 | } 744 | ``` 745 | Java 8 enables us to use multiple annotations of the same type by declaring the annotation `@Repeatable`. 746 | 747 | ### Variant 1: Using the container annotation (old school) 748 | 749 | ```java 750 | @Hints({@Hint("hint1"), @Hint("hint2")}) 751 | class Person {} 752 | ``` 753 | 754 | ### Variant 2: Using repeatable annotations (new school) 755 | 756 | ```java 757 | @Hint("hint1") 758 | @Hint("hint2") 759 | class Person {} 760 | ``` 761 | 762 | Using variant 2 the java compiler implicitly sets up the `@Hints` annotation under the hood. That's important for reading annotation information via reflection. 763 | 764 | ```java 765 | Hint hint = Person.class.getAnnotation(Hint.class); 766 | System.out.println(hint); // null 767 | 768 | Hints hints1 = Person.class.getAnnotation(Hints.class); 769 | System.out.println(hints1.value().length); // 2 770 | 771 | Hint[] hints2 = Person.class.getAnnotationsByType(Hint.class); 772 | System.out.println(hints2.length); // 2 773 | ``` 774 | 775 | Although we never declared the `@Hints` annotation on the `Person` class, it's still readable via `getAnnotation(Hints.class)`. However, the more convenient method is `getAnnotationsByType` which grants direct access to all annotated `@Hint` annotations. 776 | 777 | 778 | Furthermore the usage of annotations in Java 8 is expanded to two new targets: 779 | 780 | ```java 781 | @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 782 | @interface MyAnnotation {} 783 | ``` 784 | 785 | ## Where to go from here? 786 | 787 | If you want to learn more about all the new classes and features of the JDK 8 API, check out my [JDK8 API Explorer](http://winterbe.com/projects/java8-explorer/). It helps you figuring out all the new classes and hidden gems of JDK 8, like `Arrays.parallelSort`, `StampedLock` and `CompletableFuture` - just to name a few. 788 | 789 | - [Java 8 Stream Tutorial](http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/) 790 | - [Java 8 Concurrency Tutorial: Threads and Executors](http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/) 791 | - [Java 8 Concurrency Tutorial: Synchronization and Locks](http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/) 792 | - [Java 8 Concurrency Tutorial: Atomic Variables and ConcurrentMap](http://winterbe.com/posts/2015/05/22/java8-concurrency-tutorial-atomic-concurrent-map-examples/) 793 | - [Java 8 API by Example: Strings, Numbers, Math and Files](http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/) 794 | - [Avoid Null Checks in Java 8](http://winterbe.com/posts/2015/03/15/avoid-null-checks-in-java/) 795 | - [Fixing Java 8 Stream Gotchas with IntelliJ IDEA](http://winterbe.com/posts/2015/03/05/fixing-java-8-stream-gotchas-with-intellij-idea/) 796 | 797 | 798 | # RxJava 2.x 799 | 800 | ## Contents 801 | 802 | - [Flowable, Single and Observable](#flowable) 803 | - [Simple Operators](#simple-operators) 804 | - [Merging Streams](#merging-streams) 805 | - [Hot Publishers](#hot-publishers) 806 | - [Schedulers](#schedulers) 807 | - [FlatMap Operator](#flatmap-operator) 808 | - [Error Handling](#error-handling) 809 | - [Backpressure](#backpressure) 810 | - [Articles and books](#articles) 811 | 812 | ## Reactive Streams 813 | Reactive Streams is a programming concept for handling asynchronous 814 | data streams in a non-blocking manner while providing backpressure to stream publishers. 815 | It has evolved into a [specification](https://github.com/reactive-streams/reactive-streams-jvm) that is based on the concept of **Publisher<T>** and **Subscriber<T>**. 816 | A **Publisher** is the source of events **T** in the stream, and a **Subscriber** is the consumer for those events. 817 | A **Subscriber** subscribes to a **Publisher** by invoking a "factory method" in the Publisher that will push 818 | the stream items **<T>** starting a new **Subscription**: 819 | 820 | ```java 821 | public interface Publisher { 822 | public void subscribe(Subscriber s); 823 | } 824 | ``` 825 | 826 | When the Subscriber is ready to start handling events, it signals this via a **request** to that **Subscription** 827 | 828 | ```java 829 | public interface Subscription { 830 | public void request(long n); //request n items 831 | public void cancel(); 832 | } 833 | ``` 834 | 835 | Upon receiving this signal, the Publisher begins to invoke **Subscriber::onNext(T)** for each event **T**. 836 | This continues until either completion of the stream (**Subscriber::onComplete()**) 837 | or an error occurs during processing (**Subscriber::onError(Throwable)**). 838 | 839 | ```java 840 | public interface Subscriber { 841 | //signals to the Publisher to start sending events 842 | public void onSubscribe(Subscription s); 843 | 844 | public void onNext(T t); 845 | public void onError(Throwable t); 846 | public void onComplete(); 847 | } 848 | ``` 849 | 850 | ## Flowable and Observable 851 | RxJava provides more types of event publishers: 852 | - **Flowable** Publisher that emits 0..N elements, and then completes successfully or with an error 853 | - **Observable** like Flowables but without a backpressure strategy. They were introduced in RxJava 1.x 854 | 855 | - **Single** a specialized emitter that completes with a value successfully either an error.(doesn't have onComplete callback, instead onSuccess(val)) 856 | - **Maybe** a specialized emitter that can complete with / without a value or complete with an error. 857 | - **Completable** a specialized emitter that just signals if it completed successfully or with an error. 858 | 859 | Code is available at [Part01CreateFlowable.java](https://github.com/balamaci/rxjava-playground/blob/master/src/test/java/com/balamaci/rx/Part01CreateFlowable.java) 860 | 861 | ### Simple operators to create Streams 862 | ```java 863 | Flowable flowable = Flowable.just(1, 5, 10); 864 | Flowable flowable = Flowable.range(1, 10); 865 | Flowable flowable = Flowable.fromArray(new String[] {"red", "green", "blue"}); 866 | Flowable flowable = Flowable.fromIterable(List.of("red", "green", "blue")); 867 | ``` 868 | 869 | 870 | ### Flowable from Future 871 | 872 | ```java 873 | CompletableFuture completableFuture = CompletableFuture 874 | .supplyAsync(() -> { //starts a background thread the ForkJoin common pool 875 | log.info("CompletableFuture work starts"); 876 | Helpers.sleepMillis(100); 877 | return "red"; 878 | }); 879 | 880 | Single observable = Single.from(completableFuture); 881 | single.subscribe(val -> log.info("Stream completed successfully : {}", val)); 882 | ``` 883 | 884 | 885 | ### Creating your own stream 886 | 887 | We can use **Flowable.create(...)** to implement the emissions of events by calling **onNext(val)**, **onComplete()**, **onError(throwable)** 888 | 889 | When subscribing to the Observable / Flowable with flowable.subscribe(...) the lambda code inside **create(...)** gets executed. 890 | Flowable.subscribe(...) can take 3 handlers for each type of event - onNext, onError and onCompleted. 891 | 892 | When using **Observable.create(...)** you need to be aware of [backpressure](#backpressure) and that Observables created with 'create' are not BackPressure aware 893 | 894 | ```java 895 | Observable stream = Observable.create(subscriber -> { 896 | log.info("Started emitting"); 897 | 898 | log.info("Emitting 1st"); 899 | subscriber.onNext(1); 900 | 901 | log.info("Emitting 2nd"); 902 | subscriber.onNext(2); 903 | 904 | subscriber.onComplete(); 905 | }); 906 | 907 | //Flowable version same Observable but with a BackpressureStrategy 908 | //that will be discussed separately. 909 | Flowable stream = Flowable.create(subscriber -> { 910 | log.info("Started emitting"); 911 | 912 | log.info("Emitting 1st"); 913 | subscriber.onNext(1); 914 | 915 | log.info("Emitting 2nd"); 916 | subscriber.onNext(2); 917 | 918 | subscriber.onComplete(); 919 | }, BackpressureStrategy.MISSING); 920 | 921 | stream.subscribe( 922 | val -> log.info("Subscriber received: {}", val), 923 | err -> log.error("Subscriber received error", err), 924 | () -> log.info("Subscriber got Completed event") 925 | ); 926 | ``` 927 | 928 | ### Streams are lazy 929 | Streams are lazy meaning that the code inside create() doesn't get executed without subscribing to the stream. 930 | So event if we sleep for a long time inside create() method(to simulate a costly operation), 931 | without subscribing to this Observable, the code is not executed and the method returns immediately. 932 | 933 | ```java 934 | public void observablesAreLazy() { 935 | Observable observable = Observable.create(subscriber -> { 936 | log.info("Started emitting but sleeping for 5 secs"); //this is not executed 937 | Helpers.sleepMillis(5000); 938 | subscriber.onNext(1); 939 | }); 940 | log.info("Finished"); 941 | } 942 | =========== 943 | [main] - Finished 944 | ``` 945 | 946 | ### Multiple subscriptions to the same Observable / Flowable 947 | When subscribing to an Observable/Flowable, the create() method gets executed for each Subscriber, the events 948 | inside **create(..)** are re-emitted to each subscriber independently. 949 | 950 | So every subscriber will get the same events and will not lose any events - this behavior is named **'cold observable'** 951 | See [Hot Publishers](#hot-publisher) to understand sharing a subscription and multicasting events. 952 | 953 | ```java 954 | Observable observable = Observable.create(subscriber -> { 955 | log.info("Started emitting"); 956 | 957 | log.info("Emitting 1st event"); 958 | subscriber.onNext(1); 959 | 960 | log.info("Emitting 2nd event"); 961 | subscriber.onNext(2); 962 | 963 | subscriber.onComplete(); 964 | }); 965 | 966 | log.info("Subscribing 1st subscriber"); 967 | observable.subscribe(val -> log.info("First Subscriber received: {}", val)); 968 | 969 | log.info("======================="); 970 | 971 | log.info("Subscribing 2nd subscriber"); 972 | observable.subscribe(val -> log.info("Second Subscriber received: {}", val)); 973 | ``` 974 | 975 | will output 976 | 977 | ``` 978 | [main] - Subscribing 1st subscriber 979 | [main] - Started emitting 980 | [main] - Emitting 1st event 981 | [main] - First Subscriber received: 1 982 | [main] - Emitting 2nd event 983 | [main] - First Subscriber received: 2 984 | [main] - ======================= 985 | [main] - Subscribing 2nd subscriber 986 | [main] - Started emitting 987 | [main] - Emitting 1st event 988 | [main] - Second Subscriber received: 1 989 | [main] - Emitting 2nd event 990 | [main] - Second Subscriber received: 2 991 | ``` 992 | 993 | ## Observable / Flowable lifecycle 994 | 995 | ### Operators 996 | Between the source Observable / Flowable and the Subscriber there can be a wide range of operators and RxJava provides 997 | lots of operators to chose from. Probably you are already familiar with functional operations like **filter** and **map**. 998 | so let's use them as example: 999 | 1000 | ```java 1001 | Flowable stream = Flowable.create(subscriber -> { 1002 | subscriber.onNext(1); 1003 | subscriber.onNext(2); 1004 | .... 1005 | subscriber.onComplete(); 1006 | }, BackpressureStrategy.MISSING); 1007 | .filter(val -> val < 10) 1008 | .map(val -> val * 10) 1009 | .subscribe(val -> log.info("Received: {}", val)); 1010 | ``` 1011 | 1012 | When we call _Flowable.create()_ you might think that we're calling onNext(..), onComplete(..) on the Subscriber at the end of the chain, 1013 | not the operators between them. 1014 | 1015 | This is not true because **the operators themselves are decorators for their source** wrapping it with the operator behavior 1016 | like an onion's layers. 1017 | When we call **.subscribe()** at the end of the chain, **Subscription propagates through the layers back to the source, 1018 | each operator subscribing itself to it's wrapped source Observable / Flowable and so on to the original source, 1019 | triggering it to start producing/emitting items**. 1020 | 1021 | **Flowable.create** calls **---> filterOperator.onNext(val)** which if val > 10 calls **---> 1022 | mapOperator.onNext(val)** does val = val * 10 and calls **---> subscriber.onNext(val)**. 1023 | 1024 | [Found](https://tomstechnicalblog.blogspot.ro/2015_10_01_archive.html) a nice analogy with a team of house movers, with every mover doing it's thing before passing it to the next in line 1025 | until it reaches the final subscriber. 1026 | 1027 | ![Movers](https://1.bp.blogspot.com/-1RuGVz4-U9Q/VjT0AsfiiUI/AAAAAAAAAKQ/xWQaOwNtS7o/s1600/animation_2.gif) 1028 | 1029 | ### Canceling subscription 1030 | Inside the create() method, we can check is there are still active subscribers to our Flowable/Observable. 1031 | 1032 | There are operators that also unsubscribe from the stream so the source knows to stop producing events. 1033 | It's a way to prevent to do extra work(like for ex. querying a datasource for entries) if no one is listening 1034 | In the following example we'd expect to have an infinite stream, but because we stop if there are no active subscribers, we stop producing events. 1035 | 1036 | **take(limit)** is a simple operator. It's role is to count the number of events and then unsubscribes from it's source 1037 | once it received the specified amount and calls onComplete() to it's subscriber. 1038 | 1039 | ```java 1040 | Observable observable = Observable.create(subscriber -> { 1041 | 1042 | int i = 1; 1043 | while(true) { 1044 | if(subscriber.isDisposed()) { 1045 | break; 1046 | } 1047 | 1048 | subscriber.onNext(i++); 1049 | 1050 | //registering a callback when the downstream subscriber unsubscribes 1051 | subscriber.setCancellable(() -> log.info("Subscription canceled")); 1052 | } 1053 | }); 1054 | 1055 | observable 1056 | .take(5) //unsubscribes after the 5th event 1057 | .subscribe(val -> log.info("Subscriber received: {}", val), 1058 | err -> log.error("Subscriber received error", err), 1059 | () -> log.info("Subscriber got Completed event") //The Complete event 1060 | //is triggered by 'take()' operator 1061 | 1062 | ================== 1063 | [main] - Subscriber received: *1* 1064 | [main] - Subscriber received: *2* 1065 | [main] - Subscriber received: *3* 1066 | [main] - Subscriber received: *4* 1067 | [main] - Subscriber received: *5* 1068 | [main] - Subscriber got Completed event 1069 | [main] - Subscription canceled 1070 | ``` 1071 | 1072 | 1073 | ## Simple Operators 1074 | Code is available at [Part02SimpleOperators.java](https://github.com/balamaci/rxjava-playground/blob/master/src/test/java/com/balamaci/rx/Part02SimpleOperators.java) 1075 | 1076 | ### delay 1077 | Delay operator - the Thread.sleep of the reactive world, it's pausing each emission for a particular increment of time. 1078 | 1079 | ```java 1080 | CountDownLatch latch = new CountDownLatch(1); 1081 | Flowable.range(0, 2) 1082 | .doOnNext(val -> log.info("Emitted {}", val)) 1083 | .delay(5, TimeUnit.SECONDS) 1084 | .subscribe(tick -> log.info("Tick {}", tick), 1085 | (ex) -> log.info("Error emitted"), 1086 | () -> { 1087 | log.info("Completed"); 1088 | latch.countDown(); 1089 | }); 1090 | latch.await(); 1091 | 1092 | ============== 1093 | 14:27:44 [main] - Starting 1094 | 14:27:45 [main] - Emitted 0 1095 | 14:27:45 [main] - Emitted 1 1096 | 14:27:50 [RxComputationThreadPool-1] - Tick 0 1097 | 14:27:50 [RxComputationThreadPool-1] - Tick 1 1098 | 14:27:50 [RxComputationThreadPool-1] - Completed 1099 | ``` 1100 | 1101 | The **.delay()**, **.interval()** operators uses a [Scheduler](#schedulers) by default which is why we see it executing 1102 | on a different thread _RxComputationThreadPool-1_ which actually means it's running the operators and the subscribe operations 1103 | on another thread and so the test method will terminate before we see the text from the log unless we wait for the completion of the stream. 1104 | 1105 | 1106 | ### interval 1107 | Periodically emits a number starting from 0 and then increasing the value on each emission. 1108 | 1109 | ```java 1110 | log.info("Starting"); 1111 | Flowable.interval(5, TimeUnit.SECONDS) 1112 | .take(4) 1113 | .subscribe(tick -> log.info("Subscriber received {}", tick), 1114 | (ex) -> log.info("Error emitted"), 1115 | () -> log.info("Subscriber got Completed event")); 1116 | 1117 | ========== 1118 | 12:17:56 [main] - Starting 1119 | 12:18:01 [RxComputationThreadPool-1] - Subscriber received: 0 1120 | 12:18:06 [RxComputationThreadPool-1] - Subscriber received: 1 1121 | 12:18:11 [RxComputationThreadPool-1] - Subscriber received: 2 1122 | 12:18:16 [RxComputationThreadPool-1] - Subscriber received: 3 1123 | 12:18:21 [RxComputationThreadPool-1] - Subscriber received: 4 1124 | 12:18:21 [RxComputationThreadPool-1] - Subscriber got Completed event 1125 | ``` 1126 | 1127 | 1128 | 1129 | ### scan 1130 | Takes an **initial value** and a **function(accumulator, currentValue)**. It goes through the events 1131 | sequence and combines the current event value with the previous result(accumulator) emitting downstream the function's 1132 | result for each event(the initial value is used for the first event) 1133 | 1134 | ```java 1135 | Flowable numbers = 1136 | Flowable.just(3, 5, -2, 9) 1137 | .scan(0, (totalSoFar, currentValue) -> { 1138 | log.info("TotalSoFar={}, currentValue={}", 1139 | totalSoFar, currentValue); 1140 | return totalSoFar + currentValue; 1141 | }); 1142 | 1143 | ============= 1144 | 16:09:17 [main] - Subscriber received: 0 1145 | 16:09:17 [main] - TotalSoFar=0, currentValue=3 1146 | 16:09:17 [main] - Subscriber received: 3 1147 | 16:09:17 [main] - TotalSoFar=3, currentValue=5 1148 | 16:09:17 [main] - Subscriber received: 8 1149 | 16:09:17 [main] - TotalSoFar=8, currentValue=-2 1150 | 16:09:17 [main] - Subscriber received: 6 1151 | 16:09:17 [main] - TotalSoFar=6, currentValue=9 1152 | 16:09:17 [main] - Subscriber received: 15 1153 | 16:09:17 [main] - Subscriber got Completed event 1154 | ``` 1155 | 1156 | ### reduce 1157 | reduce operator acts like the scan operator but it only passes downstream the final result 1158 | (doesn't pass the intermediate results downstream) so the subscriber receives just one event 1159 | 1160 | ```java 1161 | Flowable numbers = Flowable.just(3, 5, -2, 9) 1162 | .reduce(0, (totalSoFar, val) -> { 1163 | log.info("totalSoFar={}, emitted={}", 1164 | totalSoFar, val); 1165 | return totalSoFar + val; 1166 | }); 1167 | 1168 | ============= 1169 | 17:08:29 [main] - totalSoFar=0, emitted=3 1170 | 17:08:29 [main] - totalSoFar=3, emitted=5 1171 | 17:08:29 [main] - totalSoFar=8, emitted=-2 1172 | 17:08:29 [main] - totalSoFar=6, emitted=9 1173 | 17:08:29 [main] - Subscriber received: 15 1174 | 17:08:29 [main] - Subscriber got Completed event 1175 | ``` 1176 | 1177 | ### collect 1178 | collect operator acts similar to the _reduce_ operator, but while the _reduce_ operator uses a reduce function 1179 | which returns a value, the _collect_ operator takes a container supplier and a function which doesn't return 1180 | anything(a consumer). The mutable container is passed for every event and thus you get a chance to modify it 1181 | in this collect consumer function. 1182 | 1183 | ```java 1184 | Flowable> numbers = Flowable.just(3, 5, -2, 9) 1185 | .collect(ArrayList::new, (container, value) -> { 1186 | log.info("Adding {} to container", value); 1187 | container.add(value); 1188 | //notice we don't need to return anything 1189 | }); 1190 | ========= 1191 | 17:40:18 [main] - Adding 3 to container 1192 | 17:40:18 [main] - Adding 5 to container 1193 | 17:40:18 [main] - Adding -2 to container 1194 | 17:40:18 [main] - Adding 9 to container 1195 | 17:40:18 [main] - Subscriber received: [3, 5, -2, 9] 1196 | 17:40:18 [main] - Subscriber got Completed event 1197 | ``` 1198 | 1199 | because the usecase to store to a List container is so common, there is a **.toList()** operator that is just a collector adding to a List. 1200 | 1201 | ### defer 1202 | An easy way to switch from a blocking method to a reactive Single/Flowable is to use **.defer(() -> blockingOp())**. 1203 | 1204 | Simply using **Flowable.just(blockingOp())** would still block, as Java needs to resolve the parameter when invoking 1205 | **Flux.just(param)** method, so _blockingOp()_ method would still be invoked(and block). 1206 | 1207 | ```java 1208 | //NOT OK 1209 | Flowable flowableBlocked = Flowable.just((blockingOp())); //blocks on this line 1210 | ``` 1211 | 1212 | In order to get around this problem, we can use **Flowable.defer(() -> blockingOp())** and wrap the _blockingOp()_ call inside a lambda which 1213 | will be invoked lazy **at subscribe time**. 1214 | 1215 | ```java 1216 | Flowable stream = Flowable.defer(() -> Flowable.just(blockingOperation())); 1217 | stream.subscribe(val -> log.info("Val " + val)); //only now the code inside defer() is executed 1218 | ``` 1219 | 1220 | 1221 | ## Merging Streams 1222 | Operators for working with multiple streams 1223 | Code at [Part03MergingStreams.java](https://github.com/balamaci/rxjava-playground/blob/master/src/test/java/com/balamaci/rx/Part03MergingStreams.java) 1224 | 1225 | ### zip 1226 | Zip operator operates sort of like a zipper in the sense that it takes an event from one stream and waits 1227 | for an event from another other stream. Once an event for the other stream arrives, it uses the zip function 1228 | to merge the two events. 1229 | 1230 | This is an useful scenario when for example you want to make requests to remote services in parallel and 1231 | wait for both responses before continuing. It also takes a function which will produce the combined result 1232 | of the zipped streams once each has emitted a value. 1233 | 1234 | ![Zip](https://raw.githubusercontent.com/reactor/projectreactor.io/master/src/main/static/assets/img/marble/zip.png) 1235 | 1236 | Zip operator besides the streams to zip, also takes as parameter a function which will produce the 1237 | combined result of the zipped streams once each stream emitted it's value 1238 | 1239 | ```java 1240 | Single isUserBlockedStream = 1241 | Single.fromFuture(CompletableFuture.supplyAsync(() -> { 1242 | Helpers.sleepMillis(200); 1243 | return Boolean.FALSE; 1244 | })); 1245 | 1246 | Single userCreditScoreStream = 1247 | Single.fromFuture(CompletableFuture.supplyAsync(() -> { 1248 | Helpers.sleepMillis(2300); 1249 | return 5; 1250 | })); 1251 | 1252 | Single> userCheckStream = Single.zip(isUserBlockedStream, userCreditScoreStream, 1253 | (blocked, creditScore) -> new Pair(blocked, creditScore)); 1254 | 1255 | userCheckStream.subscribe(pair -> log.info("Received " + pair)); 1256 | ``` 1257 | 1258 | Even if the 'isUserBlockedStream' finishes after 200ms, 'userCreditScoreStream' is slow at 2.3secs, 1259 | the 'zip' method applies the combining function(new Pair(x,y)) after it received both values and passes it 1260 | to the subscriber. 1261 | 1262 | 1263 | Another good example of 'zip' is to slow down a stream by another basically **implementing a periodic emitter of events**: 1264 | 1265 | ```java 1266 | Flowable colors = Flowable.just("red", "green", "blue"); 1267 | Flowable timer = Flowable.interval(2, TimeUnit.SECONDS); 1268 | 1269 | Flowable periodicEmitter = Flowable.zip(colors, timer, (key, val) -> key); 1270 | ``` 1271 | 1272 | Since the zip operator needs a pair of events, the slow stream will work like a timer by periodically emitting 1273 | with zip setting the pace of emissions downstream every 2 seconds. 1274 | 1275 | **Zip is not limited to just two streams**, it can merge 2,3,4,.. streams and wait for groups of 2,3,4 'pairs' of 1276 | events which it combines with the zip function and sends downstream. 1277 | 1278 | ### merge 1279 | Merge operator combines one or more stream and passes events downstream as soon as they appear. 1280 | ![merge](https://raw.githubusercontent.com/reactor/projectreactor.io/master/src/main/static/assets/img/marble/merge.png) 1281 | 1282 | ``` 1283 | Flowable colors = periodicEmitter("red", "green", "blue", 2, TimeUnit.SECONDS); 1284 | 1285 | Flowable numbers = Flowable.interval(1, TimeUnit.SECONDS) 1286 | .take(5); 1287 | Flowable flowable = Flowable.merge(colors, numbers); 1288 | 1289 | ============ 1290 | 21:32:15 - Subscriber received: 0 1291 | 21:32:16 - Subscriber received: red 1292 | 21:32:16 - Subscriber received: 1 1293 | 21:32:17 - Subscriber received: 2 1294 | 21:32:18 - Subscriber received: green 1295 | 21:32:18 - Subscriber received: 3 1296 | 21:32:19 - Subscriber received: 4 1297 | 21:32:20 - Subscriber received: blue 1298 | ``` 1299 | 1300 | ### concat 1301 | Concat operator appends another streams at the end of another 1302 | ![concat](https://raw.githubusercontent.com/reactor/projectreactor.io/master/src/main/static/assets/img/marble/concat.png) 1303 | 1304 | ```java 1305 | Flowable colors = periodicEmitter("red", "green", "blue", 2, TimeUnit.SECONDS); 1306 | 1307 | Flowable numbers = Flowable.interval(1, TimeUnit.SECONDS) 1308 | .take(4); 1309 | 1310 | Flowable events = Flowable.concat(colors, numbers); 1311 | 1312 | ========== 1313 | 22:48:23 - Subscriber received: red 1314 | 22:48:25 - Subscriber received: green 1315 | 22:48:27 - Subscriber received: blue 1316 | 22:48:28 - Subscriber received: 0 1317 | 22:48:29 - Subscriber received: 1 1318 | 22:48:30 - Subscriber received: 2 1319 | 22:48:31 - Subscriber received: 3 1320 | ``` 1321 | 1322 | Even if the 'numbers' streams should start early, the 'colors' stream emits fully its events 1323 | before we see any 'numbers'. 1324 | This is because 'numbers' stream is actually subscribed only after the 'colors' complete. 1325 | Should the second stream be a 'hot' emitter, its events would be lost until the first one finishes 1326 | and the seconds stream is subscribed. 1327 | 1328 | ## Hot Publishers 1329 | We've seen that with 'cold publishers', whenever a subscriber subscribes, each subscriber will get 1330 | it's version of emitted values independently, the exact set of data indifferently when they subscribe. 1331 | But cold publishers only produce data when the subscribers subscribes, however there are cases where 1332 | the events happen independently from the consumers regardless if someone is 1333 | listening or not and we don't have control to request more. So you could say we have 'cold publishers' for pull 1334 | scenarios and 'hot publishers' which push. 1335 | 1336 | ### Subjects 1337 | Subjects are one way to handle hot observables. Subjects keep reference to their subscribers and allow 'multicasting' 1338 | an event to them. 1339 | 1340 | ```java 1341 | for (Disposable s : subscribers.get()) { 1342 | s.onNext(t); 1343 | } 1344 | ``` 1345 | 1346 | Subjects besides being traditional Observables you can use the same operators and subscribe to them, 1347 | are also an **Observer**(interface like **Subscriber** from [reactive-streams](#reactive-streams), implementing the 3 methods **onNext, onError, onComplete**), 1348 | meaning you can invoke subject.onNext(value) from different parts in the code, 1349 | which means that you publish events which the Subject will pass on to their subscribers. 1350 | 1351 | ```java 1352 | Subject subject = ReplaySubject.create() 1353 | .map(...); 1354 | .subscribe(); // 1355 | 1356 | ... 1357 | subject.onNext(val); 1358 | ... 1359 | subject.onNext(val2); 1360 | ``` 1361 | remember for 1362 | ```java 1363 | Observable.create(subscriber -> { 1364 | subscriber.onNext(val); 1365 | }) 1366 | ``` 1367 | 1368 | ### ReplaySubject 1369 | ReplaySubject keeps a buffer of events that it 'replays' to each new subscriber, first he receives a batch of missed 1370 | and only later events in real-time. 1371 | 1372 | ```java 1373 | Subject subject = ReplaySubject.createWithSize(50); 1374 | 1375 | log.info("Pushing 0"); 1376 | subject.onNext(0); 1377 | log.info("Pushing 1"); 1378 | subject.onNext(1); 1379 | 1380 | log.info("Subscribing 1st"); 1381 | subject.subscribe(val -> log.info("Subscriber1 received {}", val), 1382 | logError(), logComplete()); 1383 | 1384 | log.info("Pushing 2"); 1385 | subject.onNext(2); 1386 | 1387 | log.info("Subscribing 2nd"); 1388 | subject.subscribe(val -> log.info("Subscriber2 received {}", val), 1389 | logError(), logComplete()); 1390 | 1391 | log.info("Pushing 3"); 1392 | subject.onNext(3); 1393 | 1394 | subject.onComplete(); 1395 | 1396 | ================== 1397 | [main] - Pushing 0 1398 | [main] - Pushing 1 1399 | [main] - Subscribing 1st 1400 | [main] - Subscriber1 received 0 1401 | [main] - Subscriber1 received 1 1402 | [main] - Pushing 2 1403 | [main] - Subscriber1 received 2 1404 | [main] - Subscribing 2nd 1405 | [main] - Subscriber2 received 0 1406 | [main] - Subscriber2 received 1 1407 | [main] - Subscriber2 received 2 1408 | [main] - Pushing 3 1409 | [main] - Subscriber1 received 3 1410 | [main] - Subscriber2 received 3 1411 | [main] - Subscriber got Completed event 1412 | [main] - Subscriber got Completed event 1413 | ``` 1414 | 1415 | ### ConnectableObservable / ConnectableFlowable and resource sharing 1416 | There are cases when we want to share a single subscription between subscribers, meaning while the code that executes 1417 | on subscribing should be executed once, the events should be published to all subscribers. 1418 | 1419 | For ex. when we want to share a connection between multiple Observables / Flowables. 1420 | Using a plain Observable would just reexecute the code inside _.create()_ and opening / closing a new connection for each 1421 | new subscriber when it subscribes / cancels its subscription. 1422 | 1423 | **ConnectableObservable** are a special kind of **Observable**. No matter how many Subscribers subscribe to ConnectableObservable, 1424 | it opens just one subscription to the Observable from which it was created. 1425 | 1426 | Anyone who subscribes to **ConnectableObservable** is placed in a set of Subscribers(it doesn't trigger 1427 | the _.create()_ code a normal Observable would when .subscribe() is called). A **.connect()** method is available for ConnectableObservable. 1428 | **As long as connect() is not called, these Subscribers are put on hold, they never directly subscribe to upstream Observable** 1429 | 1430 | ```java 1431 | ConnectableObservable connectableObservable = 1432 | Observable.create(subscriber -> { 1433 | log.info("Inside create()"); 1434 | 1435 | /* A JMS connection listener example 1436 | Just an example of a costly operation that is better to be shared **/ 1437 | 1438 | /* Connection connection = connectionFactory.createConnection(); 1439 | Session session = connection.createSession(true, AUTO_ACKNOWLEDGE); 1440 | MessageConsumer consumer = session.createConsumer(orders); 1441 | consumer.setMessageListener(subscriber::onNext); */ 1442 | 1443 | subscriber.setCancellable(() -> log.info("Subscription cancelled")); 1444 | 1445 | log.info("Emitting 1"); 1446 | subscriber.onNext(1); 1447 | 1448 | log.info("Emitting 2"); 1449 | subscriber.onNext(2); 1450 | 1451 | subscriber.onComplete(); 1452 | }).publish(); 1453 | 1454 | connectableObservable 1455 | .take(1) 1456 | .subscribe((val) -> log.info("Subscriber1 received: {}", val), 1457 | logError(), logComplete()); 1458 | 1459 | connectableObservable 1460 | .subscribe((val) -> log.info("Subscriber2 received: {}", val), 1461 | logError(), logComplete()); 1462 | 1463 | log.info("Now connecting to the ConnectableObservable"); 1464 | connectableObservable.connect(); 1465 | 1466 | =================== 1467 | 1468 | ``` 1469 | 1470 | ### share() operator 1471 | Another operator of the ConnectableObservable **.refCount()** allows to do away with having to manually call **.connect()**, 1472 | instead it invokes the .create() code when the first Subscriber subscribes while sharing this single subscription with subsequent Subscribers. 1473 | This means that **.refCount()** basically keeps a count of references of it's subscribers and subscribes to upstream Observable 1474 | (executes the code inside .create() just for the first subscriber), but multicasts the same event to each active subscriber. 1475 | When the last subscriber unsubscribes, the ref counter goes from 1 to 0 and triggers any unsubscribe callback associated. 1476 | If another Subscriber subscribes after that, counter goes from 0 to 1 and the process starts over again. 1477 | 1478 | ```java 1479 | ConnectableObservable connectableStream = Observable.create(subscriber -> { 1480 | log.info("Inside create()"); 1481 | 1482 | //Simulated MessageListener emits periodically every 500 milliseconds 1483 | ResourceConnectionHandler resourceConnectionHandler = new ResourceConnectionHandler() { 1484 | @Override 1485 | public void onMessage(Integer message) { 1486 | log.info("Emitting {}", message); 1487 | subscriber.onNext(message); 1488 | } 1489 | }; 1490 | resourceConnectionHandler.openConnection(); 1491 | 1492 | //when the last subscriber unsubscribes it will invoke disconnect on the resourceConnectionHandler 1493 | subscriber.setCancellable(resourceConnectionHandler::disconnect); 1494 | }).publish(); 1495 | 1496 | //publish().refCount() have been joined together in the .share() operator 1497 | Observable observable = connectableObservable.refCount(); 1498 | 1499 | CountDownLatch latch = new CountDownLatch(2); 1500 | connectableStream 1501 | .take(5) 1502 | .subscribe((val) -> log.info("Subscriber1 received: {}", val), 1503 | logError(), logComplete(latch)); 1504 | 1505 | Helpers.sleepMillis(1000); 1506 | 1507 | log.info("Subscribing 2nd"); 1508 | //we're not seing the code inside .create() reexecuted 1509 | connectableStream 1510 | .take(2) 1511 | .subscribe((val) -> log.info("Subscriber2 received: {}", val), 1512 | logError(), logComplete(latch)); 1513 | 1514 | //waiting for the streams to complete 1515 | Helpers.wait(latch); 1516 | 1517 | //subscribing another after previous Subscribers unsubscribed 1518 | latch = new CountDownLatch(1); 1519 | log.info("Subscribing 3rd"); 1520 | observable 1521 | .take(1) 1522 | .subscribe((val) -> log.info("Subscriber3 received: {}", val), logError(), logComplete(latch)); 1523 | 1524 | 1525 | private abstract class ResourceConnectionHandler { 1526 | 1527 | ScheduledExecutorService scheduledExecutorService; 1528 | 1529 | private int counter; 1530 | 1531 | public void openConnection() { 1532 | log.info("**Opening connection"); 1533 | 1534 | scheduledExecutorService = periodicEventEmitter(() -> { 1535 | counter ++; 1536 | onMessage(counter); 1537 | }, 500, TimeUnit.MILLISECONDS); 1538 | } 1539 | 1540 | public abstract void onMessage(Integer message); 1541 | 1542 | public void disconnect() { 1543 | log.info("**Shutting down connection"); 1544 | scheduledExecutorService.shutdown(); 1545 | } 1546 | } 1547 | 1548 | =============== 1549 | 14:55:23 [main] INFO BaseTestObservables - Inside create() 1550 | 14:55:23 [main] INFO BaseTestObservables - **Opening connection 1551 | 14:55:23 [pool-1-thread-1] INFO BaseTestObservables - Emitting 1 1552 | 14:55:23 [pool-1-thread-1] INFO BaseTestObservables - Subscriber1 received: 1 1553 | 14:55:24 [pool-1-thread-1] INFO BaseTestObservables - Emitting 2 1554 | 14:55:24 [pool-1-thread-1] INFO BaseTestObservables - Subscriber1 received: 2 1555 | 14:55:24 [pool-1-thread-1] INFO BaseTestObservables - Emitting 3 1556 | 14:55:24 [pool-1-thread-1] INFO BaseTestObservables - Subscriber1 received: 3 1557 | 14:55:24 [main] INFO BaseTestObservables - Subscribing 2nd 1558 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Emitting 4 1559 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Subscriber1 received: 4 1560 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Subscriber2 received: 4 1561 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Emitting 5 1562 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Subscriber1 received: 5 1563 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Subscriber got Completed event 1564 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Subscriber2 received: 5 1565 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - **Shutting down connection 1566 | 14:55:25 [pool-1-thread-1] INFO BaseTestObservables - Subscriber got Completed event 1567 | 14:55:25 [main] INFO BaseTestObservables - Subscribing 3rd 1568 | 14:55:25 [main] INFO BaseTestObservables - Inside create() 1569 | 14:55:25 [main] INFO BaseTestObservables - **Opening connection 1570 | 14:55:25 [pool-2-thread-1] INFO BaseTestObservables - Emitting 1 1571 | 14:55:25 [pool-2-thread-1] INFO BaseTestObservables - Subscriber3 received: 1 1572 | 14:55:25 [pool-2-thread-1] INFO BaseTestObservables - **Shutting down connection 1573 | 14:55:25 [pool-2-thread-1] INFO BaseTestObservables - Subscriber got Completed event 1574 | ``` 1575 | The **share()** operator of Observable / Flowable is an operator which basically does **publish().refCount()**. 1576 | 1577 | ## Schedulers 1578 | RxJava provides some high level concepts for concurrent execution, like ExecutorService we're not dealing 1579 | with the low level constructs like creating the Threads ourselves. Instead we're using a **Scheduler** which create 1580 | Workers who are responsible for scheduling and running code. By default RxJava will not introduce concurrency 1581 | and will run the operations on the subscription thread. 1582 | 1583 | There are two methods through which we can introduce Schedulers into our chain of operations: 1584 | 1585 | - **subscribeOn** allows to specify which Scheduler invokes the code contained in the lambda code for Observable.create() 1586 | - **observeOn** allows control to which Scheduler executes the code in the downstream operators 1587 | 1588 | RxJava provides some general use Schedulers: 1589 | 1590 | - **Schedulers.computation()** - to be used for CPU intensive tasks. A threadpool. Should not be used for tasks involving blocking IO. 1591 | - **Schedulers.io()** - to be used for IO bound tasks 1592 | - **Schedulers.from(Executor)** - custom ExecutorService 1593 | - **Schedulers.newThread()** - always creates a new thread when a worker is needed. Since it's not thread pooled and 1594 | always creates a new thread instead of reusing one, this scheduler is not very useful 1595 | 1596 | Although we said by default RxJava doesn't introduce concurrency, lots of operators involve waiting like **delay**, 1597 | **interval**, **zip** need to run on a Scheduler, otherwise they would just block the subscribing thread. 1598 | By default **Schedulers.computation()** is used, but the Scheduler can be passed as a parameter. 1599 | 1600 | 1601 | ## Flatmap operator 1602 | The flatMap operator is so important and has so many different uses it deserves it's own category to explain it. 1603 | Code at [Part06FlatMapOperator.java](https://github.com/balamaci/rxjava-playground/blob/master/src/test/java/com/balamaci/rx/Part06FlatMapOperator.java) 1604 | 1605 | I like to think of it as a sort of **fork-join** operation because what flatMap does is it takes individual stream items 1606 | and maps each of them to an Observable(so it creates new Streams from each object) and then 'flattens' the events from 1607 | these Streams back as coming from a single stream. 1608 | 1609 | Why this looks like fork-join because for each element you can fork some jobs that keeps emitting results, 1610 | and these results are emitted back as elements to the subscribers downstream 1611 | 1612 | **Rules of thumb** to consider before getting comfortable with flatMap: 1613 | 1614 | - When you have an 'item' **T** and a method **T -> Flowable<X>**, you need flatMap. Most common example is when you want 1615 | to make a remote call that returns an Observable / Flowable . For ex if you have a stream of customerIds, and downstream you 1616 | want to work with actual Customer objects: 1617 | 1618 | - When you have Observable<Observable<T>>(aka stream of streams) you probably need flatMap. Because flatMap means you are subscribing 1619 | to each substream. 1620 | 1621 | We use a simulated remote call that might return asynchronous as many events as the length of the color string 1622 | 1623 | ```java 1624 | private Flowable simulateRemoteOperation(String color) { 1625 | return Flowable.create(subscriber -> { 1626 | for (int i = 0; i < color.length(); i++) { 1627 | subscriber.onNext(color + i); 1628 | Helpers.sleepMillis(200); 1629 | } 1630 | 1631 | subscriber.onComplete(); 1632 | }, BackpressureStrategy.MISSING); 1633 | } 1634 | ``` 1635 | 1636 | If we have a stream of color names: 1637 | 1638 | ```java 1639 | Flowable colors = Flowable.just("orange", "red", "green") 1640 | ``` 1641 | 1642 | to invoke the remote operation: 1643 | 1644 | ```java 1645 | Flowable colors = Flowable.just("orange", "red", "green") 1646 | .flatMap(colorName -> simulatedRemoteOperation(colorName)); 1647 | 1648 | colors.subscribe(val -> log.info("Subscriber received: {}", val)); 1649 | 1650 | ==== 1651 | 16:44:15 [Thread-0]- Subscriber received: orange0 1652 | 16:44:15 [Thread-2]- Subscriber received: green0 1653 | 16:44:15 [Thread-1]- Subscriber received: red0 1654 | 16:44:15 [Thread-0]- Subscriber received: orange1 1655 | 16:44:15 [Thread-2]- Subscriber received: green1 1656 | 16:44:15 [Thread-1]- Subscriber received: red1 1657 | 16:44:15 [Thread-0]- Subscriber received: orange2 1658 | 16:44:15 [Thread-2]- Subscriber received: green2 1659 | 16:44:15 [Thread-1]- Subscriber received: red2 1660 | 16:44:15 [Thread-0]- Subscriber received: orange3 1661 | 16:44:15 [Thread-2]- Subscriber received: green3 1662 | 16:44:16 [Thread-0]- Subscriber received: orange4 1663 | 16:44:16 [Thread-2]- Subscriber received: green4 1664 | 16:44:16 [Thread-0]- Subscriber received: orange5 1665 | ``` 1666 | 1667 | Notice how the results are coming intertwined. This is because flatMap actually subscribes to it's inner Observables 1668 | returned from 'simulateRemoteOperation'. You can specify the **concurrency level of flatMap** as a parameter. Meaning 1669 | you can say how many of the substreams should be subscribed "concurrently" - after **onComplete** is triggered on the substreams, 1670 | a new substream is subscribed-. 1671 | 1672 | By setting the concurrency to **1** we don't subscribe to other substreams until the current one finishes: 1673 | 1674 | ``` 1675 | Observable colors = Observable.just("orange", "red", "green") 1676 | .flatMap(val -> simulateRemoteOperation(val), 1); // 1677 | 1678 | ``` 1679 | 1680 | Notice now there is a sequence from each color before the next one appears 1681 | 1682 | ``` 1683 | 17:15:24 [Thread-0]- Subscriber received: orange0 1684 | 17:15:24 [Thread-0]- Subscriber received: orange1 1685 | 17:15:25 [Thread-0]- Subscriber received: orange2 1686 | 17:15:25 [Thread-0]- Subscriber received: orange3 1687 | 17:15:25 [Thread-0]- Subscriber received: orange4 1688 | 17:15:25 [Thread-0]- Subscriber received: orange5 1689 | 17:15:25 [Thread-1]- Subscriber received: red0 1690 | 17:15:26 [Thread-1]- Subscriber received: red1 1691 | 17:15:26 [Thread-1]- Subscriber received: red2 1692 | 17:15:26 [Thread-2]- Subscriber received: green0 1693 | 17:15:26 [Thread-2]- Subscriber received: green1 1694 | 17:15:26 [Thread-2]- Subscriber received: green2 1695 | 17:15:27 [Thread-2]- Subscriber received: green3 1696 | 17:15:27 [Thread-2]- Subscriber received: green4 1697 | ``` 1698 | 1699 | There is actually an operator which is basically this **flatMap with 1 concurrency called concatMap**. 1700 | 1701 | 1702 | Inside the flatMap we can operate on the substream with the same stream operators 1703 | 1704 | ```java 1705 | Observable> colorsCounted = colors 1706 | .flatMap(colorName -> { 1707 | Observable timer = Observable.interval(2, TimeUnit.SECONDS); 1708 | 1709 | return simulateRemoteOperation(colorName) // <- Still a stream 1710 | .zipWith(timer, (val, timerVal) -> val) 1711 | .count() 1712 | .map(counter -> new Pair<>(colorName, counter)); 1713 | } 1714 | ); 1715 | ``` 1716 | 1717 | ## Error handling 1718 | Code at [Part08ErrorHandling.java](https://github.com/balamaci/rxjava-playground/blob/master/src/test/java/com/balamaci/rx/Part08ErrorHandling.java) 1719 | 1720 | Exceptions are for exceptional situations. 1721 | The Observable contract specifies that exceptions are terminal operations. 1722 | That means in case an error reaches the Subscriber, after invoking the 'onError' handler, it also unsubscribes: 1723 | 1724 | ```java 1725 | Observable colors = Observable.just("green", "blue", "red", "yellow") 1726 | .map(color -> { 1727 | if ("red".equals(color)) { 1728 | throw new RuntimeException("Encountered red"); 1729 | } 1730 | return color + "*"; 1731 | }) 1732 | .map(val -> val + "XXX"); 1733 | 1734 | colors.subscribe( 1735 | val -> log.info("Subscriber received: {}", val), 1736 | exception -> log.error("Subscriber received error '{}'", exception.getMessage()), 1737 | () -> log.info("Subscriber completed") 1738 | ); 1739 | ``` 1740 | 1741 | returns: 1742 | ``` 1743 | 23:30:17 [main] INFO - Subscriber received: green*XXX 1744 | 23:30:17 [main] INFO - Subscriber received: blue*XXX 1745 | 23:30:17 [main] ERROR - Subscriber received error 'Encountered red' 1746 | ``` 1747 | After the map() operator encounters an error it unsubscribes(cancels the subscription) from upstream 1748 | - therefore 'yellow' is not even emitted-. The error travels downstream and triggers the error handler in the subscriber. 1749 | 1750 | 1751 | There are operators to deal with error flow control: 1752 | 1753 | ### onErrorReturn 1754 | 1755 | The 'onErrorReturn' operator replaces an exception with a value: 1756 | 1757 | ```java 1758 | Flowable numbers = Flowable.just("1", "3", "a", "4", "5", "c") 1759 | .map(Integer::parseInt) 1760 | .onErrorReturn(0); 1761 | subscribeWithLog(numbers); 1762 | ===== 1763 | Subscriber received: 1 1764 | Subscriber received: 3 1765 | Subscriber received: 0 1766 | Subscriber got Completed event 1767 | ``` 1768 | 1769 | Notice though how it didn't prevent map() operator from unsubscribing from the Flowable, but it did 1770 | trigger the normal onNext callback instead of onError in the subscriber. 1771 | 1772 | 1773 | Let's introduce a more realcase scenario of a simulated remote request that might fail 1774 | 1775 | ```java 1776 | private Observable simulateRemoteOperation(String color) { 1777 | return Observable.create(subscriber -> { 1778 | if ("red".equals(color)) { 1779 | log.info("Emitting RuntimeException for {}", color); 1780 | throw new RuntimeException("Color red raises exception"); 1781 | } 1782 | if ("black".equals(color)) { 1783 | log.info("Emitting IllegalArgumentException for {}", color); 1784 | throw new IllegalArgumentException("Black is not a color"); 1785 | } 1786 | 1787 | String value = "**" + color + "**"; 1788 | 1789 | log.info("Emitting {}", value); 1790 | subscriber.onNext(value); 1791 | subscriber.onCompleted(); 1792 | }); 1793 | } 1794 | 1795 | Flowable colors = Flowable.just("green", "blue", "red", "white", "blue") 1796 | .flatMap(color -> simulateRemoteOperation(color)) 1797 | .onErrorReturn(throwable -> "-blank-"); 1798 | 1799 | subscribeWithLog(colors); 1800 | 1801 | ============ 1802 | 1803 | 22:15:51 [main] INFO - Emitting **green** 1804 | 22:15:51 [main] INFO - Subscriber received: **green** 1805 | 22:15:51 [main] INFO - Emitting **blue** 1806 | 22:15:51 [main] INFO - Subscriber received: **blue** 1807 | 22:15:51 [main] INFO - Emitting RuntimeException for red 1808 | 22:15:51 [main] INFO - Subscriber received: -blank- 1809 | 22:15:51 [main] INFO - Subscriber got Completed event 1810 | ``` 1811 | flatMap encounters an error when it subscribes to 'red' substreams and thus still unsubscribe from 'colors' 1812 | stream and the remaining colors are not longer emitted 1813 | 1814 | 1815 | ```java 1816 | Flowable colors = Flowable.just("green", "blue", "red", "white", "blue") 1817 | .flatMap(color -> simulateRemoteOperation(color) 1818 | .onErrorReturn(throwable -> "-blank-") 1819 | ); 1820 | ``` 1821 | onErrorReturn() is applied to the flatMap substream and thus translates the exception to a value and so flatMap 1822 | continues on with the other colors after red 1823 | 1824 | returns: 1825 | ``` 1826 | 22:15:51 [main] INFO - Emitting **green** 1827 | 22:15:51 [main] INFO - Subscriber received: **green** 1828 | 22:15:51 [main] INFO - Emitting **blue** 1829 | 22:15:51 [main] INFO - Subscriber received: **blue** 1830 | 22:15:51 [main] INFO - Emitting RuntimeException for red 1831 | 22:15:51 [main] INFO - Subscriber received: -blank- 1832 | 22:15:51 [main] INFO - Emitting **white** 1833 | 22:15:51 [main] INFO - Subscriber received: **white** 1834 | 22:15:51 [main] INFO - Emitting **blue** 1835 | 22:15:51 [main] INFO - Subscriber received: **blue** 1836 | 22:15:51 [main] INFO - Subscriber got Completed event 1837 | ``` 1838 | 1839 | ### onErrorResumeNext 1840 | onErrorResumeNext() returns a stream instead of an exception, useful for example to invoke a fallback 1841 | method that returns also a stream 1842 | 1843 | ```java 1844 | Observable colors = Observable.just("green", "blue", "red", "white", "blue") 1845 | .flatMap(color -> simulateRemoteOperation(color) 1846 | .onErrorResumeNext(th -> { 1847 | if (th instanceof IllegalArgumentException) { 1848 | return Observable.error(new RuntimeException("Fatal, wrong arguments")); 1849 | } 1850 | return fallbackRemoteOperation(); 1851 | }) 1852 | ); 1853 | 1854 | private Observable fallbackRemoteOperation() { 1855 | return Observable.just("blank"); 1856 | } 1857 | ``` 1858 | 1859 | ## Retrying 1860 | 1861 | ### timeout() 1862 | Timeout operator raises exception when there are no events incoming before it's predecessor in the specified time limit. 1863 | 1864 | ### retry() 1865 | **retry()** - resubscribes in case of exception to the Observable 1866 | 1867 | ```java 1868 | Flowable colors = Flowable.just("red", "blue", "green", "yellow") 1869 | .concatMap(color -> delayedByLengthEmitter(TimeUnit.SECONDS, color) 1870 | //if there are no events flowing in the timeframe 1871 | .timeout(6, TimeUnit.SECONDS) 1872 | .retry(2) 1873 | .onErrorResumeNext(Observable.just("blank")) 1874 | ); 1875 | 1876 | subscribeWithLog(colors.toBlocking()); 1877 | ``` 1878 | 1879 | returns 1880 | ``` 1881 | 12:40:16 [main] INFO - Received red delaying for 3 1882 | 12:40:19 [main] INFO - Subscriber received: red 1883 | 12:40:19 [RxComputationScheduler-2] INFO - Received blue delaying for 4 1884 | 12:40:23 [main] INFO - Subscriber received: blue 1885 | 12:40:23 [RxComputationScheduler-4] INFO - Received green delaying for 5 1886 | 12:40:28 [main] INFO - Subscriber received: green 1887 | 12:40:28 [RxComputationScheduler-6] INFO - Received yellow delaying for 6 1888 | 12:40:34 [RxComputationScheduler-7] INFO - Received yellow delaying for 6 1889 | 12:40:40 [RxComputationScheduler-1] INFO - Received yellow delaying for 6 1890 | 12:40:46 [main] INFO - Subscriber received: blank 1891 | 12:40:46 [main] INFO - Subscriber got Completed event 1892 | ``` 1893 | 1894 | When you want to retry considering the thrown exception type: 1895 | 1896 | ```java 1897 | Observable colors = Observable.just("blue", "red", "black", "yellow") 1898 | .flatMap(colorName -> simulateRemoteOperation(colorName) 1899 | .retry((retryAttempt, exception) -> { 1900 | if (exception instanceof IllegalArgumentException) { 1901 | log.error("{} encountered non retry exception ", colorName); 1902 | return false; 1903 | } 1904 | log.info("Retry attempt {} for {}", retryAttempt, colorName); 1905 | return retryAttempt <= 2; 1906 | }) 1907 | .onErrorResumeNext(Observable.just("generic color")) 1908 | ); 1909 | ``` 1910 | 1911 | ``` 1912 | 13:21:37 [main] INFO - Emitting **blue** 1913 | 13:21:37 [main] INFO - Emitting RuntimeException for red 1914 | 13:21:37 [main] INFO - Retry attempt 1 for red 1915 | 13:21:37 [main] INFO - Emitting RuntimeException for red 1916 | 13:21:37 [main] INFO - Retry attempt 2 for red 1917 | 13:21:37 [main] INFO - Emitting RuntimeException for red 1918 | 13:21:37 [main] INFO - Retry attempt 3 for red 1919 | 13:21:37 [main] INFO - Emitting IllegalArgumentException for black 1920 | 13:21:37 [main] ERROR - black encountered non retry exception 1921 | 13:21:37 [main] INFO - Emitting **yellow** 1922 | 13:21:37 [main] INFO - Subscriber received: **blue** 1923 | 13:21:37 [main] INFO - Subscriber received: generic color 1924 | 13:21:37 [main] INFO - Subscriber received: generic color 1925 | 13:21:37 [main] INFO - Subscriber received: **yellow** 1926 | 13:21:37 [main] INFO - Subscriber got Completed event 1927 | ``` 1928 | 1929 | ### retryWhen 1930 | A more complex retry logic like implementing a backoff strategy in case of exception 1931 | This can be obtained with **retryWhen**(exceptionObservable -> Observable) 1932 | 1933 | retryWhen resubscribes when an event from an Observable is emitted. It receives as parameter an exception stream 1934 | 1935 | we zip the exceptionsStream with a .range() stream to obtain the number of retries, 1936 | however we want to wait a little before retrying so in the zip function we return a delayed event - .timer() 1937 | 1938 | The delay also needs to be subscribed to be effected so we also flatMap 1939 | 1940 | ```java 1941 | Observable colors = Observable.just("blue", "green", "red", "black", "yellow"); 1942 | 1943 | colors.flatMap(colorName -> 1944 | simulateRemoteOperation(colorName) 1945 | .retryWhen(exceptionStream -> exceptionStream 1946 | .zipWith(Observable.range(1, 3), (exc, attempts) -> { 1947 | //don't retry for IllegalArgumentException 1948 | if(exc instanceof IllegalArgumentException) { 1949 | return Observable.error(exc); 1950 | } 1951 | 1952 | if(attempts < 3) { 1953 | return Observable.timer(2 * attempts, TimeUnit.SECONDS); 1954 | } 1955 | return Observable.error(exc); 1956 | }) 1957 | .flatMap(val -> val) 1958 | ) 1959 | .onErrorResumeNext(Observable.just("generic color") 1960 | ) 1961 | ); 1962 | ``` 1963 | 1964 | ``` 1965 | 15:20:23 [main] INFO - Emitting **blue** 1966 | 15:20:23 [main] INFO - Emitting **green** 1967 | 15:20:23 [main] INFO - Emitting RuntimeException for red 1968 | 15:20:23 [main] INFO - Emitting IllegalArgumentException for black 1969 | 15:20:23 [main] INFO - Emitting **yellow** 1970 | 15:20:23 [main] INFO - Subscriber received: **blue** 1971 | 15:20:23 [main] INFO - Subscriber received: **green** 1972 | 15:20:23 [main] INFO - Subscriber received: generic color 1973 | 15:20:23 [main] INFO - Subscriber received: **yellow** 1974 | 15:20:25 [RxComputationScheduler-1] INFO - Emitting RuntimeException for red 1975 | 15:20:29 [RxComputationScheduler-2] INFO - Emitting RuntimeException for red 1976 | 15:20:29 [main] INFO - Subscriber received: generic color 1977 | 15:20:29 [main] INFO - Subscriber got Completed event 1978 | ``` 1979 | 1980 | **retryWhen vs repeatWhen** 1981 | With similar names it worth noting the difference. 1982 | 1983 | - repeat() resubscribes when it receives onCompleted(). 1984 | - retry() resubscribes when it receives onError(). 1985 | 1986 | Example using repeatWhen() to implement periodic polling 1987 | ```java 1988 | remoteOperation.repeatWhen(completed -> completed 1989 | .delay(2, TimeUnit.SECONDS)) 1990 | ``` 1991 | 1992 | ## Backpressure 1993 | 1994 | It can be the case of a slow consumer that cannot keep up with the producer that is producing too many events 1995 | that the subscriber cannot process. 1996 | 1997 | Backpressure relates to a feedback mechanism through which the subscriber can signal to the producer how much data 1998 | it can consume and so to produce only that amount. 1999 | 2000 | The [reactive-streams](https://github.com/reactive-streams/reactive-streams-jvm) section above we saw that besides the 2001 | **onNext, onError** and **onComplete** handlers, the Subscriber 2002 | has an **onSubscribe(Subscription)**, Subscription through which it can signal upstream it's ready to receive a number 2003 | of items and after it processes the items request another batch. 2004 | 2005 | 2006 | ```java 2007 | public interface Subscriber { 2008 | //signals to the Publisher to start sending events 2009 | public void onSubscribe(Subscription s); 2010 | 2011 | public void onNext(T t); 2012 | public void onError(Throwable t); 2013 | public void onComplete(); 2014 | } 2015 | ``` 2016 | 2017 | The methods exposed by **Subscription** through which the subscriber comunicates with the upstream: 2018 | 2019 | ```java 2020 | public interface Subscription { 2021 | public void request(long n); //request n items 2022 | public void cancel(); 2023 | } 2024 | ``` 2025 | 2026 | So in theory the Subscriber can prevent being overloaded by requesting an initial number of items. The Publisher would 2027 | send those items downstream and not produce any more, until the Subscriber would request more. We say in theory because 2028 | until now we did not see a custom **onSubscribe(Subscription)** request being implemented. This is because if not specified explicitly, 2029 | there is a default implementation which requests of **Long.MAX_VALUE** which basically means "send all you have". 2030 | 2031 | Neither did we see the code in the producer that takes consideration of the number of items requested by the subscriber. 2032 | 2033 | ```java 2034 | Flowable.create(subscriber -> { 2035 | log.info("Started emitting"); 2036 | 2037 | for(int i=0; i < 300; i++) { 2038 | if(subscriber.isCanceled()) { 2039 | return; 2040 | } 2041 | log.info("Emitting {}", i); 2042 | subscriber.next(i); 2043 | } 2044 | 2045 | subscriber.complete(); 2046 | }, BackpressureStrategy.BUFFER); //BackpressureStrategy will be explained further bellow 2047 | ``` 2048 | Looks like it's not possible to slow down production based on request(as there is no reference to the requested items), 2049 | we can at most stop production if the subscriber canceled subscription. 2050 | 2051 | This can be done if we extend Flowable so we can pass our custom Subscription type to the downstream subscriber: 2052 | 2053 | ```java 2054 | private class CustomRangeFlowable extends Flowable { 2055 | 2056 | private int startFrom; 2057 | private int count; 2058 | 2059 | CustomRangeFlowable(int startFrom, int count) { 2060 | this.startFrom = startFrom; 2061 | this.count = count; 2062 | } 2063 | 2064 | @Override 2065 | public void subscribeActual(Subscriber subscriber) { 2066 | subscriber.onSubscribe(new CustomRangeSubscription(startFrom, count, subscriber)); 2067 | } 2068 | 2069 | class CustomRangeSubscription implements Subscription { 2070 | 2071 | volatile boolean cancelled; 2072 | boolean completed = false; 2073 | 2074 | private int count; 2075 | private int currentCount; 2076 | private int startFrom; 2077 | 2078 | private Subscriber actualSubscriber; 2079 | 2080 | CustomRangeSubscription(int startFrom, int count, Subscriber actualSubscriber) { 2081 | this.count = count; 2082 | this.startFrom = startFrom; 2083 | this.actualSubscriber = actualSubscriber; 2084 | } 2085 | 2086 | @Override 2087 | public void request(long items) { 2088 | log.info("Downstream requests {} items", items); 2089 | for(int i=0; i < items; i++) { 2090 | if(cancelled || completed) { 2091 | return; 2092 | } 2093 | 2094 | if(currentCount == count) { 2095 | completed = true; 2096 | if(cancelled) { 2097 | return; 2098 | } 2099 | 2100 | actualSubscriber.onComplete(); 2101 | return; 2102 | } 2103 | 2104 | int emitVal = startFrom + currentCount; 2105 | currentCount++; 2106 | actualSubscriber.onNext(emitVal); 2107 | } 2108 | } 2109 | 2110 | @Override 2111 | public void cancel() { 2112 | cancelled = true; 2113 | } 2114 | } 2115 | } 2116 | ``` 2117 | Now lets see how we can custom control how many items we request from upstream, to simulate an initial big request, 2118 | and then a request for other smaller batches of items as soon as the subscriber finishes and is ready for another batch. 2119 | 2120 | ```java 2121 | Flowable flowable = new CustomRangeFlowable(5, 10); 2122 | 2123 | flowable.subscribe(new Subscriber() { 2124 | 2125 | private Subscription subscription; 2126 | private int backlogItems; 2127 | 2128 | private final int BATCH = 2; 2129 | private final int INITIAL_REQ = 5; 2130 | 2131 | @Override 2132 | public void onSubscribe(Subscription subscription) { 2133 | this.subscription = subscription; 2134 | backlogItems = INITIAL_REQ; 2135 | 2136 | log.info("Initial request {}", backlogItems); 2137 | subscription.request(backlogItems); 2138 | } 2139 | 2140 | @Override 2141 | public void onNext(Integer val) { 2142 | log.info("Subscriber received {}", val); 2143 | backlogItems --; 2144 | 2145 | if(backlogItems == 0) { 2146 | backlogItems = BATCH; 2147 | subscription.request(BATCH); 2148 | } 2149 | } 2150 | 2151 | @Override 2152 | public void onError(Throwable throwable) { 2153 | log.info("Subscriber encountered error"); 2154 | } 2155 | 2156 | @Override 2157 | public void onComplete() { 2158 | log.info("Subscriber completed"); 2159 | } 2160 | }); 2161 | ===================== 2162 | Initial request 5 2163 | Downstream requests 5 items 2164 | Subscriber received 5 2165 | Subscriber received 6 2166 | Subscriber received 7 2167 | Subscriber received 8 2168 | Subscriber received 9 2169 | Downstream requests 2 items 2170 | Subscriber received 10 2171 | Subscriber received 11 2172 | Downstream requests 2 items 2173 | Subscriber received 12 2174 | Subscriber received 13 2175 | Downstream requests 2 items 2176 | Subscriber received 14 2177 | Subscriber completed 2178 | ``` 2179 | 2180 | Returning to the _Flowable.create()_ example since it's not taking any account of the requested 2181 | items by the subscriber, does it mean it might overwhelm a slow Subscriber? 2182 | 2183 | ```java 2184 | private Flowable createFlowable(int items, 2185 | BackpressureStrategy backpressureStrategy) { 2186 | 2187 | return Flowable.create(subscriber -> { 2188 | log.info("Started emitting"); 2189 | 2190 | for (int i = 0; i < items; i++) { 2191 | if(subscriber.isCancelled()) { 2192 | return; 2193 | } 2194 | 2195 | log.info("Emitting {}", i); 2196 | subscriber.onNext(i); 2197 | } 2198 | 2199 | subscriber.onComplete(); 2200 | }, backpressureStrategy); //can be BackpressureStrategy.DROP, BUFFER, LATEST,.. 2201 | ``` 2202 | This is where the 2nd parameter _BackpressureStrategy_ comes in that allows you to specify what to do 2203 | in the case. 2204 | 2205 | - BackpressureStrategy.BUFFER buffer in memory the events that overflow. Of course is we don't drop over some threshold, it might lead to OufOfMemory. 2206 | - BackpressureStrategy.DROP just drop the overflowing events 2207 | - BackpressureStrategy.LATEST keep only recent event and discards previous unconsumed events. 2208 | - BackpressureStrategy.ERROR we get an error in the subscriber immediately 2209 | - BackpressureStrategy.MISSING means we don't care about backpressure(we let one of the downstream operators 2210 | onBackpressureXXX handle it -explained further down-) 2211 | 2212 | 2213 | Still what does it mean to 'overwhelm' the subscriber? 2214 | It means to emit more items than requested by downstream subscriber. 2215 | But we said that by default the subscriber requests Long.MAX_VALUE since the code 2216 | **flowable.subscribe(onNext(), onError, onComplete)** uses a default **onSubscribe**: 2217 | ``` 2218 | (subscription) -> subscription.request(Long.MAX_VALUE); 2219 | ``` 2220 | 2221 | so unless we override it like in our custom Subscriber above, it means it would never overflow. But between the Publisher and the Subscriber you'd have a series of operators. 2222 | When we subscribe, a Subscriber travels up through all operators to the original Publisher and some operators override 2223 | the requested items upstream. One such operator is **observeOn**() which makes it's own request to the upstream Publisher(256 by default), 2224 | but can take a parameter to specify the request size. 2225 | 2226 | ``` 2227 | Flowable flowable = createFlowable(5, BackpressureStrategy.DROP) 2228 | .observeOn(Schedulers.io(), false, 3); 2229 | flowable.subscribe((val) -> { 2230 | log.info("Subscriber received: {}", val); 2231 | Helpers.sleepMillis(millis); 2232 | }, logError(), logComplete()); 2233 | ====== 2234 | [main] - Started emitting 2235 | [main] - Emitting 0 2236 | [main] - Emitting 1 2237 | [main] - Emitting 2 2238 | [main] - Emitting 3 2239 | [main] - Emitting 4 2240 | [RxCachedThreadScheduler-1] - Subscriber received: 0 2241 | [RxCachedThreadScheduler-1] - Subscriber received: 1 2242 | [RxCachedThreadScheduler-1] - Subscriber received: 2 2243 | [RxCachedThreadScheduler-1] - Subscriber got Completed event 2244 | ``` 2245 | This is expected, as the subscription travels upstream through the operators to the source Flowable, while initially 2246 | the Subscriber requesting Long.MAX_VALUE from the upstream operator **observeOn**, which in turn subscribes to the source and it requests just 3 items from the source instead. 2247 | Since we used **BackpressureStrategy.DROP** all the items emitted outside the expected 3, get discarded and thus never reach our subscriber. 2248 | 2249 | You may wonder what would have happened if we didn't use **observeOn**. We had to use it if we wanted to be able 2250 | to produce faster than the subscriber(it wasn't just to show a limited request operator), because we'd need a 2251 | separate thread to produce events faster than the subscriber processes them. 2252 | 2253 | Also you can transform an Observable to Flowable by specifying a BackpressureStrategy, otherwise Observables 2254 | just throw exception on overflowing(same as using BackpressureStrategy.DROP in Flowable.create()). 2255 | ``` 2256 | Flowable flowable = observable.toFlowable(BackpressureStrategy.DROP) 2257 | ``` 2258 | so can a hot Publisher be converted to a Flowable: 2259 | ``` 2260 | PublishSubject subject = PublishSubject.create(); 2261 | 2262 | Flowable flowable = subject 2263 | .toFlowable(BackpressureStrategy.DROP) 2264 | ``` 2265 | 2266 | There are also specialized operators to handle backpressure the onBackpressureXXX operators: **onBackpressureBuffer**, 2267 | **onBackpressureDrop**, **onBackpressureLatest** 2268 | 2269 | These operators request Long.MAX_VALUE(unbounded amount) from upstream and then take it upon themselves to manage the 2270 | requests from downstream. 2271 | In the case of _onBackpressureBuffer_ it adds in an internal queue and send downstream the events as requested, 2272 | _onBackpressureDrop_ just discards events that are received from upstream more than requested from downstream, 2273 | _onBackpressureLatest_ also drops emitted events excluding the last emitted event(most recent). 2274 | 2275 | ```java 2276 | Flowable flowable = createFlowable(10, BackpressureStrategy.MISSING) 2277 | .onBackpressureBuffer(5, () -> log.info("Buffer has overflown")); 2278 | 2279 | flowable = flowable 2280 | .observeOn(Schedulers.io(), false, 3); 2281 | subscribeWithSlowSubscriber(flowable); 2282 | 2283 | ===== 2284 | [main] - Started emitting 2285 | [main] - Emitting 0 2286 | [main] - Emitting 1 2287 | [RxCachedThreadScheduler-1] - Subscriber received: 0 2288 | [main] - Emitting 2 2289 | [main] - Emitting 3 2290 | [main] - Emitting 4 2291 | [main] - Emitting 5 2292 | [main] - Emitting 6 2293 | [main] - Emitting 7 2294 | [main] - Emitting 8 2295 | [main] - Emitting 9 2296 | [main] - Buffer has overflown 2297 | [RxCachedThreadScheduler-1] ERROR - Subscriber received error 'Buffer is full' 2298 | ``` 2299 | 2300 | We create the Flowable with _BackpressureStrategy.MISSING_ saying we don't care about backpressure 2301 | but let one of the onBackpressureXXX operators handle it. 2302 | Notice however 2303 | 2304 | 2305 | 2306 | Chaining together multiple onBackpressureXXX operators doesn't actually make sense 2307 | Using something like 2308 | 2309 | ```java 2310 | Flowable flowable = createFlowable(10, BackpressureStrategy.MISSING) 2311 | .onBackpressureBuffer(5) 2312 | .onBackpressureDrop((val) -> log.info("Dropping {}", val)) 2313 | flowable = flowable 2314 | .observeOn(Schedulers.io(), false, 3); 2315 | 2316 | subscribeWithSlowSubscriber(flowable); 2317 | ``` 2318 | 2319 | is not behaving as probably you'd expected - buffer 5 values, and then dropping overflowing events-. 2320 | Because _onBackpressureDrop_ subscribes to the previous _onBackpressureBuffer_ operator 2321 | signaling it's requesting **Long.MAX_VALUE**(unbounded amount) from it. 2322 | Thus **onBackpressureBuffer** will never feel its subscriber is overwhelmed and never "trigger", meaning that the last 2323 | onBackpressureXXX operator overrides the previous one if they are chained. 2324 | 2325 | Of course for implementing an event dropping strategy after a full buffer, there is the special overrided 2326 | version of **onBackpressureBuffer** that takes a **BackpressureOverflowStrategy**. 2327 | 2328 | ```java 2329 | Flowable flowable = createFlowable(10, BackpressureStrategy.MISSING) 2330 | .onBackpressureBuffer(5, () -> log.info("Buffer has overflown"), 2331 | BackpressureOverflowStrategy.DROP_OLDEST); 2332 | 2333 | flowable = flowable 2334 | .observeOn(Schedulers.io(), false, 3); 2335 | 2336 | subscribeWithSlowSubscriber(flowable); 2337 | 2338 | =============== 2339 | [main] - Started emitting 2340 | [main] - Emitting 0 2341 | [main] - Emitting 1 2342 | [RxCachedThreadScheduler-1] - Subscriber received: 0 2343 | [main] - Emitting 2 2344 | [main] - Emitting 3 2345 | [main] - Emitting 4 2346 | [main] - Emitting 5 2347 | [main] - Emitting 6 2348 | [main] - Emitting 7 2349 | [main] - Emitting 8 2350 | [main] - Buffer has overflown 2351 | [main] - Emitting 9 2352 | [main] - Buffer has overflown 2353 | [RxCachedThreadScheduler-1] - Subscriber received: 1 2354 | [RxCachedThreadScheduler-1] - Subscriber received: 2 2355 | [RxCachedThreadScheduler-1] - Subscriber received: 5 2356 | [RxCachedThreadScheduler-1] - Subscriber received: 6 2357 | [RxCachedThreadScheduler-1] - Subscriber received: 7 2358 | [RxCachedThreadScheduler-1] - Subscriber received: 8 2359 | [RxCachedThreadScheduler-1] - Subscriber received: 9 2360 | [RxCachedThreadScheduler-1] - Subscriber got Completed event 2361 | ``` 2362 | 2363 | onBackpressureXXX operators can be added whenever necessary and it's not limited to cold publishers and we can use them 2364 | on hot publishers also. 2365 | 2366 | ## Articles and books for further reading 2367 | [Reactive Programming with RxJava](http://shop.oreilly.com/product/0636920042228.do) 2368 | 2369 | 2370 | 2371 | 2372 | 2373 | 2374 | 2375 | 2376 | 2377 | 2378 | 2379 | 2380 | -------------------------------------------------------------------------------- /src/Algorithms/BFS.java: -------------------------------------------------------------------------------- 1 | package Algorithms; 2 | 3 | import Datastructures.Node; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | 7 | /** 8 | * Created by Naren on 5/21/17. 9 | */ 10 | public class BFS { 11 | 12 | void bfs(Node root) { 13 | 14 | Queue queue = new LinkedList<>(); 15 | queue.offer(root); 16 | 17 | while(!queue.isEmpty()){ 18 | Node node = queue.poll(); 19 | 20 | // Printing the traversal 21 | System.out.println(node.getData()); 22 | 23 | if(node.getLeft() != null){ 24 | queue.offer(node.getLeft()); 25 | } 26 | 27 | if(node.getRight() != null){ 28 | queue.offer(node.getRight()); 29 | } 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/Algorithms/BinarySearch.java: -------------------------------------------------------------------------------- 1 | package Algorithms; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by Naren on 5/19/17. 7 | */ 8 | public class BinarySearch { 9 | 10 | private int search(int[] arr, int num) { 11 | return binarySearchUtil(arr, num, 0, arr.length - 1); 12 | } 13 | 14 | private int binarySearchUtil(int[] arr, int num, int low, int high) { 15 | 16 | if(low > high){ 17 | return -1; 18 | } 19 | 20 | int mid = low + (high - low) / 2; 21 | if(arr[mid] > num) { 22 | return binarySearchUtil(arr, num, low, mid - 1); 23 | } else if(arr[mid] < num) { 24 | return binarySearchUtil(arr, num, mid + 1, high); 25 | } else { 26 | return mid; 27 | } 28 | } 29 | 30 | public static void main(String[] args) { 31 | 32 | BinarySearch search = new BinarySearch(); 33 | 34 | int[] arr = {1,2,3,4,5,2,3,5,1,2,43,3}; 35 | 36 | Arrays.sort(arr); 37 | 38 | System.out.print(search.search(arr, 43)); 39 | System.out.print(search.search(arr, 10)); 40 | System.out.print(search.search(arr, 2)); 41 | System.out.print(search.search(arr, 3)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Algorithms/DFS.java: -------------------------------------------------------------------------------- 1 | package Algorithms; 2 | 3 | import Datastructures.Node; 4 | import java.util.Stack; 5 | 6 | /** 7 | * Created by Naren on 5/21/17. 8 | */ 9 | public class DFS { 10 | 11 | void preOrderDFS(Node root) { 12 | 13 | if(root == null) 14 | return; 15 | 16 | Stack stack = new Stack<>(); 17 | stack.push(root); 18 | 19 | while(!stack.isEmpty()){ 20 | Node node = stack.pop(); 21 | 22 | // Printing the traversal 23 | System.out.println(node.getData()); 24 | 25 | Node left = node.getLeft(); 26 | Node right = node.getRight(); 27 | 28 | if(right != null){ 29 | stack.push(right); 30 | } 31 | 32 | if(left != null){ 33 | stack.push(left); 34 | } 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/Algorithms/MergeSortDemo.java: -------------------------------------------------------------------------------- 1 | package Algorithms; 2 | 3 | /** 4 | * Created by Naren on 5/22/17. 5 | */ 6 | public class MergeSortDemo { 7 | 8 | 9 | public static void MergeSort(int[] nums) { 10 | int leftStart = 0; 11 | int rightEnd = nums.length - 1; 12 | int[] temp = new int[nums.length]; 13 | mergeSort(nums, temp, leftStart, rightEnd); 14 | } 15 | 16 | private static void mergeSort(int[] nums,int[] temp, int leftStart, int rightEnd) { 17 | if(leftStart >= rightEnd) return; 18 | int mid = (leftStart + rightEnd) / 2; 19 | mergeSort(nums, temp, leftStart, mid); 20 | mergeSort(nums, temp, mid+1, rightEnd); 21 | merge(nums, temp, leftStart, rightEnd); 22 | } 23 | 24 | private static void merge(int[] nums, int[] temp, int leftStart, int rightEnd) { 25 | int leftEnd = (leftStart + rightEnd) / 2; 26 | int rightStart = leftEnd + 1; 27 | int size = rightEnd - leftStart + 1; 28 | 29 | int left = leftStart; 30 | int right = rightStart; 31 | int index = leftStart; 32 | 33 | while (left <= leftEnd && right <= rightEnd) { 34 | 35 | if(nums[left] <= nums[right]) { 36 | temp[index] = nums[left]; 37 | left++; 38 | } else { 39 | temp[index] = nums[right]; 40 | right++; 41 | } 42 | index++; 43 | } 44 | 45 | System.arraycopy(nums, left, temp, index, leftEnd - left + 1); 46 | System.arraycopy(nums, right, temp, index, rightEnd - right + 1); 47 | System.arraycopy(temp, leftStart, nums, leftStart, size); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Algorithms/QuickSortDemo.java: -------------------------------------------------------------------------------- 1 | package Algorithms; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by Naren on 5/22/17. 7 | */ 8 | public class QuickSortDemo { 9 | 10 | public static void quickSort(int[] arr) { 11 | int left = 0; 12 | int right = arr.length - 1; 13 | 14 | quickSort(arr, left, right); 15 | } 16 | 17 | private static void quickSort(int[] arr, int left, int right) { 18 | 19 | if(left >= right) return; 20 | int mid = (left+right) / 2; 21 | int pivot = arr[mid]; 22 | 23 | int pIndex = partition(arr, left, right, pivot); 24 | quickSort(arr, left, pIndex-1); 25 | quickSort(arr, pIndex, right); 26 | } 27 | 28 | private static int partition(int[] arr, int left, int right, int pivot) { 29 | 30 | while (left <= right) { 31 | 32 | while (arr[left] < pivot) { 33 | left++; 34 | } 35 | 36 | while (arr[right] > pivot) { 37 | right--; 38 | } 39 | 40 | if(left <= right) { 41 | swap(arr, left, right); 42 | left++; 43 | right--; 44 | } 45 | } 46 | return left; 47 | } 48 | 49 | private static void swap(int[] arr, int left, int right) { 50 | int temp = arr[left]; 51 | arr[left] = arr[right]; 52 | arr[right] = temp; 53 | } 54 | 55 | public static void main(String[] args) { 56 | 57 | int[] arr = {6,3,2,6,8,31,3,62,1,1,8}; 58 | 59 | quickSort(arr); 60 | 61 | System.out.println(Arrays.toString(arr)); 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Algorithms/SequentialSort.java: -------------------------------------------------------------------------------- 1 | package Algorithms; 2 | 3 | /** 4 | * Created by Naren on 5/19/17. 5 | */ 6 | public class SequentialSort { 7 | 8 | private int search(int[] arr, int target) { 9 | 10 | if(arr == null) return -1; 11 | 12 | for(int i =0; i< arr.length; i++) { 13 | if(arr[i] == target) return i; 14 | } 15 | return -1; 16 | } 17 | 18 | public static void main(String[] args) { 19 | 20 | int[] arr = {1,2,3,4,5,1,34,2}; 21 | 22 | SequentialSort sequentialSort = new SequentialSort(); 23 | 24 | System.out.println(sequentialSort.search(arr, 5)); 25 | System.out.println(sequentialSort.search(arr, 10)); 26 | System.out.println(sequentialSort.search(arr, 1)); 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Datastructures/ArrayDemo.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by Naren on 5/20/17. 8 | */ 9 | public class ArrayDemo { 10 | 11 | 12 | 13 | public static void main(String[] args) { 14 | 15 | int[] arr1 = new int[10]; 16 | arr1[0] = 10; 17 | int[] arr2 = {1,2, 2, 3, 5,6 ,3,4}; 18 | 19 | System.out.println(arr2.length); 20 | 21 | Arrays.stream(arr2) 22 | .distinct() 23 | .filter(p -> p > 2) 24 | .sorted() 25 | .forEach(System.out::println); 26 | 27 | Arrays.sort(arr1); 28 | 29 | Arrays.fill(arr1, 0); 30 | 31 | List arrList = Arrays.asList(arr2); 32 | 33 | String strArr = Arrays.toString(arr1); 34 | 35 | System.out.println(strArr); 36 | 37 | String name = "Naren"; 38 | 39 | System.out.println(name.charAt(0)); 40 | 41 | System.out.println(name.toCharArray()); 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/Datastructures/BinarySearchTree.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | /** 4 | * Created by Naren on 5/19/17. 5 | */ 6 | public class BinarySearchTree implements BST { 7 | 8 | private TreeNode root; 9 | 10 | @Override 11 | public void add(int val) { 12 | root = add(val, root); 13 | } 14 | 15 | private TreeNode add(int val, TreeNode node) { 16 | if(node == null) { 17 | node = new TreeNode(val); 18 | return node; 19 | } 20 | if(node.val > val) 21 | node.left = add(val, node.left); 22 | else if(node.val < val) 23 | node.right = add(val, node.right); 24 | return node; 25 | } 26 | 27 | @Override 28 | public TreeNode search(int val, TreeNode node) { 29 | if(node == null || node.val == val) { 30 | return node; 31 | } 32 | 33 | if(val < node.val) 34 | return search(val, root.left); 35 | 36 | return search(val, root.right); 37 | } 38 | 39 | @Override 40 | public int minVal(TreeNode r) { 41 | while (r.left != null) { 42 | r = r.left; 43 | } 44 | 45 | return r.val; 46 | } 47 | 48 | @Override 49 | public void preOrder(TreeNode root) { 50 | if(root == null) { 51 | return; 52 | } 53 | else { 54 | System.out.println(root.val); 55 | preOrder(root.left); 56 | preOrder(root.right); 57 | } 58 | } 59 | 60 | @Override 61 | public void inOrder(TreeNode root) { 62 | if(root == null) { 63 | return; 64 | } 65 | else { 66 | inOrder(root.left); 67 | System.out.println(root.val); 68 | inOrder(root.right); 69 | } 70 | } 71 | 72 | @Override 73 | public void postOrder(TreeNode root) { 74 | if(root == null) { 75 | return; 76 | } 77 | else { 78 | postOrder(root.left); 79 | postOrder(root.right); 80 | System.out.println(root.val); 81 | } 82 | } 83 | 84 | @Override 85 | public void del(int val) { 86 | root = del(root, val); 87 | } 88 | 89 | 90 | private TreeNode del(TreeNode root, int val) { 91 | // If tree is empty, return null. 92 | if (root == null) return null; 93 | 94 | // Else, recursively traverse the tree. 95 | if (val < root.val) 96 | root.left = del(root.left, val); 97 | else if (val > root.val) 98 | root.right = del(root.right, val); 99 | else { 100 | // If node has only one child or no children. 101 | if (root.left == null) 102 | return root.right; 103 | else if (root.right == null) 104 | return root.left; 105 | 106 | // If node has two children, replace current node's value with the 107 | // minimum value in the node's right subtree. 108 | root.val = minVal(root.right); 109 | 110 | // Delete the inorder successor. 111 | root.right = del(root.right, root.val); 112 | } 113 | return root; 114 | } 115 | 116 | public static void main(String[] args) { 117 | BinarySearchTree bst = new BinarySearchTree(); 118 | bst.add(10); 119 | bst.add(5); 120 | bst.add(15); 121 | bst.add(16); 122 | bst.add(13); 123 | bst.add(152); 124 | System.out.println(bst.search(5, bst.root)); 125 | bst.preOrder(bst.root); 126 | bst.inOrder(bst.root); 127 | bst.postOrder(bst.root); 128 | } 129 | } 130 | 131 | interface BST { 132 | 133 | void add(int val); 134 | 135 | TreeNode search(int val, TreeNode node); 136 | 137 | int minVal(TreeNode r); 138 | 139 | void del(int val); 140 | 141 | void preOrder(TreeNode root); 142 | 143 | void inOrder(TreeNode root); 144 | 145 | void postOrder(TreeNode root); 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/Datastructures/BinaryTree.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | /** 4 | * Created by Naren on 5/19/17. 5 | */ 6 | public class BinaryTree { 7 | 8 | private TreeNode root; 9 | 10 | public static void main(String[] args) { 11 | 12 | BinaryTree binaryTree = new BinaryTree(); 13 | TreeNode root = new TreeNode(10); 14 | binaryTree.root = root; 15 | TreeNode left_1 = new TreeNode(5); 16 | TreeNode right_1 = new TreeNode(5); 17 | root.left = left_1; 18 | root.right = right_1; 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Datastructures/Graph.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | import java.util.ArrayDeque; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | 7 | /** 8 | * Created by Naren on 5/19/17. 9 | */ 10 | public class Graph 11 | { 12 | private int V; // No. of vertices 13 | private LinkedList[] adj; //Adjacency Lists 14 | 15 | // Constructor 16 | Graph(int v) 17 | { 18 | V = v; 19 | adj = new LinkedList[v]; 20 | for (int i=0; i(); 22 | } 23 | 24 | // Function to add an edge into the graph 25 | private void addEdge(int v, int w) 26 | { 27 | adj[v].offer(w); 28 | } 29 | 30 | 31 | private void BFS(int v) { 32 | 33 | boolean visited[] = new boolean[v]; 34 | 35 | Queue queue = new ArrayDeque<>(); 36 | queue.offer(v); 37 | while (queue.size() != 0) { 38 | int s = queue.poll(); 39 | System.out.println(s + " ->"); 40 | 41 | for (Integer i : queue) { 42 | if (!visited[i]) { 43 | visited[i] = true; 44 | queue.offer(i); 45 | } 46 | } 47 | 48 | } 49 | 50 | } 51 | 52 | 53 | public static void main(String[] args) { 54 | 55 | int[][] adjMatrix = new int[][]{{1, 1, 0, 0, 0}, 56 | {0, 1, 0, 0, 1}, 57 | {1, 0, 0, 1, 1}, 58 | {0, 0, 0, 0, 0}, 59 | {1, 0, 1, 0, 1}}; 60 | 61 | Graph g = new Graph(4); 62 | 63 | g.addEdge(0, 1); 64 | g.addEdge(0, 2); 65 | g.addEdge(1, 2); 66 | g.addEdge(2, 0); 67 | g.addEdge(2, 3); 68 | g.addEdge(3, 3); 69 | 70 | g.BFS(2); 71 | 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/Datastructures/LRUCacheDemo.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by Naren on 5/22/17. 8 | */ 9 | public class LRUCacheDemo { 10 | 11 | private class Node { 12 | int key, value; 13 | Node prev, next; 14 | Node(int k, int v){ 15 | this.key = k; 16 | this.value = v; 17 | } 18 | Node(){ 19 | this(0, 0); 20 | } 21 | } 22 | 23 | private int capacity, count; 24 | private Map map; 25 | private Node head, tail; 26 | 27 | public LRUCacheDemo(int capacity) { 28 | this.capacity = capacity; 29 | this.count = 0; 30 | map = new HashMap<>(); 31 | head = new Node(); 32 | tail = new Node(); 33 | head.next = tail; 34 | tail.prev = head; 35 | } 36 | 37 | public int get(int key) { 38 | Node n = map.get(key); 39 | if(n == null){ 40 | return -1; 41 | } 42 | update(n); 43 | return n.value; 44 | } 45 | 46 | public void set(int key, int value) { 47 | Node n = map.get(key); 48 | if(n == null){ 49 | n = new Node(key, value); 50 | map.put(key, n); 51 | add(n); 52 | ++count; 53 | } 54 | else{ 55 | n.value = value; 56 | update(n); 57 | } 58 | if(count>capacity){ 59 | Node toDel = tail.prev; 60 | remove(toDel); 61 | map.remove(toDel.key); 62 | --count; 63 | } 64 | } 65 | 66 | private void update(Node node){ 67 | remove(node); 68 | add(node); 69 | } 70 | private void add(Node node){ 71 | Node after = head.next; 72 | head.next = node; 73 | node.prev = head; 74 | node.next = after; 75 | after.prev = node; 76 | } 77 | 78 | private void remove(Node node){ 79 | Node before = node.prev; 80 | Node after = node.next; 81 | before.next = after; 82 | after.prev = before; 83 | } 84 | } -------------------------------------------------------------------------------- /src/Datastructures/LinkedListDemo.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | 7 | /** 8 | * Created by Naren on 5/19/17. 9 | */ 10 | public class LinkedListDemo { 11 | 12 | 13 | public static void main(String[] args) { 14 | 15 | List integerList = new LinkedList<>(); 16 | 17 | integerList.add(10); 18 | integerList.add(80); 19 | integerList.add(90); 20 | integerList.add(40); 21 | integerList.add(50); 22 | integerList.add(60); 23 | 24 | integerList.forEach(System.out::println); 25 | 26 | integerList.sort(Integer::compareTo); 27 | 28 | System.out.println(); 29 | 30 | Iterator integerIterator = integerList.iterator(); 31 | 32 | while (integerIterator.hasNext()) { 33 | int x = integerIterator.next(); 34 | if(x == 50) integerIterator.remove(); 35 | } 36 | 37 | // integerList.removeIf(x -> x == 50); 38 | 39 | 40 | integerList.remove(integerList.size()-1); 41 | 42 | integerList.forEach(System.out::println); 43 | 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/Datastructures/Node.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | /** 4 | * Created by Naren on 5/21/17. 5 | */ 6 | public class Node { 7 | private Object data; 8 | private Node left; 9 | private Node right; 10 | 11 | Node(Object item, Node left, Node right){ 12 | this.data = item; 13 | this.left = left; 14 | this.right = right; 15 | } 16 | 17 | public Object getData() { 18 | return data; 19 | } 20 | 21 | public Node getLeft() { 22 | return left; 23 | } 24 | 25 | public Node getRight() { 26 | return right; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/Datastructures/QueueDemo.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | import java.util.ArrayDeque; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | 7 | /** 8 | * Created by Naren on 5/19/17. 9 | */ 10 | public class QueueDemo { 11 | 12 | 13 | public static void main(String[] args) { 14 | 15 | Queue queue = new LinkedList<>(); 16 | 17 | queue.offer("sup"); 18 | queue.offer("hi"); 19 | queue.offer("hey"); 20 | queue.offer("hello"); 21 | 22 | queue.forEach(System.out::print); 23 | 24 | System.out.println(queue.poll()); 25 | 26 | System.out.println(queue.peek()); 27 | 28 | queue.forEach(System.out::print); 29 | 30 | System.out.println(queue.isEmpty()); 31 | 32 | System.out.println(queue.size()); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/Datastructures/StackDemo.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by Naren on 5/19/17. 7 | */ 8 | public class StackDemo { 9 | 10 | public static void main(String[] args) { 11 | 12 | Stack stack = new Stack<>(); 13 | 14 | stack.push(10); 15 | stack.push(20); 16 | stack.push(30); 17 | stack.push(40); 18 | 19 | stack.forEach(System.out::print); 20 | 21 | System.out.println(stack.pop()); 22 | 23 | System.out.println(stack.peek()); 24 | 25 | System.out.println(stack.empty()); 26 | 27 | System.out.println(stack.isEmpty()); 28 | 29 | System.out.println(stack.size()); 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/Datastructures/TreeNode.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | /** 4 | * Created by Naren on 5/19/17. 5 | */ 6 | public class TreeNode { 7 | 8 | public int val; 9 | public TreeNode left, right = null; 10 | 11 | TreeNode(int val) { 12 | this.val = val; 13 | } 14 | } -------------------------------------------------------------------------------- /src/Datastructures/Trie.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | /** 4 | * Created by Naren on 5/19/17. 5 | */ 6 | public class Trie { 7 | private TrieNode root; 8 | 9 | public Trie() { 10 | root = new TrieNode(); 11 | } 12 | 13 | // Inserts a word into the trie. 14 | public void insert(String word) { 15 | TrieNode node = root; 16 | 17 | for (int i = 0; i < word.length(); i++) { 18 | char c = word.charAt(i); 19 | int index = c - 'a'; 20 | if (node.children[index] == null) { 21 | TrieNode temp = new TrieNode(c); 22 | node.children[index] = temp; 23 | node = temp; 24 | } else { 25 | node = node.children[index]; 26 | } 27 | } 28 | 29 | node.isEnd = true; 30 | } 31 | 32 | // Returns if the word is in the trie. 33 | public boolean search(String word) { 34 | TrieNode node = searchNode(word); 35 | 36 | if (node == null) { 37 | return false; 38 | } else { 39 | return node.isEnd; 40 | } 41 | } 42 | 43 | // Returns if there is any word in the trie that starts with the given prefix. 44 | public boolean startsWith(String prefix) { 45 | TrieNode node = searchNode(prefix); 46 | 47 | if (node == null) { 48 | return false; 49 | } else { 50 | return true; 51 | } 52 | } 53 | 54 | public TrieNode searchNode(String s) { 55 | TrieNode node = root; 56 | 57 | for (int i = 0; i < s.length(); i++) { 58 | char c = s.charAt(i); 59 | int index = c - 'a'; 60 | if (node.children[index] != null) { 61 | node = node.children[index]; 62 | } else { 63 | return null; 64 | } 65 | } 66 | 67 | if (node == root) return null; 68 | 69 | return node; 70 | } 71 | 72 | public static void main(String[] args) { 73 | 74 | Trie trie = new Trie(); 75 | trie.insert("Naren"); 76 | trie.insert("Nathan"); 77 | 78 | System.out.println(trie.search("Naren")); 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/Datastructures/TrieNode.java: -------------------------------------------------------------------------------- 1 | package Datastructures; 2 | 3 | /** 4 | * Created by Naren on 5/19/17. 5 | */ 6 | public class TrieNode { 7 | char c; 8 | 9 | TrieNode[] children = new TrieNode[26]; 10 | boolean isEnd; 11 | 12 | public TrieNode(char c) { 13 | this.c = c; 14 | } 15 | 16 | public TrieNode() { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DateTime/LocalDateTimeDemo.java: -------------------------------------------------------------------------------- 1 | package DateTime; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import java.time.LocalTime; 6 | import java.time.Month; 7 | import java.time.ZoneId; 8 | import java.time.ZonedDateTime; 9 | 10 | /** 11 | * Created by Naren on 6/3/17. 12 | */ 13 | public class LocalDateTimeDemo { 14 | 15 | public LocalDate myBirthday() { 16 | return LocalDate.of(1993, Month.SEPTEMBER, 20); 17 | } 18 | 19 | public LocalTime myBirthdayTime() { 20 | return LocalTime.of(5, 20); 21 | } 22 | 23 | public LocalDateTime myBirthdayDateTime() { 24 | return LocalDateTime.of(myBirthday(), myBirthdayTime()); 25 | } 26 | 27 | public LocalDateTime timeNow() { 28 | return LocalDateTime.now(); 29 | } 30 | 31 | public int getDiffBetweenParisLondon() { 32 | 33 | ZonedDateTime paris = ZonedDateTime.now(ZoneId.of("Europe/Paris")); 34 | ZonedDateTime london = ZonedDateTime.now(ZoneId.of("Europe/London")); 35 | 36 | return paris.getDayOfMonth() - london.getDayOfMonth(); 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Leetcode/BinaryTreeLevelOrder.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import Datastructures.TreeNode; 4 | import java.util.ArrayList; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.Queue; 8 | 9 | /** 10 | * Created by Naren on 5/21/17. 11 | */ 12 | public class BinaryTreeLevelOrder { 13 | 14 | public List> levelOrder(TreeNode root) { 15 | 16 | List> result = new ArrayList<>(); 17 | 18 | if(root == null) 19 | return result; 20 | 21 | Queue queue = new LinkedList<>(); 22 | queue.add(root); 23 | 24 | while(!queue.isEmpty()) { 25 | Queue currentLevel = new LinkedList<>(); 26 | List list = new ArrayList<>(); 27 | 28 | while(!queue.isEmpty()) { 29 | TreeNode current = queue.remove(); 30 | 31 | if(current.left != null) { 32 | currentLevel.add(current.left); 33 | list.add(current.left.val); 34 | } 35 | 36 | if(current.right != null) { 37 | currentLevel.add(current.right); 38 | list.add(current.right.val); 39 | } 40 | } 41 | 42 | if(list.size() > 0) { 43 | result.add(list); 44 | } 45 | queue = currentLevel; 46 | } 47 | return result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Leetcode/ClimbStairs.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | /** 4 | * Created by Naren on 5/22/17. 5 | */ 6 | public class ClimbStairs { 7 | 8 | private static int climbs(int n) { 9 | 10 | if (n <= 0) return 0; 11 | if (n == 1) return 1; 12 | if (n == 2) return 2; 13 | 14 | 15 | int one = 2; 16 | int two = 1; 17 | int result = 0; 18 | 19 | for (int i = 2; i < n; i++) { 20 | result = one + two; 21 | two = one; 22 | one = result; 23 | } 24 | 25 | return result; 26 | } 27 | 28 | public static void main(String[] args) { 29 | System.out.println(climbs(4)); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/Leetcode/ConcatStringStream.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.Collectors; 5 | 6 | /** 7 | * Created by Naren on 5/21/17. 8 | */ 9 | public class ConcatStringStream { 10 | 11 | public static void main(String[] args) { 12 | 13 | String[] names = {"Narendra", "Kumar", "Manoharan"}; 14 | 15 | String res = Arrays.stream(names) 16 | .collect(Collectors.joining(" ")); 17 | 18 | System.out.println(res); 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Leetcode/FizzBuzz.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by Naren on 5/22/17. 8 | */ 9 | public class FizzBuzz { 10 | 11 | private static List FizzBuzzDemo(int n) { 12 | 13 | List result = new ArrayList<>(); 14 | 15 | for(int i=1; i <=n ; i++) { 16 | 17 | if (i % 3 == 0 && i % 5 == 0) { 18 | result.add("FizzBuzz"); 19 | } 20 | else if(i % 3 == 0) { 21 | result.add("Fizz"); 22 | } 23 | else if(i % 5 == 0) { 24 | result.add("Buzz"); 25 | } 26 | else { 27 | result.add(Integer.toString(i)); 28 | } 29 | } 30 | 31 | return result; 32 | } 33 | 34 | public static void main(String[] args) { 35 | 36 | System.out.println(FizzBuzzDemo(35)); 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/Leetcode/InvertTree.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import Datastructures.TreeNode; 4 | 5 | /** 6 | * Created by Naren on 5/23/17. 7 | */ 8 | public class InvertTree { 9 | 10 | private TreeNode invertTree(TreeNode root) { 11 | if (root == null) 12 | return null; 13 | TreeNode tmp = root.left; 14 | root.left = invertTree(root.right); 15 | root.right = invertTree(tmp); 16 | return root; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/Leetcode/LinkedListRandomPtr.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | /** 4 | * Created by Naren on 5/21/17. 5 | */ 6 | public class LinkedListRandomPtr { 7 | 8 | /* 9 | The idea is: 10 | Step 1: create a new node for each existing node and join them together 11 | eg: A->B->C will be A->A'->B->B'->C->C' 12 | 13 | Step2: copy the random links: for each new node n', n'.random = n.random.next 14 | 15 | Step3: detach the list: basically n.next = n.next.next; n'.next = n'.next.next 16 | 17 | An intuitive solution is to keep a hash table for each node in the list, via which we just need to iterate the list in 2 rounds respectively to create nodes and assign the values for their random pointers. As a result, the space complexity of this solution is O(N), although with a linear time complexity. 18 | 19 | As an optimised solution, we could reduce the space complexity into constant. The idea is to associate the original node with its copy node in a single linked list. In this way, we don't need extra space to keep track of the new nodes. 20 | 21 | The algorithm is composed of the follow three steps which are also 3 iteration rounds. 22 | 23 | Iterate the original list and duplicate each node. The duplicate 24 | of each node follows its original immediately. 25 | 26 | Iterate the new list and assign the random pointer for each 27 | duplicated node. 28 | 29 | Restore the original list and extract the duplicated nodes. 30 | */ 31 | 32 | public RandomListNode copyRandomList(RandomListNode head) { 33 | if(head == null){ 34 | return null; 35 | } 36 | 37 | // Creating the copy = orig_head -> new_head -> orig_sec -> next_sec 38 | RandomListNode n = head; 39 | while (n!=null){ 40 | RandomListNode n1 = new RandomListNode(n.label); 41 | RandomListNode tmp = n.next; 42 | n.next = n1; 43 | n1.next = tmp; 44 | n = tmp; 45 | } 46 | 47 | // Copy the random pointers 48 | n = head; 49 | while(n != null){ 50 | RandomListNode n1 = n.next; 51 | if(n.random != null) 52 | n1.random = n.random.next; 53 | else 54 | n1.random = null; 55 | n = n.next.next; 56 | } 57 | 58 | //detach list 59 | RandomListNode n1 = head.next; 60 | n = head; 61 | RandomListNode head2 = head.next; 62 | while(n1 != null && n != null){ 63 | n.next = n.next.next; 64 | if (n1.next == null){ 65 | break; 66 | } 67 | n1.next = n1.next.next; 68 | n1 = n1.next; 69 | n = n.next; 70 | } 71 | 72 | return head2; 73 | } 74 | } 75 | 76 | class RandomListNode { 77 | 78 | int label; 79 | RandomListNode next, random; 80 | 81 | RandomListNode(int x) { 82 | this.label = x; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Leetcode/MaximumPathSum.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | /** 4 | * Created by Naren on 5/21/17. 5 | */ 6 | class MaximumPathSum { 7 | 8 | // Root of the Binary Tree 9 | private Node root; 10 | 11 | // This function returns overall maximum path sum in 'res' 12 | // And returns max path sum going through root. 13 | private int findMaxUtil(Node node, Res res) 14 | { 15 | 16 | // Base Case 17 | if (node == null) 18 | return 0; 19 | 20 | // l and r store maximum path sum going through left and 21 | // right child of root respectively 22 | int l = findMaxUtil(node.left, res); 23 | int r = findMaxUtil(node.right, res); 24 | 25 | // Max path for parent call of root. This path must 26 | // include at-most one child of root 27 | int max_single = Math.max(Math.max(l, r) + node.data, 28 | node.data); 29 | 30 | 31 | // Max Top represents the sum when the Node under 32 | // consideration is the root of the maxsum path and no 33 | // ancestors of root are there in max sum path 34 | int max_top = Math.max(max_single, l + r + node.data); 35 | 36 | // Store the Maximum Result. 37 | res.val = Math.max(res.val, max_top); 38 | 39 | return max_single; 40 | } 41 | 42 | private int findMaxSum() { 43 | return findMaxSum(root); 44 | } 45 | 46 | // Returns maximum path sum in tree with given root 47 | private int findMaxSum(Node node) { 48 | 49 | // Initialize result 50 | // int res2 = Integer.MIN_VALUE; 51 | Res res = new Res(); 52 | res.val = Integer.MIN_VALUE; 53 | 54 | // Compute and return result 55 | findMaxUtil(node, res); 56 | return res.val; 57 | } 58 | 59 | /* Driver program to test above functions */ 60 | public static void main(String args[]) { 61 | MaximumPathSum tree = new MaximumPathSum(); 62 | tree.root = new Node(10); 63 | tree.root.left = new Node(2); 64 | tree.root.right = new Node(10); 65 | tree.root.left.left = new Node(20); 66 | tree.root.left.right = new Node(1); 67 | tree.root.right.right = new Node(-25); 68 | tree.root.right.right.left = new Node(3); 69 | tree.root.right.right.right = new Node(4); 70 | System.out.println("maximum path sum is : " + 71 | tree.findMaxSum()); 72 | } 73 | } 74 | 75 | /* Class containing left and right child of current 76 | node and key value*/ 77 | class Node { 78 | 79 | int data; 80 | Node left, right; 81 | 82 | Node(int item) { 83 | data = item; 84 | left = right = null; 85 | } 86 | } 87 | 88 | // An object of Res is passed around so that the 89 | // same value can be used by multiple recursive calls. 90 | class Res { 91 | int val; 92 | } 93 | -------------------------------------------------------------------------------- /src/Leetcode/MinStack.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by Naren on 5/23/17. 7 | */ 8 | class MinStack { 9 | 10 | private int min = Integer.MAX_VALUE; 11 | private Stack stack = new Stack<>(); 12 | 13 | public void push(int x) { 14 | // only push the old minimum value when the current 15 | // minimum value changes after pushing the new value x 16 | if(x <= min){ 17 | stack.push(min); 18 | min=x; 19 | } 20 | stack.push(x); 21 | } 22 | 23 | public void pop() { 24 | // if pop operation could result in the changing of the current minimum value, 25 | // pop twice and change the current minimum value to the last minimum value. 26 | if(stack.pop() == min) 27 | min=stack.pop(); 28 | } 29 | 30 | public int top() { 31 | return stack.peek(); 32 | } 33 | 34 | public int getMin() { 35 | return min; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Leetcode/MoveZeroesDemo.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by Naren on 5/22/17. 7 | */ 8 | public class MoveZeroesDemo { 9 | 10 | private void MoveZeroes(int[] nums) { 11 | 12 | int start = 0; 13 | int end = nums.length - 1; 14 | 15 | while (start= m || col < 0 || col >= n || grid[row][col] == 0) { 31 | return; 32 | } 33 | 34 | grid[row][col] = 0; 35 | 36 | sinkNeighbours(grid, row-1, col); 37 | sinkNeighbours(grid, row+1, col); 38 | sinkNeighbours(grid, row, col+1); 39 | sinkNeighbours(grid, row, col-1); 40 | } 41 | 42 | public static void main(String[] args) { 43 | int[][] grid = new int[][] {{0,0,0,1,1,0,0}, 44 | {0,1,0,0,1,1,0}, 45 | {1,1,0,1,0,0,1}, 46 | {0,0,0,0,0,1,0}, 47 | {1,1,0,0,0,0,0}, 48 | {0,0,0,1,0,0,0}}; 49 | 50 | System.out.println(numIslands(grid)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Leetcode/Power.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | /** 4 | * Created by Naren on 5/21/17. 5 | */ 6 | public class Power { 7 | 8 | private static double myPow(double num, int pow) { 9 | 10 | if(pow == 0) { 11 | return 1; 12 | } 13 | 14 | if(Double.isInfinite(num)) { 15 | return 0; 16 | } 17 | 18 | if(pow < 0) { 19 | pow = -pow; 20 | num = 1 / num; 21 | } 22 | 23 | if(pow % 2 == 0) { 24 | return myPow(num * num, pow / 2); 25 | } else { 26 | return num * myPow(num * num, pow / 2); 27 | } 28 | 29 | } 30 | 31 | 32 | public static void main(String[] args) { 33 | 34 | System.out.println(myPow(10, 2)); 35 | System.out.println(myPow(5, 3)); 36 | System.out.println(myPow(4, 4)); 37 | System.out.println(myPow(0, 2)); 38 | System.out.println(myPow(16, 0)); 39 | 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Leetcode/RandomDemo.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | import java.util.Random; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * Created by Naren on 5/21/17. 10 | */ 11 | public class RandomDemo { 12 | 13 | public static void main(String[] args) { 14 | 15 | List random = Collections.unmodifiableList(new Random() 16 | .ints(0, 101) 17 | .limit(20) 18 | .boxed() 19 | .collect(Collectors.toList())); 20 | 21 | System.out.println(random); 22 | 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/Leetcode/SpiralDemo.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by Naren on 5/22/17. 8 | */ 9 | public class SpiralDemo { 10 | 11 | public List spiralOrder(int[][] matrix) { 12 | 13 | List res = new ArrayList<>(); 14 | 15 | if (matrix.length == 0) { 16 | return res; 17 | } 18 | 19 | int rowBegin = 0; 20 | int rowEnd = matrix.length-1; 21 | int colBegin = 0; 22 | int colEnd = matrix[0].length - 1; 23 | 24 | while (rowBegin <= rowEnd && colBegin <= colEnd) { 25 | // Traverse Right 26 | for (int j = colBegin; j <= colEnd; j ++) { 27 | res.add(matrix[rowBegin][j]); 28 | } 29 | rowBegin++; 30 | 31 | // Traverse Down 32 | for (int j = rowBegin; j <= rowEnd; j ++) { 33 | res.add(matrix[j][colEnd]); 34 | } 35 | colEnd--; 36 | 37 | if (rowBegin <= rowEnd) { 38 | // Traverse Left 39 | for (int j = colEnd; j >= colBegin; j --) { 40 | res.add(matrix[rowEnd][j]); 41 | } 42 | } 43 | rowEnd--; 44 | 45 | if (colBegin <= colEnd) { 46 | // Traver Up 47 | for (int j = rowEnd; j >= rowBegin; j --) { 48 | res.add(matrix[j][colBegin]); 49 | } 50 | } 51 | colBegin ++; 52 | } 53 | 54 | return res; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/Leetcode/TwoSum.java: -------------------------------------------------------------------------------- 1 | package Leetcode; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.HashSet; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.Set; 10 | import java.util.stream.Collectors; 11 | 12 | /** 13 | * Created by Naren on 5/21/17. 14 | */ 15 | public class TwoSum { 16 | 17 | 18 | private static Set calculatePairs(List nums, int target) { 19 | 20 | Set res = new HashSet<>(); 21 | 22 | if(nums.size() == 0) { 23 | return Collections.emptySet(); 24 | } 25 | 26 | HashSet integers = new HashSet<>(); 27 | 28 | for (Integer n: nums) { 29 | int val = target - n; 30 | if(!integers.contains(val)) { 31 | integers.add(val); 32 | } 33 | } 34 | 35 | Iterator intIterator = nums.iterator(); 36 | 37 | Integer n = null; 38 | 39 | while (intIterator.hasNext()) { 40 | n = intIterator.next(); 41 | if (integers.contains(n)) { 42 | Pair newPair = new Pair(n, target - n); 43 | res.add(newPair); 44 | } 45 | } 46 | 47 | return res; 48 | } 49 | 50 | public static void main(String[] args) { 51 | 52 | Integer[] num = {-10, 4, 1, 2, 3, 3, 3, 5, 15, 23}; 53 | 54 | int target = 6; 55 | 56 | List nums = Arrays.asList(num); 57 | 58 | Set result = calculatePairs(nums, target); 59 | 60 | result.forEach(System.out::println); 61 | 62 | } 63 | } 64 | 65 | class Pair { 66 | 67 | private int left; 68 | private int right; 69 | 70 | public Pair(int left, int right) { 71 | this.left = left; 72 | this.right = right; 73 | } 74 | 75 | @Override public boolean equals(Object o) { 76 | if (this == o) return true; 77 | if (o == null || getClass() != o.getClass()) return false; 78 | Pair pair = (Pair) o; 79 | return left == pair.right && right == pair.left || left == pair.left && right == pair.right; 80 | } 81 | 82 | @Override public int hashCode() { 83 | int result = left; 84 | result = 31 * result + right; 85 | return result; 86 | } 87 | 88 | @Override public String toString() { 89 | return "Pair{" + "left=" + left + ", right=" + right + '}'; 90 | } 91 | } -------------------------------------------------------------------------------- /src/test/DateTime/LocalDateTimeTest.java: -------------------------------------------------------------------------------- 1 | package DateTime; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import java.time.LocalTime; 6 | import org.junit.Assert; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Created by Naren on 6/3/17. 14 | */ 15 | public class LocalDateTimeTest { 16 | 17 | private LocalDateTimeDemo dateTimeDemo; 18 | 19 | @Before 20 | public void before() { 21 | dateTimeDemo = new LocalDateTimeDemo(); 22 | } 23 | 24 | @Test 25 | public void myBirthdayTest() { 26 | 27 | final LocalDate myBirthday = dateTimeDemo.myBirthday(); 28 | 29 | assertEquals(1993, myBirthday.getYear()); 30 | assertEquals(20, myBirthday.getDayOfMonth()); 31 | assertEquals(9, myBirthday.getMonthValue()); 32 | } 33 | 34 | @Test 35 | public void myBirthdayTimeTest() { 36 | 37 | final LocalTime myBirthdayTime = dateTimeDemo.myBirthdayTime(); 38 | 39 | assertEquals(5, myBirthdayTime.getHour()); 40 | assertEquals(20, myBirthdayTime.getMinute()); 41 | } 42 | 43 | @Test public void timeNowTest() { 44 | 45 | final LocalDateTime now = dateTimeDemo.timeNow(); 46 | 47 | assertEquals(LocalDateTime.now().getHour(), now.getHour()); 48 | } 49 | 50 | @Test public void getDifferenceParisLondonTest() { 51 | 52 | final int diff = dateTimeDemo.getDiffBetweenParisLondon(); 53 | 54 | assertEquals(0, diff); 55 | } 56 | 57 | @Test public void myBirthdayDateTimeTest() throws Exception { 58 | 59 | final LocalDateTime myBirthdayDateTime = dateTimeDemo.myBirthdayDateTime(); 60 | 61 | assertEquals(20, myBirthdayDateTime.getDayOfMonth()); 62 | assertEquals(1993, myBirthdayDateTime.getYear()); 63 | 64 | } 65 | } 66 | --------------------------------------------------------------------------------