programming:java:java8
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| programming:java:java8 [2023/11/01 07:31] – removed - external edit (Unknown date) 127.0.0.1 | programming: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' | ||
| + | |||
| + | ===== New Concepts ===== | ||
| + | |||
| + | |Behaviour parametrization | | ||
| + | | | ||
| + | ===== Typing ===== | ||
| + | Which type do new Java8 expressions have? | ||
| + | |||
| + | <sxh java> | ||
| + | |||
| + | // Function. Gets Ranking. Returns Integer. | ||
| + | Function< | ||
| + | |||
| + | // Consumer - accepts sinle parameter. Returns nothing | ||
| + | Consumer< | ||
| + | |||
| + | // Predicate - boolean returning function | ||
| + | Predicate< | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | // MODELS | ||
| + | |||
| + | static class Ranking{ | ||
| + | int value; | ||
| + | |||
| + | public static void echo(Object value){ | ||
| + | System.out.println(String.format(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | ===== 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< | ||
| + | * Biconsumer< | ||
| + | |||
| + | |||
| + | |Functional Interface|< | ||
| + | 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:// | ||
| + | |||
| + | </ | ||
| + | |||
| + | |< | ||
| + | **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. | ||
| + | </ | ||
| + | |||
| + | |< | ||
| + | **Object is NOT a functional interface**\\ | ||
| + | It does not have a single abstract method. \\ | ||
| + | Lambdas can't be assigned to Object variables | ||
| + | |||
| + | < | ||
| + | Object o = () -> {return 2;} // invalid Object in not a functional interface | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | == @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:: | ||
| + | |||
| + | } | ||
| + | |||
| + | |||
| + | // 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{ | ||
| + | | ||
| + | } | ||
| + | |||
| + | static class MyClass{ | ||
| + | | ||
| + | return true; | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | ===== Lambdas ===== | ||
| + | |||
| + | ==Glossar== | ||
| + | |||
| + | | Identifier | < | ||
| + | Identifiers are used as names variables, functions. Identifiert | ||
| + | * starts with a **letter** or **_** or **$** | ||
| + | * is not a java-keyword (keywords are lister here: https:// | ||
| + | < | ||
| + | </ | ||
| + | | Literals | < | ||
| + | Notations for **constant values**, **build in types** | ||
| + | < | ||
| + | </ | ||
| + | | Operators | < | ||
| + | * Mathematical operators, | ||
| + | * call operators () | ||
| + | * array operator [] | ||
| + | * increment operator ++ | ||
| + | The full operator list is here: https:// | ||
| + | |||
| + | **Not** operators: | ||
| + | < | ||
| + | |||
| + | return | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | | Expression | < | ||
| + | It contains: | ||
| + | * identifiers, | ||
| + | * literals, | ||
| + | * operators | ||
| + | |||
| + | Expressions: | ||
| + | < | ||
| + | " | ||
| + | " | ||
| + | System.out.print(" | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | | Statement | < | ||
| + | * Statements are made up of expressions. | ||
| + | * Form a complete unit of execution | ||
| + | * End with **;** | ||
| + | More here: https:// | ||
| + | |||
| + | Statements: | ||
| + | < | ||
| + | System.out.print(" | ||
| + | return " | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | ==Lamda Syntax== | ||
| + | |||
| + | 1. < | ||
| + | 2. < | ||
| + | |||
| + | Lamda Examples: | ||
| + | < | ||
| + | () -> {} // valid 1 | ||
| + | () -> " | ||
| + | () -> {return " | ||
| + | (Integer i) -> return " | ||
| + | (String s) -> {"Iron Man";} // invalid. Valid version: | ||
| + | </ | ||
| + | |||
| + | |||
| + | More valid examples: | ||
| + | <sxh java> | ||
| + | (TYPE name) -> FUNCTION(name) | ||
| + | (String s) -> s.toUpperCase() + " !!!" | ||
| + | (Apple a) -> a.getWeigth() > 150 | ||
| + | </ | ||
| + | |||
| + | |||
| + | == Type inference == | ||
| + | Compiler can deduce the input type from the functional interface. \\ | ||
| + | So you can omit the type in lambdas. | ||
| + | |||
| + | legal usages of lamdas: \\ | ||
| + | < | ||
| + | List< | ||
| + | </ | ||
| + | |||
| + | ==Method reference== | ||
| + | Methods can be references, to use them as lambdas: | ||
| + | < | ||
| + | Integer:: | ||
| + | Apple:: | ||
| + | new Apple():: | ||
| + | </ | ||
| + | |||
| + | ==Constructor reference== | ||
| + | < | ||
| + | Supplier< | ||
| + | Apple a1 = c1.get(); // produce an apple by calling a suplier | ||
| + | </ | ||
| + | |||
| + | |||
| + | ===== 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, | ||
| + | < | ||
| + | inventory.stream().filter... | ||
| + | inventory.parallelStream().filter... // parallelized | ||
| + | </ | ||
| + | |||
| + | |||
| + | == Methods == | ||
| + | The stream methods are separated into: | ||
| + | |intermediate| < | ||
| + | returns a stream. Which allows to execute the next operation, as defined in chain pattern. | ||
| + | < | ||
| + | </ | ||
| + | |terminal |< | ||
| + | operation which returns a non string. FInalizes the chain of stream commands. | ||
| + | < | ||
| + | .stream()...count(); | ||
| + | .stream()...collect(toList()); | ||
| + | .stream()....forEach(System.out:: | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | **Intermesiate methods** | ||
| + | ^ method ^ argument ^ result ^ mapping ^ | ||
| + | |filter| T-> boolean| Stream< | ||
| + | |map| T -> R| Stream< | ||
| + | |limit| int | Stream< | ||
| + | |skip| int | Stream< | ||
| + | |sorted| T,T - int| Stream< | ||
| + | |distinct| | Stream< | ||
| + | |flatMap| | | Stream< | ||
| + | |||
| + | **terminal methods** | ||
| + | |||
| + | ^ method ^ argument ^ result ^ | ||
| + | |forEach| | | | ||
| + | |count| | int | | ||
| + | |collect| | | | ||
| + | |allMatch| | boolean | | ||
| + | |anyMatch| | boolean | | ||
| + | |noneMatch| | boolean | | ||
| + | |findFirst| | ||
| + | |findAny| | Optional< | ||
| + | |reduce|T, T -> T | Optional< | ||
| + | |||
| + | |||
| + | == 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; | ||
| + | }); | ||
| + | </ | ||
| + | |||
| + | **output** | ||
| + | <sxh java> | ||
| + | pork // name | ||
| + | flesh // type | ||
| + | pumkin // name | ||
| + | vegetables // type | ||
| + | </ | ||
| + | |||
| + | **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:: | ||
| + | |||
| + | // collecting futures into collection first is the right parallel way. When we do the first " | ||
| + | List< | ||
| + | List< | ||
| + | |||
| + | On the Image the upper Situation is depicted | ||
| + | </ | ||
| + | |||
| + | {{http:// | ||
| + | |||
| + | |||
| + | == Filling the Stream == | ||
| + | |||
| + | <sxh java> | ||
| + | // filling the stream with content using " | ||
| + | Stream.iterate(0l, | ||
| + | .limit(100); | ||
| + | </ | ||
| + | |||
| + | == 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. | ||
| + | < | ||
| + | import static java.util.stream.Collectors.*; | ||
| + | </ | ||
| + | |||
| + | **Glossar** | ||
| + | |multilevel reduction| groupingBy collector creates substreams, for different grouping criteria. Substreams may be transfered/ | ||
| + | |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< | ||
| + | | toSet | Set< | ||
| + | | toCollection | ||
| + | | counting | ||
| + | | summingInt | ||
| + | | averagingInt | ||
| + | | summarizingInt | IntSummary-Statistics | ||
| + | | joining | ||
| + | | maxBy / minBy | | ||
| + | | reducing | The type produced by the reduction operation | ||
| + | | collectingAndThen | ||
| + | | groupingBy | Map<K, List< | ||
| + | | partitioningBy | Map< | ||
| + | |||
| + | |||
| + | == Collector Interface - implementing own collectors == | ||
| + | |||
| + | < | ||
| + | |||
| + | /* COLLECTOR | ||
| + | * | ||
| + | * Collector< | ||
| + | * | ||
| + | * 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< | ||
| + | * R - List< | ||
| + | * | ||
| + | * Supplier< | ||
| + | * BiConsumer< | ||
| + | * Function< | ||
| + | * BinaryOperator< | ||
| + | * Set< | ||
| + | * | ||
| + | * | ||
| + | * supplier - ArrayList:: | ||
| + | * accumulator - (List< | ||
| + | * finisher - Functions:: | ||
| + | * combiner - (List< | ||
| + | * characteristics - return Collections.unmodifyableSet(EnumSet.of(IDENTITY_FINISH, | ||
| + | */ | ||
| + | </ | ||
| + | |||
| + | |||
| + | == 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, | ||
| + | .limit(max) | ||
| + | .reduce(0l, | ||
| + | System.out.println(" | ||
| + | // 220ms | ||
| + | |||
| + | // Stream generates Boxed Values (Long) | ||
| + | start = System.currentTimeMillis(); | ||
| + | summ = Stream.iterate(0l, | ||
| + | .limit(max) | ||
| + | .reduce(0l, | ||
| + | System.out.println(" | ||
| + | // 1228 ms | ||
| + | </ | ||
| + | |||
| + | |||
| + | 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< | ||
| + | @Override | ||
| + | public String apply(String t, Dish u) { | ||
| + | return t+u.name; | ||
| + | } // | ||
| + | |||
| + | }, | ||
| + | (a,b) -> { | ||
| + | return a+b; | ||
| + | } // combiner - used in the case of using parallel streams | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | ===== 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** | ||
| + | < | ||
| + | default void methodName(){... | ||
| + | </ | ||
| + | |||
| + | <sxh java> | ||
| + | public class Pazak implements HasDefaultMethodKu, | ||
| + | |||
| + | // have to override method #ku() to explicetly say which interface' | ||
| + | @Override | ||
| + | public void ku() { | ||
| + | HasDefaultMethodKu.super.ku(); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | public interface HasDefaultMethodKu{ | ||
| + | default void ku(){ | ||
| + | System.out.println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | public interface HasDefaultMethodKuToo{ | ||
| + | default void ku(){ | ||
| + | System.out.println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | ===== Optional< | ||
| + | Return that instead of **null** to avoid NPE | ||
| + | |||
| + | * explicitely define where the var may be null | ||
| + | |||
| + | **Methods** | ||
| + | |isPresent| | | ||
| + | |ifPresent(Consumer< | ||
| + | |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(" | ||
| + | System.out.println(optionals.getEmptyName().orElse(" | ||
| + | } | ||
| + | |||
| + | |||
| + | Optional< | ||
| + | return Optional.of(name); | ||
| + | } | ||
| + | |||
| + | Optional< | ||
| + | // explicitly say that this var is nullable | ||
| + | return Optional.ofNullable(null); | ||
| + | // return Optional.of(null); | ||
| + | } | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | ===== CompletableFuture< | ||
| + | |||
| + | Like a future with more functional-style interface. | ||
| + | |||
| + | <sxh java> | ||
| + | CompletableFuture< | ||
| + | </ | ||
| + | |||
| + | |||
| + | == occured exceptions rethrown on get()== | ||
| + | The occured Exceptions are rethrown on **get()** | ||
| + | |||
| + | <sxh java> | ||
| + | |||
| + | CompletableFuture< | ||
| + | |||
| + | try { | ||
| + | double calculatedPrice = f.get(); | ||
| + | System.out.println(String.format(" | ||
| + | return calculatedPrice; | ||
| + | |||
| + | } catch (Exception e1) { | ||
| + | System.out.println(String.format(" | ||
| + | return (double) 0; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | == Chainable == | ||
| + | The CompletableFuture can be chained, | ||
| + | to execute some code when the future has completed the computation. | ||
| + | |||
| + | <sxh java> | ||
| + | CompletableFuture< | ||
| + | CompletableFuture< | ||
| + | |||
| + | CompletableFuture cc = c.thenApply((Integer i) -> " | ||
| + | /* thenApply((FutureType) -> T) -> CompletableFuture< | ||
| + | * Executed, when previous Future is done. | ||
| + | * Modifies the value " | ||
| + | |||
| + | /* thenRun(() -> Void) -> CompletableFuture< | ||
| + | * Executes some code (no params are passed), when previous Future is done */ | ||
| + | |||
| + | /* thenAccept(FutureType -> Void) -> CompletableFuture< | ||
| + | * 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(" | ||
| + | /* thenCompose(FutureType) -> CompletableFuture) -> CompletableFuture | ||
| + | * Executes a SECOND CompletableFuture, | ||
| + | |||
| + | // thenCombine | ||
| + | CompletableFuture< | ||
| + | /* thenCombine(CompletableFuture, | ||
| + | * Executes FIRST and SECOND ComputableFutures. Produces the results in a Function which itselfe produces a ComputableFunction | ||
| + | */ | ||
| + | </ | ||
| + | |||
| + | |||
| + | Chaining can be used in streams, to implement real parallel (not only concurrent) evaluation. | ||
| + | |||
| + | <sxh java> | ||
| + | // List< | ||
| + | (List< | ||
| + | List< | ||
| + | .stream() | ||
| + | |||
| + | // Picture -> Futures< | ||
| + | // echo result of future when ready | ||
| + | .map((Picture picturePriceless) -> { | ||
| + | CompletableFuture< | ||
| + | |||
| + | // | ||
| + | picFutureWithPrice = CompletableFutures.getFutureFillingPriceInPictureDelayed(picturePriceless); | ||
| + | |||
| + | // | ||
| + | picFutureWithPrice = picFutureWithPrice.thenApply(CompletableFutures:: | ||
| + | return picFutureWithPrice; | ||
| + | } | ||
| + | ) | ||
| + | .collect(Collectors.toList()); | ||
| + | return listFuturesFIlledPrice; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== Date API ===== | ||
| + | |||
| + | Basic classes | ||
| + | |Instant|< | ||
| + | // INSTANT - to be used by machines | ||
| + | Instant instant = Instant.ofEpochSecond(1454523011); | ||
| + | // nanosecond adjustment - 1sec=1.000.000.000nanosec | ||
| + | Instant.ofEpochSecond(0); | ||
| + | Instant.ofEpochSecond(2, | ||
| + | Instant.ofEpochSecond(3, | ||
| + | |||
| + | |||
| + | // Instant -> LocalDate, LocalTime | ||
| + | LocalDate dateOfInstant = LocalDateTime.ofInstant(instant, | ||
| + | LocalTime timeOfInstant = LocalDateTime.ofInstant(instant, | ||
| + | |||
| + | </ | ||
| + | |LocalDate| < | ||
| + | LocalDate localDateNow = LocalDate.now(); | ||
| + | LocalDate localDateNowLondon = LocalDate.now(ZoneId.of(" | ||
| + | LocalDate localDate = LocalDate.of(2016, | ||
| + | |||
| + | int fieldYear = localDate.get(ChronoField.YEAR); | ||
| + | </ | ||
| + | |LocalTime| < | ||
| + | LocalTime time = LocalTime.of(14, | ||
| + | LocalTime time2 = LocalTime.of(14, | ||
| + | LocalTime time3 = LocalTime.of(14, | ||
| + | int hourTime = time.getHour(); | ||
| + | int minuteTime = time.getMinute(); | ||
| + | </ | ||
| + | |LocalDateTime| < | ||
| + | // 1415-07-6T6: | ||
| + | LocalDate dateOne = LocalDate.of(1415, | ||
| + | LocalTime timeOne = LocalTime.of(6, | ||
| + | LocalDateTime dt1 = LocalDateTime.of(2014, | ||
| + | LocalDateTime dt2 = LocalDateTime.of(dateOne, | ||
| + | LocalDateTime dt3 = dateOne.atTime(13, | ||
| + | LocalDateTime dt4 = dateOne.atTime(timeOne); | ||
| + | LocalDateTime dt5 = timeOne.atDate(dateOne); | ||
| + | </ | ||
| + | |ZoneId| < | ||
| + | ZoneId romeZone = ZoneId.of(" | ||
| + | ZoneId berlinZone = ZoneId.of(" | ||
| + | ZoneId myZone = TimeZone.getDefault().toZoneId(); | ||
| + | </ | ||
| + | |ZonedDateTime| < | ||
| + | ZoneId berlinZone = ZoneId.of(" | ||
| + | |||
| + | ZonedDateTime zonedDateTimeBerlin1 = dateOne.atStartOfDay(berlinZone); | ||
| + | ZonedDateTime zonedDateTimeBerlin2 = localDateTimeOfGuss.atZone(berlinZone); | ||
| + | </ | ||
| + | |DateTimeFormatter| < | ||
| + | LocalDate parsedDate; | ||
| + | parsedDate = LocalDate.parse(" | ||
| + | parsedDate = LocalDate.parse(" | ||
| + | parsedDate = LocalDate.parse(" | ||
| + | parsedDate = LocalDate.parse(" | ||
| + | |||
| + | parsedDate = LocalDate.parse(" | ||
| + | |||
| + | DateTimeFormatter germanFormatter = new DateTimeFormatterBuilder() | ||
| + | .appendText(ChronoField.DAY_OF_MONTH) | ||
| + | .appendLiteral(" | ||
| + | .appendValue(ChronoField.MONTH_OF_YEAR) // 7 | ||
| + | .appendLiteral(" | ||
| + | .appendText(ChronoField.MONTH_OF_YEAR) // July | ||
| + | .appendLiteral(" | ||
| + | .appendLiteral(" | ||
| + | .appendValue(ChronoField.YEAR) // | ||
| + | .parseCaseInsensitive() | ||
| + | .toFormatter(Locale.GERMAN); | ||
| + | System.out.println(germanFormatter.format(dateOne)); | ||
| + | </ | ||
| + | |Duration| < | ||
| + | /* | ||
| + | * 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, | ||
| + | Duration durationSinceGuss1 = Duration.between(LocalDateTime.of(dateOne, | ||
| + | Duration durationSinceGuss2 = Duration.between(timeOne, | ||
| + | // | ||
| + | </ | ||
| + | |Period| < | ||
| + | Period periodBetweenGuss = Period.between(dateOne, | ||
| + | long yearsSinceGuss7 = periodBetweenGuss.getYears(); | ||
| + | </ | ||
| + | |TemporalAdjuster| < | ||
| + | |||
| + | |||
| + | 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, | ||
| + | localTime.plus(1, | ||
| + | |||
| + | // LocalDateTime supports both | ||
| + | localDateTime.plus(1, | ||
| + | localDateTime.plus(1, | ||
| + | </ | ||
| + | |||
| + | |||
| + | CHronofield - contains diffrent kinds of data info names, which may be requested from diffrent TemporalFields. | ||
| + | |||
| + | < | ||
| + | int fieldYear = localDate.get(ChronoField.YEAR); | ||
| + | /* | ||
| + | | ||
| + | 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 - 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 | ||
| + | | typing | is unambigous | may become ambigous - needs explicit typing | | ||
| + | |||
| + | <sxh java> | ||
| + | |||
| + | |||
| + | Runnable runnable = new Runnable(){ | ||
| + | void execute(){ | ||
| + | System.out.println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | Runnable runnable = () -> System.out.println(" | ||
| + | |||
| + | int mVar = 20; | ||
| + | Runnable runnable = () -> { | ||
| + | int mVar = 30; // not ok - overriding vars not allowed | ||
| + | System.out.println(" | ||
| + | } | ||
| + | |||
| + | |||
| + | public static void doSomething(Runnable r){ r.run(); } | ||
| + | public static void doSomething(Task a){ r.execute(); | ||
| + | doSomething(() -> System.out.println(" | ||
| + | doSomething((Task)() -> System.out.println(" | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | == Method Reference with helper static methods == | ||
| + | |||
| + | <sxh java> | ||
| + | Stream< | ||
| + | stream.map(String:: | ||
| + | stream.map(Helpers:: | ||
| + | |||
| + | String quote(String str){ | ||
| + | | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | == Use native collectors == | ||
| + | Native collectors are known by others. Are better readable. | ||
| + | <sxh java> | ||
| + | int totalCalories = menu.stream().collect(summingInt(Dish:: | ||
| + | </ | ||
| + | |||
| + | == Replace loops by streams API == | ||
| + | Better readability, | ||
| + | <sxh java> | ||
| + | // collecting names of dishes, which have > 300 calories | ||
| + | List< | ||
| + | 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:: | ||
| + | .collect(toList()); | ||
| + | </ | ||
| + | |||
| + | == Deferred conditional execution == | ||
| + | <sxh java> | ||
| + | // message is evaluated EVERY TIME, even if the level does not fit | ||
| + | logger.log(Level.FINER, | ||
| + | |||
| + | // to avoid - pass a lambda, which will be called ONLY IF LEVEL FITS | ||
| + | logger.log(Level.FINER, | ||
| + | </ | ||
| + | |||
| + | |||
| + | == Execute around == | ||
| + | <sxh java> | ||
| + | // same code, which is executed around some variable logic | ||
| + | void method1(){ | ||
| + | | ||
| + | // | ||
| + | | ||
| + | | ||
| + | } | ||
| + | void method2(){ | ||
| + | | ||
| + | // | ||
| + | | ||
| + | | ||
| + | } | ||
| + | |||
| + | |||
| + | // better | ||
| + | void method(Runnable r){ | ||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | method(()-> | ||
| + | method(()-> | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== 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< | ||
| + | = addHeader.andThen(Letter:: | ||
| + | .andThen(Letter:: | ||
| + | </ | ||
| + | |||
| + | |||
| + | == use Carriying == | ||
| + | create FUnctions producing FUnctions, \\ | ||
| + | which will prefill some constants. | ||
| + | |||
| + | <sxh java> | ||
| + | // carrying | ||
| + | Function createConvertingFunction(double course){ | ||
| + | | ||
| + | } | ||
| + | |||
| + | Function eurToChf = createConvertingFunction(0.9); | ||
| + | Function bintcoinToEur = createConvertingFunction(421); | ||
| + | </ | ||
| + | |||
| + | 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){ | ||
| + | | ||
| + | } | ||
| + | |||
| + | // partially apply function echoColoredObject | ||
| + | Function echoColoredBall(String color){ | ||
| + | | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | ===== 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< | ||
| + | |||
| + | Function< | ||
| + | DoubleFunction< | ||
| + | |||
| + | IntBinaryOperator plusOperation = (a, b) -> a + b; // operator on two int numbers a and b | ||
| + | |||
| + | LongPredicate l = longValue -> longValue < 0l; // boolean function | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | ===== Terminal Methods ===== | ||
| + | |||
| + | == findAny / findFirst == | ||
| + | |||
| + | <sxh java> | ||
| + | |||
| + | List< | ||
| + | |||
| + | // gives maybe 7, 8 or 9, cause findAny doesnt respect order | ||
| + | int res = list | ||
| + | .stream() | ||
| + | .parallel() | ||
| + | .filter(integer -> integer > 6) | ||
| + | .findAny() | ||
| + | .orElseThrow(); | ||
| + | | ||
| + | assertThat(res, | ||
| + | |||
| + | |||
| + | |||
| + | // 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, | ||
| + | |||
| + | </ | ||
| + | |||
| + | |||
| + | == reduce == | ||
| + | |||
| + | <sxh java> | ||
| + | // cruel method to concat numbers, just to demonstrate reduce | ||
| + | List< | ||
| + | |||
| + | Integer res = list | ||
| + | .stream() | ||
| + | .mapToInt(value -> value) | ||
| + | .reduce(0, | ||
| + | (integer, integer2) -> { | ||
| + | return Integer.parseInt(String.format(" | ||
| + | } | ||
| + | ); | ||
| + | System.out.println(res); | ||
| + | |||
| + | // better way would be with java8 | ||
| + | String res2 = list | ||
| + | .stream() | ||
| + | .map(String:: | ||
| + | .collect(Collectors.joining()); | ||
| + | System.out.println(res2); | ||
| + | </ | ||
