User Tools

Site Tools


programming:java:java

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
programming:java:java [2023/11/01 07:31] – removed - external edit (Unknown date) 127.0.0.1programming:java:java [2023/11/02 14:33] (current) – [Records] skipidar
Line 1: Line 1:
 +===== FallPits =====
 +  * When doing Collection.equals(Collection2) - look out for different implementation. See chapter Collection.Comparisson
 +  * <WRAP><code>
 +// what happens in new B() ?
 +class A{ 
 +  int size =1
 +  public A(){
 +   System.out.println(size);
 +  }
 +}
  
 +class B exends A{ 
 +  {
 +   int size = 2
 +  }
 +  public B(){
 +   System.out.println(size);
 +  }
 +}
 +
 +// new B() prints 1, becuase the block is called AFTER the constructor call
 +</code></WRAP>
 +===== Libs =====
 +
 +^Object^ Comparisson^ Details ^
 +|[[http://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/builder/EqualsBuilder.html|Apache Commons]] |EqualsBuilder.reflectionEquals(Object o1, Object o2)| Helps to implement Object comparison |
 +|[[https://en.wikipedia.org/wiki/Javassist|Javassist]] | | Implements powerfull reflection funcitonality, e.g. proxies |
 +
 +
 +
 +===== Available JDKs =====
 +https://sdkman.io/jdks
 +
 +===== install alternative JDK using SDKman =====
 +
 +install SDK man
 +<code>
 +# sdkman
 +curl -fsSL "https://get.sdkman.io?rcupdate=false" | bash
 +</code>
 +
 +Install sdk man in silent mode
 +<code>
 +# sdkman
 +curl -fsSL "https://get.sdkman.io?rcupdate=false" | bash
 +</code>
 +
 +List and install java
 +<code>
 +sdk list java
 +</code>
 +
 +<sxh shell>
 +================================================================================
 +Available Java Versions for Linux 64bit
 +================================================================================
 + Vendor        | Use | Version      | Dist    | Status     | Identifier
 +--------------------------------------------------------------------------------
 + Corretto      |     | 19.0.2       | amzn    |            | 19.0.2-amzn
 +                   | 19.0.1       | amzn    |            | 19.0.1-amzn
 +                   | 17.0.6       | amzn    |            | 17.0.6-amzn
 +                   | 17.0.5       | amzn    |            | 17.0.5-amzn
 +                   | 11.0.18      | amzn    |            | 11.0.18-amzn
 +                   | 11.0.17      | amzn    |            | 11.0.17-amzn
 +                   | 8.0.362      | amzn    |            | 8.0.362-amzn
 +                   | 8.0.352      | amzn    |            | 8.0.352-amzn
 + Dragonwell    |     | 17.0.6       | albba              | 17.0.6-albba
 +                   | 17.0.5       | albba              | 17.0.5-albba
 +                   | 17.0.4       | albba              | 17.0.4-albba
 +                   | 11.0.18      | albba              | 11.0.18-albba
 +                   | 11.0.17      | albba              | 11.0.17-albba
 +                   | 11.0.16      | albba              | 11.0.16-albba
 +                   | 8.0.362      | albba              | 8.0.362-albba
 +                   | 8.0.352      | albba              | 8.0.352-albba
 +                   | 8.0.345      | albba              | 8.0.345-albba
 + Gluon             | 22.1.0.1.r17 | gln                | 22.1.0.1.r17-gln
 +                   | 22.1.0.1.r11 | gln                | 22.1.0.1.r11-gln
 + GraalVM           | 22.3.r19     | grl                | 22.3.r19-grl
 +                   | 22.3.r17     | grl                | 22.3.r17-grl
 +                   | 22.3.r11     | grl                | 22.3.r11-grl
 +                   | 22.3.1.r19   | grl                | 22.3.1.r19-grl
 +                   | 22.3.1.r17   | grl                | 22.3.1.r17-grl
 +                   | 22.3.1.r11   | grl                | 22.3.1.r11-grl
 +                   | 22.2.r17     | grl                | 22.2.r17-grl
 +                   | 22.2.r11     | grl                | 22.2.r11-grl
 +                   | 22.1.0.r17   | grl                | 22.1.0.r17-grl
 +                   | 22.1.0.r11   | grl                | 22.1.0.r11-grl
 +                   | 22.0.0.2.r17 | grl                | 22.0.0.2.r17-grl
 +                   | 22.0.0.2.r11 | grl                | 22.0.0.2.r11-grl
 +                   | 21.3.3.r17   | grl                | 21.3.3.r17-grl
 +                   | 21.3.3.r11   | grl                | 21.3.3.r11-grl
 +                   | 21.3.3.1.r17 | grl                | 21.3.3.1.r17-grl
 +                   | 21.3.3.1.r11 | grl                | 21.3.3.1.r11-grl
 +                   | 21.3.2.r17   | grl                | 21.3.2.r17-grl
 +                   | 21.3.2.r11   | grl                | 21.3.2.r11-grl
 +                   | 21.3.1.r8    | grl                | 21.3.1.r8-grl
 +                   | 21.2.0.r8    | grl                | 21.2.0.r8-grl
 +                   | 21.1.0.r8    | grl                | 21.1.0.r8-grl
 +                   | 20.3.6.r11   | grl                | 20.3.6.r11-grl
 +                   | 20.3.3.r8    | grl                | 20.3.3.r8-grl
 +                   | 20.3.2.r8    | grl                | 20.3.2.r8-grl
 +                   | 19.3.6.r11   | grl                | 19.3.6.r11-grl
 +                   | 19.3.6.r8    | grl                | 19.3.6.r8-grl
 + Java.net      |     | 21.ea.8      | open    |            | 21.ea.8-open
 +                   | 21.ea.7      | open    |            | 21.ea.7-open
 +                   | 21.ea.6      | open    |            | 21.ea.6-open
 +                   | 21.ea.5      | open    |            | 21.ea.5-open
 +                   | 21.ea.4      | open    |            | 21.ea.4-open
 +                   | 20.ea.34     | open    |            | 20.ea.34-open
 +                   | 20.ea.33     | open    |            | 20.ea.33-open
 +                   | 20.ea.32     | open    |            | 20.ea.32-open
 +                   | 20.ea.31     | open    |            | 20.ea.31-open
 +                   | 20.ea.30     | open    |            | 20.ea.30-open
 +                   | 19.ea.1.pma  | open    |            | 19.ea.1.pma-open
 +                   | 19.0.2       | open    |            | 19.0.2-open
 +                   | 19.0.1       | open    |            | 19.0.1-open
 +                   | 11.0.12      | open    |            | 11.0.12-open
 +                   | 11.0.2       | open    |            | 11.0.2-open
 +                   | 8.0.302      | open    |            | 8.0.302-open
 +                   | 8.0.282      | open    |            | 8.0.282-open
 +                   | 8.0.265      | open    |            | 8.0.265-open
 + Liberica      |     | 19.0.2.fx    | librca  |            | 19.0.2.fx-librca
 +                   | 19.0.2       | librca  |            | 19.0.2-librca
 +                   | 19.0.1.fx    | librca  |            | 19.0.1.fx-librca
 +                   | 19.0.1       | librca  |            | 19.0.1-librca
 +                   | 17.0.6.fx    | librca  |            | 17.0.6.fx-librca
 +                   | 17.0.6       | librca  |            | 17.0.6-librca
 +                   | 17.0.5.fx    | librca  |            | 17.0.5.fx-librca
 +                   | 17.0.5       | librca  |            | 17.0.5-librca
 +                   | 11.0.18.fx   | librca  |            | 11.0.18.fx-librca
 +                   | 11.0.18      | librca  |            | 11.0.18-librca
 +                   | 11.0.17.fx   | librca  |            | 11.0.17.fx-librca
 +                   | 11.0.17      | librca  |            | 11.0.17-librca
 +                   | 8.0.362.fx   | librca  |            | 8.0.362.fx-librca
 +                   | 8.0.362      | librca  |            | 8.0.362-librca
 +                   | 8.0.352.fx   | librca  |            | 8.0.352.fx-librca
 +                   | 8.0.352      | librca  |            | 8.0.352-librca
 +                   | 8.0.332.fx   | librca  |            | 8.0.332.fx-librca
 + Liberica NIK  |     | 22.3.r17     | nik                | 22.3.r17-nik
 +                   | 22.3.r11     | nik                | 22.3.r11-nik
 +                   | 22.3.1.r17   | nik                | 22.3.1.r17-nik
 +                   | 22.3.1.r11   | nik                | 22.3.1.r11-nik
 +                   | 22.2.r17     | nik                | 22.2.r17-nik
 +                   | 22.2.r11     | nik                | 22.2.r11-nik
 +                   | 22.1.r17     | nik                | 22.1.r17-nik
 +                   | 22.1.r11     | nik                | 22.1.r11-nik
 +                   | 22.0.0.2.r17 | nik                | 22.0.0.2.r17-nik
 +                   | 22.0.0.2.r11 | nik                | 22.0.0.2.r11-nik
 +                   | 21.3.3.r17   | nik                | 21.3.3.r17-nik
 +                   | 21.3.3.r11   | nik                | 21.3.3.r11-nik
 +                   | 21.3.3.1.r17 | nik                | 21.3.3.1.r17-nik
 +                   | 21.3.3.1.r11 | nik                | 21.3.3.1.r11-nik
 +                   | 21.3.2.r17   | nik                | 21.3.2.r17-nik
 +                   | 21.3.2.r11   | nik                | 21.3.2.r11-nik
 +                   | 21.2         | nik                | 21.2-nik
 +                   | 21.1         | nik                | 21.1-nik
 +                   | 21.0.0.2.r11 | nik                | 21.0.0.2.r11-nik
 +                   | 21.0.0.2     | nik                | 21.0.0.2-nik
 + Mandrel           | 22.3.1.r17   | mandrel |            | 22.3.1.r17-mandrel
 +                   | 22.3.0.1.r17 | mandrel |            | 22.3.0.1.r17-mandrel
 +                   | 22.2.r17     | mandrel |            | 22.2.r17-mandrel
 +                   | 22.2.r11     | mandrel |            | 22.2.r11-mandrel
 +                   | 22.1.0.0.r17 | mandrel |            | 22.1.0.0.r17-mandrel
 +                   | 22.1.0.0.r11 | mandrel |            | 22.1.0.0.r11-mandrel
 +                   | 22.0.0.2.r17 | mandrel |            | 22.0.0.2.r17-mandrel
 +                   | 22.0.0.2.r11 | mandrel |            | 22.0.0.2.r11-mandrel
 +                   | 21.3.5.1.r17 | mandrel |            | 21.3.5.1.r17-mandrel
 +                   | 21.3.5.1.r11 | mandrel |            | 21.3.5.1.r11-mandrel
 +                   | 21.3.4.r17   | mandrel |            | 21.3.4.r17-mandrel
 +              |     | 21.3.4.r11   | mandrel |            | 21.3.4.r11-mandrel
 +                   | 21.3.3.r17   | mandrel |            | 21.3.3.r17-mandrel
 +                   | 21.3.3.r11   | mandrel |            | 21.3.3.r11-mandrel
 +                   | 21.3.2.0.r17 | mandrel |            | 21.3.2.0.r17-mandrel
 +                   | 21.3.2.0.r11 | mandrel |            | 21.3.2.0.r11-mandrel
 +                   | 21.3.1.1.r17 | mandrel |            | 21.3.1.1.r17-mandrel
 +                   | 21.3.1.1.r11 | mandrel |            | 21.3.1.1.r11-mandrel
 +                   | 21.3.1.0.r17 | mandrel |            | 21.3.1.0.r17-mandrel
 +                   | 21.3.1.0.r11 | mandrel |            | 21.3.1.0.r11-mandrel
 +                   | 21.3.0.0     | mandrel |            | 21.3.0.0-mandrel
 +                   | 21.2.0.2     | mandrel |            | 21.2.0.2-mandrel
 +                   | 20.3.3.0     | mandrel |            | 20.3.3.0-mandrel
 + Microsoft         | 17.0.6       | ms      |            | 17.0.6-ms
 +                   | 17.0.5       | ms      |            | 17.0.5-ms
 +                   | 11.0.18      | ms      |            | 11.0.18-ms
 +                   | 11.0.17      | ms      |            | 11.0.17-ms
 + Oracle        |     | 19.0.2       | oracle  |            | 19.0.2-oracle
 +                   | 19.0.1       | oracle  |            | 19.0.1-oracle
 +                   | 17.0.6       | oracle  |            | 17.0.6-oracle
 +                   | 17.0.5       | oracle  |            | 17.0.5-oracle
 + SapMachine    |     | 19.0.2       | sapmchn |            | 19.0.2-sapmchn
 +                   | 19.0.1       | sapmchn |            | 19.0.1-sapmchn
 +                   | 17.0.6       | sapmchn |            | 17.0.6-sapmchn
 +                   | 17.0.5       | sapmchn |            | 17.0.5-sapmchn
 +                   | 11.0.18      | sapmchn |            | 11.0.18-sapmchn
 +                   | 11.0.17      | sapmchn |            | 11.0.17-sapmchn
 + Semeru        |     | 18.0.2       | sem                | 18.0.2-sem
 +                   | 17.0.5       | sem                | 17.0.5-sem
 +                   | 17.0.4.1     | sem                | 17.0.4.1-sem
 +                   | 11.0.17      | sem                | 11.0.17-sem
 +                   | 11.0.16.1    | sem                | 11.0.16.1-sem
 +                   | 8.0.352      | sem                | 8.0.352-sem
 +                   | 8.0.345      | sem                | 8.0.345-sem
 + Temurin           | 19.0.2       | tem                | 19.0.2-tem
 +                   | 19.0.1       | tem                | 19.0.1-tem
 +                   | 17.0.6       | tem                | 17.0.6-tem
 +                   | 17.0.5       | tem                | 17.0.5-tem
 +                   | 11.0.18      | tem                | 11.0.18-tem
 +                   | 11.0.17      | tem                | 11.0.17-tem
 +                   | 8.0.362      | tem                | 8.0.362-tem
 +                   | 8.0.352      | tem                | 8.0.352-tem
 +                   | 8.0.345      | tem                | 8.0.345-tem
 + Trava             | 11.0.15      | trava              | 11.0.15-trava
 +                   | 11.0.9       | trava              | 11.0.9-trava
 +                   | 8.0.282      | trava              | 8.0.282-trava
 +                   | 8.0.232      | trava              | 8.0.232-trava
 + Zulu          |     | 19.0.2       | zulu    |            | 19.0.2-zulu
 +                   | 19.0.2.fx    | zulu    |            | 19.0.2.fx-zulu
 +                   | 19.0.1       | zulu    |            | 19.0.1-zulu
 +                   | 19.0.1.fx    | zulu    |            | 19.0.1.fx-zulu
 +                   | 17.0.6       | zulu    |            | 17.0.6-zulu
 +                   | 17.0.6.fx    | zulu    |            | 17.0.6.fx-zulu
 +                   | 17.0.5       | zulu    |            | 17.0.5-zulu
 +                   | 17.0.5.fx    | zulu    |            | 17.0.5.fx-zulu
 +                   | 11.0.18      | zulu    |            | 11.0.18-zulu
 +                   | 11.0.18.fx   | zulu    |            | 11.0.18.fx-zulu
 +                   | 11.0.17      | zulu    |            | 11.0.17-zulu
 +                   | 11.0.17.fx   | zulu    |            | 11.0.17.fx-zulu
 +                   | 8.0.362      | zulu    |            | 8.0.362-zulu
 +                   | 8.0.362.fx   | zulu    |            | 8.0.362.fx-zulu
 +                   | 8.0.352      | zulu    |            | 8.0.352-zulu
 +                   | 8.0.352.fx   | zulu    |            | 8.0.352.fx-zulu
 +                   | 7.0.352      | zulu    |            | 7.0.352-zulu
 +                   | 6.0.119      | zulu    |            | 6.0.119-zulu
 +================================================================================
 +Omit Identifier to install default version 17.0.6-tem:
 +    $ sdk install java
 +Use TAB completion to discover available versions
 +    $ sdk install java [TAB]
 +Or install a specific version by Identifier:
 +    $ sdk install java 17.0.6-tem
 +Hit Q to exit this list view
 +================================================================================
 +</sxh>
 +
 +
 +silent installing some java
 +
 +<code>
 +# java open GraalVM from liberica "native image kit"
 +sdk install java 22.3.r17-nik < /dev/null
 +
 +# java openjdk
 +sdk install java 19.0.2-open < /dev/null
 +</code>
 +
 +
 +switching version
 +
 +<code>
 +sdk use java 19.0.2-open
 +sdk use java 22.3.r17-nik
 +</code>
 +
 +===== install alternative JDK in parallel and switch =====
 +
 +https://ubunlog.com/en/instala-java-8-9-y-10-en-ubuntu-18-04-y-derivados/
 +
 +<code>
 +sudo apt-get update
 +
 +// check which openjdk versions are available
 +apt-cache search openjdk.*-jdk
 +
 +// install some JDK
 +sudo apt install openjdk-8-jdk
 +sudo apt install openjdk-9-jdk
 +sudo apt install openjdk-11-jdk
 +sudo apt install openjdk-17-jdk
 +
 +// list 
 +update-java-alternatives -l
 +
 +// switch
 +sudo update-alternatives --config java
 +
 +There are 3 choices for the alternative java (providing /usr/bin/java).
 +
 +Selection    Path...
 +------------------------------------------------------------
 +  0            /usr/lib/jvm/java-9-oracle/bin/java...
 +* 1            /usr/lib/jvm/java-7-oracle/jre/bin/java...
 +  2            /usr/lib/jvm/java-8-oracle/jre/bin/java...
 +  3            /usr/lib/jvm/java-9-oracle/bin/java...
 +
 +</code>
 +
 +===== JDK Tools =====
 +Java consists of many tools
 +Here is a full list: http://docs.oracle.com/javase/8/docs/technotes/tools/#basic
 +
 +Here are some tools, which I think are most useful:
 +
 +| java | launcher for java apps |
 +| javac | compiler for the Java programms |
 +| keytools | manages keystores, certificates |
 +| jar | creates jars |
 +| jarsigner | signs the jars using certificates |
 +| jvisualvm | Tool to monitor a Java-Application (JVM) |
 +| jconsole | wie jvisualvm  |
 +| |  |
 +
 +
 +===== Garbage Collector, Java Memory (Heap, Stack) =====
 +
 +== Heap ==
 +  * **Process size** of your java app
 +    * **Native Heap** (C-Heap) - JVM uses this memory for its internal operations (JDBC Drivers allocate memory. IO OPerations may allocate native memory.)
 +    * **Java-Heap** - **Memory area**, from which memory for all **class-instances**, **arrays** is allocated
 +      * **Young Gen** - space for new Objects
 +        * Eden
 +        * Survivor1
 +        * Survivor2
 +      * **Old Gen** - space for Objects, which survived multiple Garbadge Collector runs
 +
 +Java-Heap is reclaimed by garbage collector. \\
 +More about garbage collector is described here: \\
 +http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
 +
 +In Java8 the memory model was redesigned (PermGen was eliminated)
 +
 +{{http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/images/gcslides/Slide5.png?600}}
 +{{http://i520.photobucket.com/albums/w327/schajtan/2015-10-08_20-08-38_zps2kxezs3c.png?600}}
 +
 +
 +
 +
 +===== JavaDoc =====
 +JavaDoc can contain Pictures
 +<sxh java>
 +    /** Sorts labels according to {@link #LABEL_PRIORITY} 
 +     * <img alt="" src=png;base64,iVBORw0KGgoAAAANSUhEUgAAARYAAAiBMy1wVPx/7leh9m/FkN8AAAAASUVORK5CYII=" />
 +     */
 +    public static final method() {   }
 +</sxh>
 +===== Annotations =====
 +
 +  * The annotations in java are like interface. 
 +  * Annotations are applied to classes (methods, parameters) - not to objects!
 +  * Annotations are markers, which are used when evaluating by using **reflections**.
 +  * Via annotation parameters only following Types may be passed: \\ **primitive type, String, Class, annotation, enumeration, or 1-dimensional arrays thereof**
 +
 +Details are here: http://en.wikipedia.org/wiki/Java_annotation
 +
 +<sxh java>
 +package com.annotation;
 + 
 +import java.lang.annotation.Documented;
 +import java.lang.annotation.ElementType;
 +import java.lang.annotation.Inherited;
 +import java.lang.annotation.Retention;
 +import java.lang.annotation.RetentionPolicy;
 +import java.lang.annotation.Target;
 + 
 +@Documented
 +@Retention(RetentionPolicy.RUNTIME)
 +@Target({ElementType.TYPE,ElementType.METHOD,
 + ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,
 + ElementType.PACKAGE,ElementType.FIELD,ElementType.LOCAL_VARIABLE})
 +@Inherited
 + 
 +public @interface Unfinished {
 +        public enum Priority { LOW, MEDIUM, HIGH }
 +        String value();
 +        String[] changedBy() default "";
 +        String[] lastChangedBy() default "";
 +        Priority priority() default Priority.MEDIUM;
 +        String createdBy() default "James Gosling";
 +        String lastChanged() default "08/07/2011";
 +}
 +</sxh>
 +
 +<sxh java>
 +@Unfinished( Proority = HIGH, value=2, createdBy="Mr. Anderson")
 +class MyClass{
 +
 +}
 +</sxh>
 +===== POJO, JavaBean, DTO, ValueObject =====
 +Here are some details about the differences: http://stackoverflow.com/questions/1612334/difference-between-dto-vo-pojo-javabeans
 +
 +Java provides some API to work with JavaBean getter / setter
 +
 +<sxh java>
 +BeanInfo info = Introspector.getBeanInfo(domainObjectType);
 +PropertyDescriptor[] props = info.getPropertyDescriptors();
 +
 +for (PropertyDescriptor pd : props) {
 +   Class<?> propertyType = pd.getPropertyType();
 +   String propertyName = pd.getName();
 +}
 +</sxh>
 +===== Collections =====
 +== LinkedList ==
 +<code>
 +// good to iterate over elements, stop on each element while condition is true
 +LinkedList.getFirst();
 +LinkedList.removeFirst();
 +</code>
 +
 +
 +
 +==== Comparisson ====
 +The Following code does different things.
 +<code>
 +Collection.equals(Collection)
 +</code>
 +
 +In **HashMaps<MyObject>**:
 +
 +it copares the elements in collections, <fc #FF0000>by computing a key for every element, which is a hash</fc> and checking, whether the other collection contains the key.
 +The implementation of MyObject.equals() is never called.
 +
 +In **ArrayList<MyObject>**:
 +it copares the elements in collections, by doing MyObject.equals(MyObject2) for every element.
 +
 +
 +==== Multithreading ====
 +
 +==Threadlocal variables ==
 +It may happen, that every thread should have an own variable.
 +<sxh java>
 +    private static final ThreadLocal<ApplicationContext> current = new ThreadLocal<>();
 +
 +    public static void setCurrent(ApplicationContext context) {
 +        current.set(context);
 +    }
 +
 +    public static ApplicationContext getCurrent() {
 +        return current.get();
 +    }
 +</sxh>
 +
 +
 +===== Enums with Parameters =====
 +The Enum can hava a Constructor and Methods.
 +It can be used to create many constants, dependent on X factors, like price ...
 +
 +Example: http://www.avajava.com/tutorials/lessons/how-do-i-use-the-enum-type-with-a-constructor.html
 +
 +
 +===== Logging =====
 +
 +==== Logging Fascade ====
 +The jar with a logging Fascade contains a bunch of interfaces, without implementation. The implementation of the interfaces are provided in a separate jar, see logging engine.
 +The following logging Fascade are available:
 +
 +|Slf4J| Most popular logging interfaces in the java world.  |
 +|Apache’s commons-logging| Less popular option. |
 +
 +
 +
 +==== Logging Engine ====
 +
 +
 +|Log4j2| Replaces Log4j. Claims to be faster, than the predecessor.|
 +|LogBack|<WRAP>
 +which is an evolved version of Log4j.
 +Logback is the implementation of the SL4J interfaces.
 +The Details are here: http://logback.qos.ch/
 +
 +This implementation is available for all platforms. Once learned it can be reused.
 +
 +The configurations may be done in XML or in code. Sometimes they do not work in XML, here an example of a configuration in code.
 +</WRAP>|
 +
 +==== Details Logback ====
 +
 +
 +^Concept ^ Explanation^
 +|Logger |<WRAP>
 +hiererachy - loggers are hierarchically arranged by name. The names mark the packages/classes which the messages d ooriginate from!
 + "com.test.logger" is parent of 
 + "com.test.logger.core" is parent of 
 + "com.test.logger.core.gui" is parent of ..
 +</WRAP>|
 +|Appender |<WRAP>
 +the Objects which are attached to the Loggers. They are responsible for writing down the output into Files, Consoles etc. Each Logger may have multiple appenders.
 +</WRAP>|
 +|LoggerContext |<WRAP>
 +is reponsible for maufacturing loggers! Every logger is attached to one.
 +</WRAP>|
 +|Layout |<WRAP>
 +configures the Format of the output messages, e.g. : 176  [main] DEBUG manual.architecture.HelloWorld2 - Hello world.
 +</WRAP>|
 +|TurboFilter |<WRAP>
 +is used to deny or accept messages according to some conditions. 
 + LevelFilter can be used to filter messages below of level ERROR for an appender.
 + Then several appenders with different LevelFilters can be applied to the same logging level.
 +</WRAP>|
 +
 +
 +
 +
 +<sxh java>
 +import java.io.File;
 +
 +import org.slf4j.LoggerFactory;
 +
 +import android.os.Environment;
 +import ch.qos.logback.classic.Level;
 +import ch.qos.logback.classic.Logger;
 +import ch.qos.logback.classic.LoggerContext;
 +import ch.qos.logback.classic.android.LogcatAppender;
 +import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
 +import ch.qos.logback.classic.filter.LevelFilter;
 +import ch.qos.logback.classic.spi.ILoggingEvent;
 +import ch.qos.logback.core.rolling.RollingFileAppender;
 +import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
 +import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
 +import ch.qos.logback.core.spi.FilterReply;
 +
 +public class LoggerConfig {
 +
 + //The path is relative to the Android External storage.
 + final static String LOG_DIR_REL_PATH = "/Android/data/de.ivu.eticket.app/logs";
 + final static String MAX_FILE_SIZE = "30MB";
 + final static String LOG_PATTERN = "%-7level %date{dd MMM HH:mm} [%thread]: %message%n";
 + final static String FILENAME_ERRORS = "logErrors";
 + final static String FILENAME_TRACE = "logТrace";
 +
 + public static void configureLogbackDirectly() {
 +
 +     
 + File file = Environment.getExternalStorageDirectory();
 + String pathExternalStorage = file.getPath();
 + String logPathAbsolute = pathExternalStorage + LOG_DIR_REL_PATH;
 +
 + LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
 +     context.reset();
 +     
 +     
 +
 +     
 +     
 +     //FILE ERRORS
 +     RollingFileAppender<ILoggingEvent> rollingFileAppenderErrors = new RollingFileAppender<ILoggingEvent>();
 +     rollingFileAppenderErrors.setAppend(true);
 +     rollingFileAppenderErrors.setContext(context);
 +
 +     // OPTIONAL: Set an active log file (separate from the rollover files).
 +     // If rollingPolicy.fileNamePattern already set, you don't need this.
 +     rollingFileAppenderErrors.setFile(logPathAbsolute + "/"+FILENAME_ERRORS+".txt");
 +
 +     TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy1 = new TimeBasedRollingPolicy<ILoggingEvent>();
 +     rollingPolicy1.setFileNamePattern(logPathAbsolute + "/" +FILENAME_ERRORS+".%d.txt"); //is overridden by setFile() but necessary
 +     rollingPolicy1.setMaxHistory(7);
 +     rollingPolicy1.setParent(rollingFileAppenderErrors);  // parent and context required!
 +     rollingPolicy1.setContext(context);
 +     rollingPolicy1.start();
 +     rollingFileAppenderErrors.setRollingPolicy(rollingPolicy1);
 +     
 +     SizeBasedTriggeringPolicy<ILoggingEvent> sizePolicy1 = new SizeBasedTriggeringPolicy<ILoggingEvent>();
 +     sizePolicy1.setMaxFileSize(MAX_FILE_SIZE);
 +     sizePolicy1.start();
 +     rollingFileAppenderErrors.setTriggeringPolicy(sizePolicy1);
 +     
 +     LevelFilter levelFilter1 = new LevelFilter();
 +     levelFilter1.setLevel(Level.ERROR);
 +     levelFilter1.start();
 +     levelFilter1.setOnMatch(FilterReply.ACCEPT);
 +     levelFilter1.setOnMismatch(FilterReply.DENY);
 +     rollingFileAppenderErrors.addFilter(levelFilter1);
 +     
 +     PatternLayoutEncoder encoder1 = new PatternLayoutEncoder();
 +     encoder1.setPattern(LOG_PATTERN);
 +     encoder1.setContext(context);
 +     encoder1.start();
 +     rollingFileAppenderErrors.setEncoder(encoder1);
 +     
 +     rollingFileAppenderErrors.start();
 +     
 +     
 +     
 +     
 +     
 +     
 +     //FILE DEBUG
 +     RollingFileAppender<ILoggingEvent> rollingFileAppenderDebug = new RollingFileAppender<ILoggingEvent>();
 +     rollingFileAppenderDebug.setAppend(true);
 +     rollingFileAppenderDebug.setContext(context);
 +
 +     // OPTIONAL: Set an active log file (separate from the rollover files).
 +     // If rollingPolicy.fileNamePattern already set, you don't need this.
 +     rollingFileAppenderDebug.setFile(logPathAbsolute + "/"+FILENAME_TRACE+".txt");
 +
 +     TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy2 = new TimeBasedRollingPolicy<ILoggingEvent>();
 +     rollingPolicy2.setFileNamePattern(logPathAbsolute + "/" +FILENAME_TRACE+".%d.txt"); //is overridden by setFile() but necessary
 +     rollingPolicy2.setMaxHistory(7);
 +     rollingPolicy2.setParent(rollingFileAppenderDebug);  // parent and context required!
 +     rollingPolicy2.setContext(context);
 +     rollingPolicy2.start();
 +
 +     
 +     SizeBasedTriggeringPolicy<ILoggingEvent> sizePolicy2 = new SizeBasedTriggeringPolicy<ILoggingEvent>();
 +     sizePolicy2.setMaxFileSize(MAX_FILE_SIZE);
 +     
 +     rollingFileAppenderDebug.setRollingPolicy(rollingPolicy2);
 +     rollingFileAppenderDebug.setTriggeringPolicy(sizePolicy2);
 +     
 +
 +     
 +     PatternLayoutEncoder encoder2 = new PatternLayoutEncoder();
 +     encoder2.setPattern(LOG_PATTERN);
 +     encoder2.setContext(context);
 +     encoder2.start();
 +
 +     rollingFileAppenderDebug.setEncoder(encoder2);
 +     rollingFileAppenderDebug.start();
 +     
 +
 +     
 +     
 +     
 +     
 +     //LOGCAT
 +     PatternLayoutEncoder logCatENcoder = new PatternLayoutEncoder();
 +     logCatENcoder.setContext(context);
 +     logCatENcoder.setPattern(LOG_PATTERN);
 +     logCatENcoder.start();
 +     
 +     LogcatAppender logcatAppender = new LogcatAppender();
 +     logcatAppender.setContext(context);
 +     logcatAppender.setEncoder(logCatENcoder);
 +     logcatAppender.start();
 +     
 +     
 +
 +     
 +//      add the newly created appenders to the root logger;
 +     ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
 +     root.setLevel(Level.TRACE);
 +     root.addAppender(rollingFileAppenderDebug);
 +     root.addAppender(rollingFileAppenderErrors);
 +     root.addAppender(logcatAppender);
 +     
 + }
 +
 +}
 +
 +</sxh>
 +
 +
 +===== Internationalization =====
 +The internationalization is made via *.properties files.
 +The *.properties files may be translated to Excelt files, using an open source tool:
 +https://code.google.com/p/i18n-binder/
 +
 +
 +
 +If you would like to insert some values into the translated strings do that as following:
 +
 +==locale.properties ==
 +Define the places, where the data should be inserted into the strings by inserting **{i}** into the strings. \\
 +**i** is the number of the parameter you will pass beginning with 0.
 +
 +<code>
 +UserNameMessage={0} users with the name {1} have been found
 +</code>
 + 
 +
 +==code ==
 +Insert the data into the String at predefined places:
 +<code>
 +MessageFormat.format(Messages.UserNameMessage, "3", "Steve");
 +</code>
 +
 +
 +This mehtod is better than adding **%s** into the translations and inserting the data by doing the following, because Runtime-Exceptions will be thrown, if the string does not contains enoughh placeholders **%s**
 +<code>
 +UserNameMessage=%s users with the name %s have been found
 +</code>
 +
 +<code>
 +String.format(Messages.UserNameMessage, "3", "Steve");
 +</code>
 +===== Date =====
 +Details: http://tutorials.jenkov.com/java-date-time/java-util-timezone.html
 +
 +**ACHTUNG:** 
 +  * Etc/GMT+1 - counts the timezones backwards. It is equal to UTC-1. It is equal to GMT-1.
 +  * When Java converts a numer to Date - in interprets the number as UTC and add the local offset to create a local time. \\ so new Date(System.currentTimeMillis()) - is in local time, even if System.currentTimeMillis() is in UTC
 +
 +== Timezones ==
 +Java knows TimeZones.
 +
 +<sxh java>
 +   TimeZone utc = TimeZone.getTimeZone("UTC");
 +// TimeZone berlin = TimeZone.getTimeZone("Europe/Berlin");
 +// TimeZone cassablanca = TimeZone.getTimeZone("Africa/Casablanca");
 +   TimeZone local = TimeZone.getDefault();
 +</sxh>
 +
 +
 +== Objects==
 +  * The Object **Date** is silly and does not contain
 +  * The Object **Timezone** contains the operations about Timzeones
 +  * The Object **Calendar** contains the operations on Dates. **GregorianCalendar** is a concreate calendar.
 +
 +<sxh java>
 + TimeZone utc = TimeZone.getTimeZone("UTC");
 + Date barcodeDateInUTC = new Date(2014,22,05);
 +
 + // assume barcodeDate is in UTC
 + GregorianCalendar gregorianCalendar = new GregorianCalendar();
 + gregorianCalendar.setTimeZone(utc);
 + gregorianCalendar.setTime(barcodeDateInUTC); 
 +</sxh>
 +
 +
 +== Conversion between TimeZones ==
 +<sxh java>
 +TimeZone local = TimeZone.getDefault();
 +
 +// assume barcodeDate is in UTC
 +GregorianCalendar gregorianCalendar = new GregorianCalendar();
 +gregorianCalendar.setTimeZone(utc);
 +gregorianCalendar.setTime(barcodeDateInUTC); 
 +
 +// ACHTUNG: 
 +// offset is given relative to the LOCAL ZONE, not to UTC.
 +// GMT-1 gives an offset of -1  Convert from UTC: utc --1 
 +// GMT+1 gives an offset of  1  Convert from UTC: utc - 1
 +// "Europe/Berlin" gives an offset of  1. 
 +int offset = local.getOffset(0); 
 +
 +// calendar is UTC now. Convert to European time.
 +gregorianCalendar.add(Calendar.MILLISECOND, -offset);
 +Date localTime = gregorianCalendar.getTime();
 +</sxh>
 +
 +
 +== Format of Date ==
 +The Date is conveted from String and back by using **DateFormat**.
 +It should by used, considering the Local formats. E.g. in Europe you display date as 24.12.2014. In USA you display date as 12.24.2014.
 +<sxh java>
 +DateFormat dateFormat =  DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault());
 +</sxh>
 +
 +|DateFormat.SHORT | 24.12.06 | 21:54 |
 +|DateFormat.MEDIUM | 24.12.2006 | 21:54:46 |
 +|DateFormat.LONG | 24. Dezember 2006 | 21:54:20 GMT+02:00 |
 +|DateFormat.FULL | Sonntag, 24. Dezember 2006 |21.54 Uhr GMT+02:00|
 +
 +===== Bit arithmetik =====
 +Bit arithmetik in Java. Details: http://openbook.galileocomputing.de/javainsel/javainsel_18_001.html#dodtp63255d32-d0b5-4be8-9423-e891b6949017
 +
 +May be used to pass settings to a method in java, if many settings are allowd in arbitrary combinations, like SWT bits in java
 +
 +<sxh java>
 +/**
 +
 + * 0  in binary format is 0000 0000 0000 0000
 + * 1  in binary format is 0000 0000 0000 0001
 + * -1 in binary format is 1111 1111 1111 1111
 + *  
 + */
 +
 + static final int first = 1 << 0; // binary 0000 0000 0000 0001
 + static final int second = 1 << 1; // binary 0000 0000 0000 0010
 + static final int third = 1 << 2; // binary 0000 0000 0000 0100
 + static final int four = 1 << 3; // binary 0000 0000 0000 1000
 +
 + public static void main(String[] args) {
 +
 + System.out.println(isBitSet(first, first)); // true
 + System.out.println(isBitSet(0, first)); // false
 + System.out.println(isBitSet(second, first)); // false
 + System.out.println(isBitSet(second|first, first)); // true
 +
 + System.out.println("--");
 +
 + int bits = first|second|third;
 + System.out.println(isBitSet(bits, second)); // true
 + bits = unsetBit(bits, second);
 + System.out.println(isBitSet(bits, second)); // false
 +
 +
 + }
 +
 + /**
 + * Checks whether the bits in mask are set inside the bits input
 + * @param bits
 + * @param mask
 + * @return
 + */
 + public static boolean isBitSet(int bits, int mask){
 + return (bits & mask) == mask;
 + }
 +
 + /**
 + * Takes the mask, flips the bits in mask
 + * @param bits - where to flip the bits
 + * @param mask - the mask which contains the bits to flip
 + * @return
 + */
 + public static int unsetBit(int bits, int mask){
 + int negatedMask = ~mask;
 + return (bits & negatedMask);
 + }
 +</sxh>
 +
 +
 +===== Java VM =====
 +
 +Following parameters are possible
 +<code>
 +C:\java -X
 +
 +    -Xmixed           mixed mode execution (default)
 +    -Xint             interpreted mode execution only
 +    -Xbootclasspath:<directories and zip/jar files separated by ;>
 +                      set search path for bootstrap classes and resources
 +    -Xbootclasspath/a:<directories and zip/jar files separated by ;>
 +                      append to end of bootstrap class path
 +    -Xbootclasspath/p:<directories and zip/jar files separated by ;>
 +                      prepend in front of bootstrap class path
 +    -Xnoclassgc       disable class garbage collection
 +    -Xincgc           enable incremental garbage collection
 +    -Xloggc:<file>    log GC status to a file with time stamps
 +    -Xbatch           disable background compilation
 +    -Xms<size>        set initial Java heap size
 +    -Xmx<size>        set maximum Java heap size
 +    -Xss<size>        set java thread stack size
 +    -Xprof            output cpu profiling data
 +    -Xfuture          enable strictest checks, anticipating future default
 +    -Xrs              reduce use of OS signals by Java/VM (see documentation)
 +    -Xcheck:jni       perform additional checks for JNI functions
 +    -Xshare:off       do not attempt to use shared class data
 +    -Xshare:auto      use shared class data if possible (default)
 +    -Xshare:on        require using shared class data, otherwise fail.
 +
 +The -X options are non-standard and subject to change without notice.
 +</code>
 +
 +
 +===== System properties =====
 +There are infos about the PC environment which may be retrieved from java: 
 +
 +<code>
 +System.getProperty("user.dir")
 +
 +Key Description of Associated Value 
 +java.version Java Runtime Environment version 
 +java.vendor Java Runtime Environment vendor 
 +java.vendor.url Java vendor URL 
 +java.home Java installation directory 
 +java.vm.specification.version Java Virtual Machine specification version 
 +java.vm.specification.vendor Java Virtual Machine specification vendor 
 +java.vm.specification.name Java Virtual Machine specification name 
 +java.vm.version Java Virtual Machine implementation version 
 +java.vm.vendor Java Virtual Machine implementation vendor 
 +java.vm.name Java Virtual Machine implementation name 
 +java.specification.version Java Runtime Environment specification version 
 +java.specification.vendor Java Runtime Environment specification vendor 
 +java.specification.name Java Runtime Environment specification name 
 +java.class.version Java class format version number 
 +java.class.path Java class path 
 +java.library.path List of paths to search when loading libraries 
 +java.io.tmpdir Default temp file path 
 +java.compiler Name of JIT compiler to use 
 +java.ext.dirs Path of extension directory or directories 
 +os.name Operating system name 
 +os.arch Operating system architecture 
 +os.version Operating system version 
 +file.separator File separator ("/" on UNIX) 
 +path.separator Path separator (":" on UNIX) 
 +line.separator Line separator ("\n" on UNIX) 
 +user.name User's account name 
 +user.home User's home directory 
 +user.dir User's current working directory 
 +</code>
 +
 +===== Reflection =====
 +  * When setting the fields via Reflection boxing is not done automatically.
 +  * And you have to use the Field.set() methods to set the wraper types (not Field.setShort(), Field.setInteger())
 +
 +<sxh java>
 +     public static void initAllFieldsWithDefaults(Object modelToInit, Map<Class<?>, Object> defaultValues) {
 +
 +        int defaultInt = Integer.valueOf(defaultValues.get(Integer.class).toString());
 +        double defaultDouble = Double.valueOf(defaultValues.get(Double.class).toString());
 +        float defaultFloat = Float.valueOf(defaultValues.get(Float.class).toString());
 +        short defaultShort = Short.valueOf(defaultValues.get(Short.class).toString());
 +        String defaultString = defaultValues.get(String.class).toString();
 +        Date defaultDate = (Date) defaultValues.get(Date.class);
 +
 +        for (Field f : getAllNonStaticFieldsInHierarchy(modelToInit.getClass())) {
 +            Class<?> type = f.getType();
 +            String name = f.getName();
 +            try {
 +                if (type == Integer.class) {
 +                    f.set(modelToInit, new Integer(defaultInt));
 +
 +                } else if (type == int.class) {
 +                    f.setInt(modelToInit, defaultInt);
 +
 +                } else if (type == Double.class) {
 +                    f.set(modelToInit, new Double(defaultDouble));
 +
 +                } else if (type == double.class) {
 +                    f.setDouble(modelToInit, defaultDouble);
 +
 +                } else if (type == Float.class) {
 +                    f.set(modelToInit, new Float(defaultFloat));
 +
 +                } else if (type == float.class) {
 +                    f.setFloat(modelToInit, defaultFloat);
 +
 +                } else if (type == Short.class) {
 +                    f.set(modelToInit, new Short(defaultShort));
 +
 +                } else if (type == short.class) {
 +                    f.setShort(modelToInit, defaultShort);
 +
 +                } else if (type == String.class) {
 +                    f.set(modelToInit, defaultString);
 +
 +                } else if (type.isInstance(Date.class)) {
 +                    f.set(modelToInit, defaultDate);
 +                }
 +            } catch (Exception e) {
 +                LOG.error("Failed to initialize model's ({}) field '{}' with type '{}' ", f.getDeclaringClass()
 +                        .getSimpleName(), name, type);
 +            }
 +        }
 +
 +    }
 +</sxh>
 +
 +
 +
 +===== Generics =====
 +
 +== PeCs - Producer Extends - Consumer super ==
 +
 +<sxh java>
 +
 + // OK - can hold any Function
 + private Collection<? extends Function> producerExtends1(){
 + return new ArrayList<UnaryOperator>();
 + }
 +
 + /* WRONG! - ArrayList<UnaryOperator> is not a legal replacement for Collection<Function>.
 + * It is legal to try putting NonUnaryOperator into Collection<Function>.
 + * It is NOT legal to put NonUnaryOperator  into Collection<UnaryOperator>.
 + * So you can not return Collection<UnaryOperator> here.
 + */
 +// private Collection<Function> producerExtends2(){
 +// return new ArrayList<UnaryOperator>();
 +// }
 +
 +
 + private void producerExtends3(Collection<? extends Function> collection){
 + /* Indeed it is not possible to put something into the collection, 
 + * since you do not know what is ?,
 + * in the instance of Collection.
 + * May have been anything. UnaryOperator, NonUnaryOperator.
 +
 + * WRONG!
 + */
 +// collection.add(new ArrayList<UnaryOperator>())
 + }
 +
 + /* OK - can put any Function in here, 
 + * because you know - collection contains ONLY some superclasses of Function.
 + * So you can put any Function in here. 
 + */
 + private void consumerSuper1(Collection<? super Function> collection){
 + UnaryOperator u = null;
 + collection.add(u);
 + }
 +
 + private void consumerSuper2(Collection<? super Function> collection){
 + /* WRONG!
 + * You do not know which superclasses of Function the collection contains.
 + */
 +// Function func = collection.iterator().next();
 + }
 +</sxh>
 +
 +
 +
 +
 +===== Debugging Tools =====
 +
 +== VisualVm ==
 +VisualVm is able to connect to a Java virtual mashine and to debug it. \\
 +It is Delivered together with JDK. \\
 +..\Java\jdk1.7.0_15\bin\jvisualvm.exe \\
 +{{http://46zwyrvli634e39iq2l9mv8g.wpengine.netdna-cdn.com/wp-content/uploads/2011/10/Screen-Shot-2011-10-19-at-7.14.47-PM2.png}}
 +
 +
 +== Decompiler ==
 +Procyon - a nice decompiler
 +Luyten - a GUI for the decompiler
 +
 +Luyten v0.4.8 / Procyon v0.5.32
 +
 +https://github.com/deathmarine/Luyten/releases/tag/v0.4.8
 +
 +{{http://i520.photobucket.com/albums/w327/schajtan/2016-08-13_11-36-52_zpspcjqdmpl.png}}
 +
 +
 +=== Remote debugging ===
 +To debug Ant you can enable let ant wait for the debugger to attach,
 +then you may attach to the debugger from Eclipse IDE.
 +
 +To make a java application wait for debugger to attach the following JVM params have to be passed to it 
 +<code>
 +-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=1044
 +</code>
 +
 +
 +To attach with the debugger with Eclipse IDE use the Debug COnfiguration and set the Breaking Point, to stop on an uncatched Exception \\
 +{{http://i520.photobucket.com/albums/w327/schajtan/2015-06-18_13-36-44_zpshnsjyjju.png}}
 +
 +=== suspend=y ===
 +makes the serer stop and wait for debugger to atach.
 +
 +
 +
 +
 +===== Install on Ubuntu and switch version =====
 +
 +<code>
 +sudo apt-get update
 +sudo apt-get install openjdk-8-jdk
 +sudo apt-get install openjdk-11-jdk
 +</code>
 +
 +Then switch the JDK
 +<code>
 +sudo update-alternatives --config java
 +</code>
 +
 +
 +
 +==== Get File as String =====
 +
 +<sxh java>
 +    private Document getStringFromFile(String aspectJsonFile) throws IOException {
 +        Path workDirPath = Path.of(getProjectBasePath());
 +        Path subPath = Path.of("src", "test", "resources", aspectJsonFile);
 +        final Path absPath = workDirPath.resolve(subPath);
 +
 +        return Files.readString(absPath);
 +
 +    }
 +
 +    // returns project base path
 +    private static String getProjectBasePath() {
 +        return new File("").getAbsolutePath();
 +    }
 +</sxh>
 +
 +
 +
 +===== JUnit 5 =====
 +
 +<sxh groovy>
 +
 +</sxh>
 +
 +
 +===== Hamcrest =====
 +
 +Has matches useful for unit tests.
 +
 +Set the groovy dependencies
 +<sxh groovy>
 +dependencies {
 +    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
 +    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
 +
 +    // import here
 +    testImplementation 'org.hamcrest:hamcrest:2.2'
 +}
 +</sxh>
 +
 +Now you can import "org.hamcrest"
 +
 +<sxh java>
 +import static org.hamcrest.MatcherAssert.assertThat;
 +import static org.hamcrest.Matchers.*;
 +
 +import org.junit.jupiter.api.Test;
 +
 +public class MyTest {
 +
 +    @Test
 +    void testExample() {
 +        String value = "Hello, world!";
 +        
 +        assertThat(value, containsString("Hello"));
 +        assertThat(value, endsWith("!"));
 +        assertThat(value, is(notNullValue()));
 +    }
 +}
 +</sxh>
 +
 +
 +===== Text processing =====
 +
 +==== Regular Expressions (java.util.regex) ====
 +
 +When using Regex - make sure you dont introduce too greedy patterns
 +
 +https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
 +<code>
 +Boundary matchers
 +^ The beginning of a line
 +$ The end of a line
 +\b A word boundary
 +\B A non-word boundary
 +\A The beginning of the input
 +\G The end of the previous match
 +\Z The end of the input but for the final terminator, if any
 +\z The end of the input
 +</code>
 +
 +
 +==== Tokenize strings ====
 +
 +Break into single words. 
 +
 +<sxh java>
 +
 +        String[] result = "this is a test".split("\\s");
 +        for (int x=0; x<result.length; x++)
 +            System.out.println(result[x]);
 +
 +/*      this
 +        is
 +        a
 +        test
 +*/
 +
 +</sxh>
 +
 +
 +<sxh java>
 +    @Test
 +    void patternMatch() {
 +        mymatch(".*(alice|bob).*", "bob and alice like to text each other" ); // 1 - because greedy match matches the whole string
 +        mymatch("\\b(alice|bob)\\b", "bob and alice like to text each other" ); // 2 - ACHTUNG: escape back slashes. \b marks word boundaries
 +    }
 +
 +    public static long mymatch(String regex, String text) {
 +        Pattern pattern = Pattern.compile(regex);
 +        Matcher matcher = pattern.matcher(text);
 +
 +        List<MatchResult> res =  matcher
 +                .results()
 +                .toList();
 +
 +        System.out.printf("%s matches %s%n", regex, res.size());
 +        return res.size();
 +    }
 +
 +</sxh>
 +
 +==== ReplaceAll  ====
 +
 +<sxh java>
 +    @Test
 +    void stringReplaceAll() {
 +        String s = "bob and alice like to text each other";
 +        String john = s.replaceAll("\\b(bob)\\b", "john");
 +        System.out.println(john);
 +    }
 +
 +</sxh>
 +
 +
 +===== Records =====
 +First: Java 14
 +
 +
 +
 +<sxh java>
 +    // some interface
 +    interface MyBarkInterface{
 +        default void bark(){
 +            System.out.println("bark bark");
 +        }
 +    }
 +
 +    record MyPoint(int x, int y) implements MyBarkInterface{};
 +
 +    // Cant inherit from Record - its final
 +    //record MyPoint2(int x, int y) extends MyPoint{};
 +
 +
 +    @Test
 +    void recordTest1() {
 +        MyPoint p = new MyPoint(1,2);
 +
 +        System.out.println(p); // MyPoint[x=1, y=2]
 +        System.out.println(p.x()); // can access vars via methods
 +        System.out.println(p.x()); // can access vars via methods
 +        
 +        p.bark(); // can access hiearchy
 +    }
 +
 +</sxh>