Java 8

OpenJDK - JDK 8 Features (opens in a new tab)

Primitives

Float & Double

  • Don't use == or != for comparison. Use Float.compare or >, <.

Enum

  • EnumSet

    • All the methods in an EnumSet are implemented using arithmetic bitwise operations, therefore compact and efficient.

Convert to HEX representation

  • Integer.toHexString(int i)

  • Long.toHexString(int i)

  • Float.toHexString(float i)

  • Double.toHexString(double i)

  • Byte array

    • Lowercase: String.format("%02x", b)
    • Uppercase: String.format("%02X", b)

Control Statements

  • switch

    • Better performance when there are a lot of cases, the more the faster
    • Better readability
    • case expression must be a constant, which means eagerness and static
    • Only the matched case gets executed, order does not matter
    • Without break statement, execution follows through
  • if

    • Dynamic and expressive, as switch does not allow boolean
    • When there is overlap, first case that meets the criteria will be executed, with the rest ignored

Access Control

  • Access level check is performed in the following order:
    1. access level of Class
    2. access level of members of the Class, such as constructors, fields, methods

Generics

  • Wildcard

    • Principle: Producer Extends, Consumer Super

    • extends

      • Set the upper bound, which can be any type that is a descendant of the specified type, but only one at a time.
      • For collection, not able to add element to it, as upper bound is set, while the specific class could be any descendent of the upper bound.
    • super

      • Set the lower bound, which can be any type that is a ancestor of the specified type, which means it works for any type in runtime passes is-a relation.
      // Any type that has an ancestor of Number class
      List<? super Number> list = new ArrayList<>();
      list.add(3);
      list.add(123L);
      list.add(34.0F);
      list.add(34.0D);
    • Can be used in method parameters

    • Can be used as return type

    • Concrete types cannot be captured and used. In those cases, a type parameter must be used.

    • References

  • Troubleshoot compilation error about type inference:

    • Extract variables from chaining method calls to make intermediate type explicit, so compiler can successfully deduce.
    • Closely examine method signatures with type parameters and add type information to method calls when needed.
    • Add omitted type information to variables of lambda expression when necessary.
    • Replace lambda expression with method reference to supplement missing type information.

Annotations

Processing

  • Runtime
    • Reflection API
  • Source code
    • Java Language Model API (javax.lang.model)
    • Java compiler (Annotation Processor)
  • Byte code

Collections

Map

Regular Expression

Example

<?xml version="1.0" encoding="UTF-8"?>
<folder name="c">
    <folder name="program files">
    <folder name="uninstall information" /></folder>
    <folder name="users" />
</folder>
<(?:folder)[\s]+(name)="([\w\s]+)"\s*/?>
  • Use parenthesis to enclose capture group such as (name) and ([\w\s]+) in the example.
  • Group zero denotes the entire pattern, matcher.group() is equivalent to matcher.group(0).
  • Use numbers to access corresponding group like matcher.group(1).
  • Use (?:<pattern>) to denote non-capturing group such as (?:folder) in the example. Non-capturing groups are used for matching, but they are not captured.

NIO.2

Path

  • Path.startWith is used to check path not filename. Use Path.getFileName().toString().startWith instead to check file name.

Stream

  • allMatch and noneMatch return true when stream is empty, while anyMatch returns false;
  • Stream backed by IO resources needs to be closed.

Parallel Stream

Concurrency

ThreadLocal

  • ThreadLocal variable must be either a static variable or an instance variable of a singleton object to ensure single source of truth.
  • Can supply an initial value
  • The value stored by a particular thread is only accessible by itself.
  • The field usually has a type not Thread safe.
private static final ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }
};

InterruptedException

  • Use Thread.isInterrupted instead of Thread.interrupted to check interrupted status, as Thread.interrupted clears interrupted status.
  • java.lang.InterruptedException is intended for stopping the execution of a thread gracefully.
  • Any method throwing java.lang.InterruptedException is a blocking method.

Lock

  • Avoid acquiring multiple locks. If you want to acquire multiple locks, make sure that they are acquired in the same order everywhere to avoid deadlocks.
  • ReentrantLock basically has the same effect as synchronized, but it's not structural and based on methods, therefore more flexible.

volatile

  • Modified by one thread, read by multiple threads

    Best scenario

  • Modified by multiple threads

    Use Atomic classes or locking

  • When you modify a volatile variable, its value is sent to the main memory. The value of all the variables modified previously by the same thread are sent too.

  • Compilers can't reorder sentences that modify a volatile variable for an optimization purpose. It can reorder the previous operations and the later ones, but not the modifications of a volatile variable. The changes that happen before these modifications will be visible to those instructions.

  • volatile variables only solve the visibility problem. They cannot be used to safely implement the atomic read-modify-write sequences that are necessary for safely implementing counters and other entities that require mutual exclusion.

ForkJoinPool

  • All worker threads are daemon threads, which means they don't prevent the JVM from shutting down.

CompletableFuture

Use a custom Executor insteand of the default ForkJoinPool

CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

JSR 310: Date and Time API

  • All classes under java.time package are immutable and thread-safe, so don't forget to assign the result.

  • Period: date-based

  • Duration: time-based

  • Month values are one-based, namely like realworld month values.

  • Formatter

    java.time.format.DateTimeFormatter is thread-safe and immutable, so can be shared thus replacing java.text.DateFormat.

Maths

  • BigDecimal
    • Don't use double constructor, which has precision and approximation issues.
    • Use String constructor as the first choice.
    • Use valueOf() method as the second choice as it still has precision issue.
    • BigDecimals shouldn’t be compared using the equals() method, but instead the compareTo() method should be used, because it compares the numerical values (x = 1; y = 1.0) represented by the two instances of BigDecimal.