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); | ||
+ | </ | ||