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 super T> 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 | 
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 | 
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 | 
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 | 
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 super Integer> 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 super Integer> actualSubscriber;
2079 |
2080 | CustomRangeSubscription(int startFrom, int count, Subscriber super Integer> 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 |
--------------------------------------------------------------------------------