User Tools

Site Tools


programming:java:java8

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
programming:java:java8 [2023/11/01 07:31] – removed - external edit (Unknown date) 127.0.0.1programming:java:java8 [2023/11/01 07:31] (current) – ↷ Page moved from camunda:programming:java:java8 to programming:java:java8 skipidar
Line 1: Line 1:
 +===== Java8 =====
 +New features:
 +  * Methods as first class citizens
 +  * Lambdas
 +    * Passing code to methods (behavior parametrization)
 +  * Default methods in Interfaces
 +  * Streams
 +  * Nashorn
 +  * New Date API
 +  * Optional
 +
 +
 +===== Glossar =====
 +|Predicate|boolean function, which takes some input|
 +|Functional interface| Interface to pass behavior |
 +===== Literature =====
 +
 +|What's New in Java 8| https://leanpub.com/whatsnewinjava8/read |
 +
 +===== New Concepts =====
 +
 +|Behaviour parametrization |
 +|
 +===== Typing =====
 +Which type do new Java8 expressions have?
 +
 +<sxh java>
 +
 + // Function. Gets Ranking. Returns Integer.
 + Function<Ranking, Integer> f = ranking -> ranking.value;
 +
 + // Consumer - accepts sinle parameter. Returns nothing
 + Consumer<Ranking> c = Ranking:: echo; 
 +
 + // Predicate - boolean returning function
 + Predicate<Ranking> isLarger2 = ranking -> ranking.value > 2;
 +
 +
 +
 +
 + // MODELS
 +
 + static class Ranking{
 + int value;
 +
 + public static void echo(Object value){
 + System.out.println(String.format("Value is '%s'",value));
 + }
 + }
 +</sxh>
 +
 +
 +
 +===== Behaviour parametrization =====
 +
 +You can pass a method as a function-parameter.
 +For that the method-signature must define a **functional interface** as a paramter.
 +
 +  * functional Interfaces are located in package **java.util.function**
 +    * e.g. Consumer<A>
 +    * Biconsumer<A,B> ...
 +
 +
 +|Functional Interface|<WRAP> 
 +An interface with **exactly one** single **abstract** method. \\ 
 +The interface may have  many additional default methods. \\
 +Overriden abstract methods of Object.class - are not included in abstract interfacew, which count 
 +[[http://www.tutorialspoint.com/java8/java8_functional_interfaces.htm|Some functional inerfaces]] 
 +
 +</WRAP>|
 +
 +|<WRAP>
 +**Comparator is a functional interface**\\
 +Comparator is a functional interface, since it has two abstract methods:
 +  * equals
 +  * compare
 +and **equals** is a method from Object.class.
 +</WRAP>|
 +
 +|<WRAP>
 +**Object is NOT a functional interface**\\
 +It does not have a single abstract method. \\
 +Lambdas can't be assigned to Object variables
 +
 +<code>
 +Object o = () -> {return 2;} // invalid Object in not a functional interface
 +</code>
 +</WRAP>|
 +
 +== @FunctionalInterface == 
 +Functional Interfaces may be annotated with **@FunctionalInterface** to clarify what they are!
 +
 +== Exisiting generic functional interfaces ==
 +
 +The generic functions have following names:
 +|..Consumer | provides a method with input. No output|
 +|..Supplier | provides output. No input.|
 +|..Function | provides method with input. And with output.|
 +|..Predicate| provides a boolean function|
 +|..Operation | method with input and output of same type|
 +
 +
 +== Behaviour parametrization examples ==
 +
 +<sxh java>
 +class Test{
 +public static void main(String[] args){
 +
 +// passing myMethod, which may be used inside fun
 +Test.function(Test::myMethod);
 +
 +}
 +
 +
 +// As defined by class FunctionalInterface - you can pass any function in here, 
 +// which takes String as parameter AND
 +// which returns boolean
 +public void function(FunctionalInterface interface){
 +}
 +
 +static interface FunctionalInterface{
 + boolean function(String parameter); // defines a single function operating on String, returning boolean
 +}
 +
 +static class MyClass{
 + static boolean myMethod(String input){
 +  return true;
 + }
 +
 +}
 +</sxh>
 +===== Lambdas =====
 +
 +==Glossar==
 +
 +| Identifier | <WRAP>
 +Identifiers are used as names variables, functions. Identifiert 
 +  * starts with a **letter** or **_** or **$**
 +  * is not a java-keyword (keywords are lister here: https://docs.oracle.com/cd/E19798-01/821-1841/bnbuk/index.html)
 +<code>abcd123</code>
 +</WRAP> |
 +| Literals | <WRAP> 
 +Notations for **constant values**, **build in types**
 +<code>123.33</code>
 +</WRAP> |
 +| Operators | <WRAP>
 +  * Mathematical operators, 
 +  * call operators ()
 +  * array operator []
 +  * increment operator ++
 +The full operator list is here: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/opsummary.html
 +
 +**Not** operators:
 +<code>
 +print 
 +return
 +</code>
 +
 + </WRAP> |
 +| Expression | <WRAP> 
 +It contains:
 +  * identifiers, 
 +  * literals, 
 +  * operators
 +
 +Expressions:
 +<code>
 +"String is an expression too"
 +"Alan" + i
 +System.out.print("ho")
 +</code>
 +
 +</WRAP> |
 +| Statement | <WRAP>
 +  * Statements are made up of expressions.
 +  * Form a complete unit of execution
 +  * End with **;**
 +More here: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/expressions.html
 +
 +Statements:
 +<code>
 +System.out.print("ho");
 +return "Alan" + i;
 +</code>
 +
 + </WRAP> |
 +
 +
 +==Lamda Syntax==
 +
 +1. <code>(parameters) -> expression</code>
 +2. <code>(parameters) -> { statements; }</code>
 +
 +Lamda Examples:
 +<code>
 +() -> {} // valid 1
 +() -> "Raoul" // valid 1
 +() -> {return "Mario";} // valid 1
 +(Integer i) -> return "Alan" + i; // invalid. Valid version:  (Integer i) -> {return "Alan" + i;}
 +(String s) -> {"Iron Man";} // invalid. Valid version:  (String s) -> {return "Iron Man";
 +</code>
 +
 +
 +More valid examples:
 +<sxh java>
 +(TYPE name) -> FUNCTION(name)
 +(String s) -> s.toUpperCase() + " !!!"
 +(Apple a) -> a.getWeigth() > 150
 +</sxh>
 +
 +
 +== Type inference ==
 +Compiler can deduce the input type from the functional interface. \\
 +So you can omit the type in lambdas.
 +
 +legal usages of lamdas: \\
 +<code>
 +List<Apple> greenApples = filter(inventory, a -> "green".equals(a.getColor())); // a has no type. It becomes an Apple automagically
 +</code>
 +
 +==Method reference==
 +Methods can be references, to use them as lambdas:
 +<code>
 +Integer::parseInt // local method on class
 +Apple::getWeight // static method on class
 +new Apple()::getWeight // on instance
 +</code>
 +
 +==Constructor reference==
 +<code>
 +Supplier<Apple> c1 = Apple::new; // supplier takes no pramas, creates Apple. COnstructor is a supplier
 +Apple a1 = c1.get(); // produce an apple by calling a suplier
 +</code>
 +
 +
 +===== Streams =====
 +
 +== Summary ==
 +Streams introduce **internal collection navigation** where you don't need to. \\
 +As a contra to extrnal navigation, where you explicitely iterate a collection.
 +
 +Streams describe **computations of Data sets**, \\
 +whereas collections describe the storage and access.
 +
 +Operations on Streams are **parallelized** automagically, when using parallelStream()
 +<code>
 +inventory.stream().filter...  // not parallelized
 +inventory.parallelStream().filter... // parallelized
 +</code>
 +
 +
 +== Methods ==
 +The stream methods are separated into:
 +|intermediate| <WRAP> 
 +returns a stream. Which allows to execute the next operation, as defined in chain pattern.
 +<code> .stream().filter(...).distinct().limit(3)... </code>
 + </WRAP>|
 +|terminal |<WRAP>
 +operation which returns a non string. FInalizes the chain of stream commands.
 +<code> 
 +.stream()...count();
 +.stream()...collect(toList());
 +.stream()....forEach(System.out::println);
 +</code>
 + </WRAP>|
 +
 +
 +
 +
 +**Intermesiate methods**
 +^ method ^ argument ^ result ^ mapping ^
 +|filter| T-> boolean| Stream<T> |
 +|map| T -> R| Stream<R> |
 +|limit| int  | Stream<T> |
 +|skip| int  | Stream<T> |
 +|sorted| T,T - int| Stream<T> |
 +|distinct| | Stream<T> |
 +|flatMap| | | Stream<T[]> -> Stream<T> |
 +
 +**terminal methods**
 +
 +^ method ^ argument ^ result ^  
 +|forEach| |  |
 +|count| | int |
 +|collect| |  |
 +|allMatch| | boolean | 
 +|anyMatch| | boolean |
 +|noneMatch| | boolean |
 +|findFirst|  | Optional<T>
 +|findAny| | Optional<T>
 +|reduce|T, T -> T | Optional<T> |
 +
 +
 +== single pass ==
 +All the stream-methods chained one after another are executed in a single, internal iteration.
 +
 +When you apply a sequence of operations to a stream, these are merely saved up. 
 +Only when you apply a terminal operation to a stream is anything actually computed. This has the great advantage when you apply several
 +operations (perhaps a filter and a map followed by a terminal operation reduce) to a stream, then the stream has to be traversed only once instead of for each operation.
 +
 +
 +
 +THe following code would produce the floowing output:
 +
 +**code** 
 +<sxh java>
 +        dishes.stream().filter(a -> {
 +            System.out.println(a.name);
 +            return true;
 +        }).distinct().map(a -> {
 +            System.out.println(a.type);
 +            return a.name;
 +        });
 +</sxh>
 +
 +**output** 
 +<sxh java>
 +pork // name
 +flesh  // type
 +pumkin // name
 +vegetables // type
 +</sxh>
 +
 +**Name** and **type** come **one after another** or each element.
 +
 +
 +This means that steps during parallel execution - methods that can block the parallel execution should not be executed inside the Stream-pipeline.
 +
 +
 +Assume you have two versions of getting prices from futures:
 +
 +<sxh java>
 +// directly chaining map methods to create Future, get Result is wrong. Because f.get() will be called after every future creation and block further Future creation (Single Pass)
 +stream.map(Helper::createFuture).map((Future f) -> g.get()).asList()
 +
 +// collecting futures into collection first is the right parallel way. When we do the first "get" all Futures already exist and computing
 +List<Future> futures = stream.map(Helper::toFuture).asList();
 +List<Integer> prices = futures.asStream().map((Future f) -> g.get())
 +
 +On the Image the upper Situation is depicted
 +</sxh>
 +
 +{{http://i520.photobucket.com/albums/w327/schajtan/2016-01-25_14-33-18_zpsgm9w0fjz.png}}
 +
 +
 +== Filling the Stream ==
 +
 +<sxh java>
 + // filling the stream with content using "iterate"
 + Stream.iterate(0l, i -> i + 1)
 + .limit(100);
 +</sxh>
 +
 +== Collect and Partition methods - the better reduce ==
 +
 +There are plently of collectors, which are availalbe via **java.util.stream.Collectors**.
 +Just import all static collector methods and vars to use them by name.
 +<code>
 +import static java.util.stream.Collectors.*;
 +</code>
 +
 +**Glossar**
 +|multilevel reduction| groupingBy collector creates substreams, for different grouping criteria. Substreams may be transfered/grouped by another collector, called a downstream collector |
 +|downstream collector| collector, to transfer substreams (substreams created by groupingBy collector)|
 +| reduce-accumulator | method B, A -> B , which converts an STREAM-ENTRY of type A to B. It is applied on EVERY Stream Element. It is passed the accumulated reduce value B so far and the next stream value A. It returns the value, resulting from accumulation of the next stream-element A |
 +| reduce-combiner | when stream is reduced in a parallel way - combiner will combine every result, accumulated on different Streams. |
 +
 +^ Method ^ Returns ^ Describtion ^ Example ^
 +| toList | List<T> | Gather all the stream’s items in a List. | <code> List<Dish> dishes = menuStream.collect(toList()); </code> |
 +| toSet  | Set<T>  | Gather all the stream’s items in a Set, eliminating duplicates. | <code> Set<Dish> dishes = menuStream.collect(toSet()); </code> |
 +| toCollection  | Collection<T>  | Gather all the stream’s items in the collection created by the provided supplier.  | <code> Collection<Dish> dishes = menuStream.collect(toCollection(), ArrayList::new) </code> |
 +| counting  | Long  |   | <code> long howManyDishes = menuStream.collect(counting()); </code>|
 +| summingInt  | Integer  |   | <code> int totalCalories = menuStream.collect(summingInt(Dish::getCalories));  </code> |
 +| averagingInt  | Double  |   | <code> double avgCalories = menuStream.collect(averagingInt(Dish::getCalories)); </code> |
 +| summarizingInt | IntSummary-Statistics  | Collect statistics regarding an Integer property of the items in the stream, such as the maximum, minimum, total, and average.  | <code> IntSummaryStatistics menuStatistics = menuStream.collect(summarizingInt(Dish::getCalories));  </code> |
 +| joining  | String |   | <code> String shortMenu = menuStream.map(Dish::getName).collect(joining(", ")); </code> |
 +| maxBy / minBy |     | <code> Optional<Dish> lightest = menuStream.collect(minBy(comparingInt(Dish::getCalories))); </code> |
 +| reducing | The type produced by the reduction operation  | Reduce the stream to a single value starting from an initial value used as accumulator and iteratively combining it with each item of the stream using a BinaryOperator.  | <code> int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));  </code> |
 +| collectingAndThen  | The type returned by the transforming function  |   | <code> int howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size));   </code> |
 +| groupingBy | Map<K, List<T>> | Maps the stream to groups (as hashmap keys)  | <sxh java> Map<Dish.Type, List<Dish>> dishesByType = menuStream.collect(groupingBy(Dish::getType)); </sxh> |
 +| partitioningBy | Map<Boolean, List<T>> |  | <code> Map<Boolean, List<Dish>> vegetarianDishes =menuStream.collect(partitioningBy(Dish::isVegetarian)); </code> |
 +
 +
 +== Collector Interface - implementing own collectors ==
 +
 +<code>
 +
 + /* COLLECTOR
 +
 + * Collector<T,A,R>
 +
 + *  T - Type of input item in stream
 + *  A - intermediate Type of Objects, during calculation
 + *  R - Result Type
 + *  
 + *  e.g. Collector which collects Stream of Strings to List 
 + *  T - String
 + *  A - List<String>
 + *  R - List<String>
 + *  
 + *  Supplier<A> supplier() - provides initial value of intermediate Type
 + *  BiConsumer<A,T> accumulator() -  input -> the A value calculated so far. T is the next value in stream
 + *  Function<A,R> finisher() - function is executed after iteration over all elements is done
 + *  BinaryOperator<A> combiner() - function which combined two intermediate Objects. This one makes multithreading possible
 + *  Set<Characteristics> characteristics - some optimization hints. UNORDERED, CONCURRENT, IDENTITY_FINISH
 + *  
 + *  
 + *  supplier - ArrayList::new
 + *  accumulator - (List<String> a, String b) -> {a.add(b)}
 + *  finisher - Functions::identity
 + *  combiner - (List<String> a, List<String> b) -> {a.addAll(b)}
 + *  characteristics - return Collections.unmodifyableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT ))
 + */
 +</code>
 +
 +
 +== Parallelism ==
 +
 +Boxed Values are a performace killer.
 +Using a Stream with primitives - improves performance by factor x6
 +<sxh java>
 + long max = 90000000;
 +
 +// LongStream uses primitives (long)
 + start = System.currentTimeMillis();
 + summ = LongStream.iterate(0l, i -> i + 1)
 + .limit(max)
 + .reduce(0l, Long::sum);
 + System.out.println("Sequential LongStream Ready filling after: "+ (System.currentTimeMillis()-start) +"ms");
 + // 220ms
 +
 +// Stream generates Boxed Values (Long)
 + start = System.currentTimeMillis();
 + summ = Stream.iterate(0l, i -> i + 1)
 + .limit(max)
 + .reduce(0l, Long::sum);
 + System.out.println("Sequential Stream Ready filling after: "+ (System.currentTimeMillis()-start) +"ms");
 + // 1228 ms
 +</sxh>
 +
 +
 +Reducing DIshes to Strings in a parallel way:
 +<sxh java>
 + // parallel streams of Dishes, reduced to String, which is a concatenated list of names
 + String res = getExampleStream().parallel().reduce("", 
 + new BiFunction<String, Dish, String>() { 
 + @Override
 + public String apply(String t, Dish u) {
 + return t+u.name;
 + } //accumulator - can convert the Stream content to something else (String)
 +
 + }, 
 + (a,b) -> {
 + return a+b;
 + } // combiner - used in the case of using parallel streams
 + );
 +</sxh>
 +
 +===== Default methods in Interfaces =====
 +It is possible to implement default methods in interfaces. \\
 +So multiple inheritance is some sort of allowed now in java!!!
 +
 +The default interface methods are marked by keyword **default**
 +<code>
 +default void methodName(){...
 +</code>
 +
 +<sxh java>
 + public class Pazak implements HasDefaultMethodKu, HasDefaultMethodKuToo{
 +
 + // have to override method #ku() to explicetly say which interface's method to execute 
 + @Override
 + public void ku() {
 + HasDefaultMethodKu.super.ku();
 + }
 + }
 +
 + public interface HasDefaultMethodKu{
 + default void ku(){
 + System.out.println("Say Ku!");
 + }
 + }
 +
 + public interface HasDefaultMethodKuToo{
 + default void ku(){
 + System.out.println("Say Ku Too!");
 + }
 + }
 +</sxh>
 +
 +
 +===== Optional<T> class =====
 +Return that instead of **null** to avoid NPE
 +
 +  * explicitely define where the var may be null
 +
 +**Methods**
 +|isPresent| |
 +|ifPresent(Consumer<T> block)|  |
 +|get| value or NoSuchMethod-Exception |
 +|T orElse(T other)| |
 +
 +
 +<sxh java>
 +public class Optionals {
 +
 + String name = "Сапожник козоед";
 +
 + public static void main(String[] args) {
 + Optionals optionals = new Optionals();
 + System.out.println(optionals.getName().get());
 +
 + // add defaults
 + System.out.println(optionals.getName().orElse("defaultName"));
 + System.out.println(optionals.getEmptyName().orElse("defaultName"));
 + }
 +
 +
 + Optional<String> getName(){
 + return Optional.of(name);
 + }
 +
 + Optional<String> getEmptyName(){
 + // explicitly say that this var is nullable
 + return Optional.ofNullable(null);
 +// return Optional.of(null); // would produce a NullPointerException
 + }
 +
 +}
 +</sxh>
 +
 +
 +
 +===== CompletableFuture<T> class =====
 +
 +Like a future with more functional-style interface.
 +
 +<sxh java>
 +CompletableFuture<Double> f = CompletableFuture.supplyAsync(() -> calculatePrice());
 +</sxh>
 +
 +
 +== occured exceptions rethrown on get()==
 +The occured Exceptions are rethrown on **get()**
 +
 +<sxh java>
 +
 + CompletableFuture<Double> f = ...
 +
 + try {
 + double calculatedPrice = f.get();
 + System.out.println(String.format("Everything was fine. Price calculated: "+calculatedPrice));
 + return calculatedPrice;
 +
 + } catch (Exception e1) {
 + System.out.println(String.format("I know - an Exception occured earlier on another thread: %s.", e1.getCause()));
 + return (double) 0;
 + }
 +</sxh>
 +
 +
 +== Chainable ==
 +The CompletableFuture can be chained, 
 +to execute some code when the future has completed the computation.
 +
 +<sxh java>
 +CompletableFuture<Integer> c = null;
 +CompletableFuture<String> c2 = null;
 +
 +CompletableFuture cc = c.thenApply((Integer i) -> "Done");
 +/* thenApply((FutureType) -> T) -> CompletableFuture<T>
 + * Executed, when previous Future is done.
 + * Modifies the value "INSIDE" the completableFuture container to T */
 +
 +/* thenRun(() -> Void) -> CompletableFuture<Void>
 + * Executes some code (no params are passed), when previous Future is done */
 +
 +/* thenAccept(FutureType -> Void) -> CompletableFuture<Void>
 + * Executed, when the previous Future is done
 + * VOID will be inside the Future after this call. To preserve some Type T in FUture - use thenApply()
 + */
 +
 +CompletableFuture ccc = c.thenCompose((Integer inte) -> CompletableFuture.runAsync(() -> System.out.println("Done")));
 +/* thenCompose(FutureType) -> CompletableFuture) -> CompletableFuture
 + * Executes a SECOND CompletableFuture, when the first is done    */
 +
 +// thenCombine
 +CompletableFuture<Double> aaa = c.thenCombine(c2, (Integer ii, String ss) -> 2.2);
 +/* thenCombine(CompletableFuture, Function(FutureType1, FutureType2) -> T) -> CompletableFuture<T>
 + * Executes FIRST and SECOND ComputableFutures. Produces the results in a Function which itselfe produces a ComputableFunction 
 + */
 +</sxh>
 +
 +
 +Chaining can be used in streams, to implement real parallel (not only concurrent) evaluation.
 +
 +<sxh java>
 + // List<Picture> -> List<Futures<Picture>> 
 + (List<Picture> l) -> {
 + List<CompletableFuture<Picture>> listFuturesFIlledPrice = l
 + .stream()
 +
 + // Picture -> Futures<Picture>
 + // echo result of future when ready
 + .map((Picture picturePriceless) -> {
 + CompletableFuture<Picture> picFutureWithPrice;
 +
 + // ASYNC DELAYED: get price
 + picFutureWithPrice = CompletableFutures.getFutureFillingPriceInPictureDelayed(picturePriceless);
 +
 + // react immediately after calculation is done
 + picFutureWithPrice = picFutureWithPrice.thenApply(CompletableFutures::echoPictureWhenFutureReady); 
 + return picFutureWithPrice;
 + }
 + )
 + .collect(Collectors.toList());
 + return listFuturesFIlledPrice;
 + }
 +</sxh>
 +
 +
 +
 +
 +===== Date API =====
 +
 +Basic classes
 +|Instant|<WRAP><sxh java>
 + // INSTANT - to be used by machines
 + Instant instant = Instant.ofEpochSecond(1454523011);
 + // nanosecond adjustment - 1sec=1.000.000.000nanosec
 + Instant.ofEpochSecond(0); // 1.January.1970 UTC
 + Instant.ofEpochSecond(2, 1000_000_000); // 2sec + 1sec
 + Instant.ofEpochSecond(3, -1000_000_000); // 4sec - 1sec
 +
 +
 + // Instant -> LocalDate, LocalTime
 + LocalDate dateOfInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalDate();
 + LocalTime timeOfInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalTime();
 +
 +</sxh></WRAP> |
 +|LocalDate| <WRAP><sxh java>
 + LocalDate localDateNow = LocalDate.now();
 + LocalDate localDateNowLondon = LocalDate.now(ZoneId.of("UTC+0"));
 + LocalDate localDate = LocalDate.of(2016, 2, 16);
 +
 + int fieldYear = localDate.get(ChronoField.YEAR);
 +</sxh></WRAP> |
 +|LocalTime| <WRAP><sxh java>
 + LocalTime time = LocalTime.of(14, 55, 54, 11 ); // hour, minute, second, milli
 + LocalTime time2 = LocalTime.of(14, 55, 54 ); // hour, minute, second
 + LocalTime time3 = LocalTime.of(14, 55 ); // hour, minute
 + int hourTime = time.getHour();
 + int minuteTime = time.getMinute();
 +</sxh></WRAP> |
 +|LocalDateTime| <WRAP><sxh java>
 + // 1415-07-6T6:55:20
 + LocalDate dateOne = LocalDate.of(1415, Month.JULY, 6);
 + LocalTime timeOne = LocalTime.of(6, 55, 20);
 + LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20);
 + LocalDateTime dt2 = LocalDateTime.of(dateOne, timeOne);
 + LocalDateTime dt3 = dateOne.atTime(13, 45, 20);
 + LocalDateTime dt4 = dateOne.atTime(timeOne);
 + LocalDateTime dt5 = timeOne.atDate(dateOne);
 +</sxh></WRAP> |
 +|ZoneId| <WRAP><sxh java>
 + ZoneId romeZone = ZoneId.of("Europe/Rome");
 + ZoneId berlinZone = ZoneId.of("Europe/Berlin");
 + ZoneId myZone = TimeZone.getDefault().toZoneId();
 +</sxh></WRAP> |
 +|ZonedDateTime| <WRAP><sxh java>
 + ZoneId berlinZone = ZoneId.of("Europe/Berlin");
 +
 + ZonedDateTime zonedDateTimeBerlin1 = dateOne.atStartOfDay(berlinZone);
 + ZonedDateTime zonedDateTimeBerlin2 = localDateTimeOfGuss.atZone(berlinZone);
 +</sxh></WRAP> |
 +|DateTimeFormatter| <WRAP><sxh java>
 + LocalDate parsedDate;
 + parsedDate = LocalDate.parse("2014-03-18");
 + parsedDate = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_DATE);
 + parsedDate = LocalDate.parse("18/03/2014", DateTimeFormatter.ofPattern("dd/MM/yyyy"));
 + parsedDate = LocalDate.parse("18.03.2014", DateTimeFormatter.ofPattern("dd.MM.yyyy"));
 +
 + parsedDate = LocalDate.parse("18 März 2014", DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.GERMAN));
 +
 + DateTimeFormatter germanFormatter = new DateTimeFormatterBuilder()
 + .appendText(ChronoField.DAY_OF_MONTH)   // 6
 + .appendLiteral(".")
 + .appendValue(ChronoField.MONTH_OF_YEAR) // 7
 + .appendLiteral("( alias ")
 + .appendText(ChronoField.MONTH_OF_YEAR) // July
 + .appendLiteral(")")
 + .appendLiteral(".")
 + .appendValue(ChronoField.YEAR) // 1941
 + .parseCaseInsensitive()
 + .toFormatter(Locale.GERMAN);
 + System.out.println(germanFormatter.format(dateOne));
 +</sxh></WRAP> ||
 +|Duration| <WRAP><sxh java>
 + /*
 + * Duration is CRAP, because based on Seconds / Nanos.
 + * - you only can compute a duration on "time based units" - something what can handle seconds like LocalTime. 
 + *   The compiler still allows computing Duration between LocalDate, or getting YEARS from Duration,
 + *   which results in an Exception.
 + *   WHY OR WHY CAN'T I JUST CONVERT SECONDS IN ANY UNIT WITHOUT EXCEPTIONS, AS EXPECTED?!
 + */
 + // Duration only works with Seconds-supporting types. Using LocaDate - throws an exception
 + // Duration durationSinceGuss = Duration.between(dateOne, LocalDate.now());
 + Duration durationSinceGuss1 = Duration.between(LocalDateTime.of(dateOne, LocalTime.MIDNIGHT),LocalDateTime.now());
 + Duration durationSinceGuss2 = Duration.between(timeOne,LocalTime.now());
 +// Duration durationSinceGuss3 = Duration.between(dateOne,LocalDate.now());    // exception. It trys to convert LocalDate to Seconds, which is not allowed
 +</sxh></WRAP> |
 +|Period| <WRAP><sxh java>
 + Period periodBetweenGuss = Period.between(dateOne, LocalDate.now());
 + long yearsSinceGuss7 = periodBetweenGuss.getYears();
 +</sxh></WRAP> |
 +|TemporalAdjuster| <WRAP><sxh java>LocalDate dateNextSunay = dateOne.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));</sxh></WRAP> |
 +
 +
 +The Time Units are contained by **ChronoUnit.class** and separated in timeBased and dateBased:
 +
 +|
 +It is FUCKING UNCLEAR, why DAYS ARE NOT TIMEBASED?!
 +Still it is important, 
 +some operations are only legal for time- or dateBased units:
 +like getting the amount of years from a Duration.
 +|
 +
 +^TimeBased ^DateBased^
 +|Nanos | Days|
 +|Micros | Weeks |
 +|Millis | Months |
 +|Seconds | Years |
 +|Minutes | Decades |
 +|Hours | Centuries |
 +|HalfDays | Millennia |
 +| | Eras |
 +
 +
 +The same separation exists with Classes:
 +^TimeBased ^DateBased^
 +|LocalDateTime| LocalDateTime|
 +|LocalDate| LocalTime|
 +|Period| Duration|
 +
 +mixing them up produces an **UnsupportedTemporalTypeException**.
 +<sxh java>
 +localDate.plus(1, CHronoUnit.SECOND) // UnsupportedTemporalTypeException 
 +localTime.plus(1, CHronoUnit.DAY)   // UnsupportedTemporalTypeException 
 +
 +// LocalDateTime supports both
 +localDateTime.plus(1, ChronoUnit.SECONDS);
 +localDateTime.plus(1, ChronoUnit.DAYS);
 +</sxh> 
 +
 +
 +CHronofield - contains diffrent kinds of data info names, which may be requested from diffrent TemporalFields.
 +
 +<code>
 + int fieldYear = localDate.get(ChronoField.YEAR);
 + /*
 +                   ChronoField.
 +         NanoOfSecond
 + NanoOfDay
 + MicroOfSecond
 + MicroOfDay
 + MilliOfSecond
 + MilliOfDay
 + SecondOfMinute
 + SecondOfDay
 + MinuteOfHour
 + MinuteOfDay
 + HourOfAmPm
 + ClockHourOfAmPm
 + HourOfDay
 + ClockHourOfDay
 + AmPmOfDay
 + DayOfWeek
 + AlignedDayOfWeekInMonth
 + AlignedDayOfWeekInYear
 + DayOfMonth
 + DayOfYear
 + EpochDay
 + AlignedWeekOfMonth
 + AlignedWeekOfYear
 + MonthOfYear
 + ProlepticMonth
 + YearOfEra
 + Year
 + Era
 + InstantSeconds
 + OffsetSeconds
 + */
 +</code>
 +===== Code - Java8 Style =====
 +How to write code in Java8?
 +
 +== Lambdas instead of anonymous Classes==
 +
 +You can replace many anonymous classes with method calls.
 +Important:
 +
 +^ theme ^ anonymous class ^ lambdas ^
 +| this | means the anonymous class | means the wrapping class |
 +| overriding  vars| is allowed | is forbidden |
 +| typing | is unambigous | may become ambigous - needs explicit typing |
 +
 +<sxh java>
 +
 +
 +Runnable runnable = new Runnable(){
 + void execute(){
 +  System.out.println("Go!")
 + }
 +}
 +
 +Runnable runnable = () -> System.out.println("Go!"); // ok
 +
 +int mVar = 20;
 +Runnable runnable = () -> {
 +  int mVar = 30; // not ok - overriding vars not allowed
 +  System.out.println("Go!");
 +}
 +
 +
 +public static void doSomething(Runnable r){ r.run(); }
 +public static void doSomething(Task a){ r.execute(); }
 +doSomething(() -> System.out.println("Go!")); // not ok -  call doSOmething for Task or Runnable?
 +doSomething((Task)() -> System.out.println("Go!")); // ok
 +
 +</sxh>
 +
 +
 +== Method Reference with helper static methods ==
 +
 +<sxh java>
 +Stream<String> stream = ...
 +stream.map(String::length);
 +stream.map(Helpers::quote);
 +
 +String quote(String str){
 + return String.format("'%s'",str);
 +}
 +</sxh>
 +
 +== Use native collectors ==
 +Native collectors are known by others. Are better readable.
 +<sxh java>
 +int totalCalories = menu.stream().collect(summingInt(Dish::getCalories));
 +</sxh>
 +
 +== Replace loops by streams API ==
 +Better readability, optimization behind the scenes.
 +<sxh java>
 +// collecting names of dishes, which have > 300 calories
 + List<String> dishNames = new ArrayList<>();
 + for (Dish dish : menu) {
 + if (dish.getCalories() > 300) {
 + dishNames.add(dish.getName());
 + }
 + }
 +// intent is better readable.
 +menu.parallelStream()
 +.filter(d -> d.getCalories() > 300)
 +.map(Dish::getName)
 +.collect(toList());
 +</sxh>
 +
 +== Deferred conditional execution ==
 +<sxh java>
 +// message is evaluated EVERY TIME, even if the level does not fit
 +logger.log(Level.FINER, "Problem: " + generateDiagnostic());
 +
 +// to avoid - pass a lambda, which will be called ONLY IF LEVEL FITS
 +logger.log(Level.FINER, () -> "Problem: " + generateDiagnostic());
 +</sxh>
 +
 +
 +== Execute around ==
 +<sxh java>
 +// same code, which is executed around some variable logic 
 +void method1(){
 + doPreparation();
 + //variable method here
 + varMethod2();
 + cleanUp();
 +}
 +void method2(){
 + doPreparation();
 + //variable method here
 + varMethod2();
 + cleanUp();
 +}
 +
 +
 +// better
 +void method(Runnable r){
 + doPreparation();
 + r.execute();
 + cleanUp();
 +}
 +method(()->varMethod1());
 +method(()->varMethod2());
 +
 +</sxh>
 +
 +
 +
 +
 +===== Functional programming style =====
 +
 +With Java8 the programming style is pushing towards the functional edge. \\
 +Some rules for writing functional code:
 +
 +=== Functions must have ===
 +Requirenments to functions
 +
 +== have no side Effects ==
 +Functions may only change private variables.
 +
 +== have referential transparency ==
 +Calling same function always returns the same result. \\
 +E.g. readNextLine() is NOT referential transparent. It alwas returns another line.
 +
 +
 +=== Do ===
 +What to do, when programming:
 +
 +== get Function, return Function ==
 +pass functions to methods. Return new functions with functionality around it.
 +<sxh java> 
 +Function<String, String> transformationPipeline
 += addHeader.andThen(Letter::checkSpelling)
 +.andThen(Letter::addFooter);
 +</sxh>
 +
 +
 +== use Carriying ==
 +create FUnctions producing FUnctions, \\
 +which will prefill some constants.
 +
 +<sxh java> 
 +// carrying
 +Function createConvertingFunction(double course){
 + return (double x) -> course * x;
 +}
 +
 +Function eurToChf = createConvertingFunction(0.9);
 +Function bintcoinToEur = createConvertingFunction(421);
 +</sxh>
 +
 +When function reuses another function and \\
 +when preselecting some arguments (but not all) have been passed - \\
 +then **the function is partially applied**
 +
 +<sxh java>
 +Function echoColoredObject(Object object, String color){
 + (object, color) -> System.out.println("The "+object+" has the color "+color);
 +}
 +
 +// partially apply function echoColoredObject
 +Function echoColoredBall(String color){
 + (color) -> echoColoredObject("Ball", color)
 +}
 +
 +</sxh>
 +
 +
 +===== Interfaces relevant for Lambdas =====
 +
 +If you would like to create a method accepting a lamda use the Argument, typed with one of those methods:
 +**java.util.function.IntBinaryOperator.**
 +
 +
 +Examples:
 +
 +<sxh java>
 +
 +Consumer<Double> c = aDouble -> System.out.println(aDouble);  // no output
 +
 +Function<Double, String> f = aDouble -> String.valueOf(f);  // function returns what you define
 +DoubleFunction<String> d = doubleValue -> String.valueOf(doubleValue); // same as previous
 +
 +IntBinaryOperator plusOperation = (a, b) -> a + b; // operator on two int numbers a and b
 +
 +LongPredicate l = longValue -> longValue < 0l; // boolean function
 +
 +</sxh>
 +
 +
 +===== Terminal Methods =====
 +
 +== findAny / findFirst ==
 +
 +<sxh java>
 +
 +            List<Integer> list = List.of(1, 2, 3, 4, 9, 8, 7, 6, 1, 2, 3);
 +
 +            // gives maybe 7, 8 or 9, cause findAny doesnt respect order
 +            int res = list
 +                    .stream()
 +                    .parallel()
 +                    .filter(integer -> integer > 6)
 +                    .findAny()
 +                    .orElseThrow();
 +                    
 +            assertThat(res, anyOf(is(7), is(8), is(9)));
 +
 +
 +
 +            // gives 9, cause its the first in the row match to filter
 +            int res2 = list
 +                    .stream()
 +                    .parallel()
 +                    .filter(integer -> integer > 6)
 +                    .findFirst()
 +                    .orElseThrow();
 +
 +            assertThat(res, is(9));
 +
 +</sxh>
 +
 +
 +== reduce ==
 +
 +<sxh java>
 +        // cruel method to concat numbers, just to demonstrate reduce
 +        List<Integer> list = List.of(1, 2, 3, 4, 9, 8, 7, 6, 1, 2);
 +
 +        Integer res = list
 +                .stream()
 +                .mapToInt(value -> value)
 +                .reduce(0,
 +                        (integer, integer2) -> {
 +                            return Integer.parseInt(String.format("%s%s", integer, integer2));
 +                        }
 +                );
 +        System.out.println(res); // 1234987612
 +
 +        // better way would be with java8
 +        String res2 = list
 +                .stream()
 +                .map(String::valueOf)
 +                .collect(Collectors.joining());
 +        System.out.println(res2); // 1234987612
 +</sxh>