Skip to content

Latest commit

 

History

History
2228 lines (1738 loc) · 55 KB

1Z0-816and1Z0-817.md

File metadata and controls

2228 lines (1738 loc) · 55 KB

1Z0-816 & 1ZO-817

Chapter 1: Java Fundamentals

Final Modifier

  • Local variables:
    • Can only be assigned once
    • Must be initialized before it can be used
  • Instance variables:
    • Can only be assigned once inline, in initialization block or constructor
    • Must be initialized
  • Class variables:
    • Can only be assigned once inline or in static initialization block
    • Must be initialized
  • Methods:
    • Can't be overridden
  • Classes:
    • Can't be inherited

Enum

  • List of static enumerated members
  • All values are each constructed, the first time any enum value gets called
  • Can also have:
    • Instance variables (good practice: final)
    • Constructor (implicitly private)
    • Methods

Nested Class

  • Inner class
  • Static nested class
  • Local class
  • Anonymous class

Inner Class:

  • Can have any access modifier
  • Can extend any class or implement interfaces
  • Can not declare static fields or members except for static finals
  • Can access members of the outer class including private ones
  • Require an instance of the outer class to be constructed

Static Nested Class:

  • Can have any access modifier
  • Can be instantiated without an instance of the outer class
  • Can't access instance variables or methods without a reference to an outer class instance
  • The outer class can refer to methods and fields in the static nested class
  • Creates a namespace
  • Can be imported with a regular import

Local Class:

  • Does not have access modifier
  • Defined within a method and only exists when that method is called
  • Can not declare static fields or members except for static finals
  • They have access to all fields and methods of the enclosing class
  • They can access local variables that are effectively final

Anonymous Inner Class:

  • Is a sort of local class, without a name:
    • Does not have access modifier
    • Defined within a method and only exists when that method is called
    • Can not declare static fields or members except for static finals
    • They have access to all fields and methods of the enclosing class
    • They can access local variables that are effectively final
  • Can't be abstract or final
  • Can't both extend and/or have multiple interfaces
  • Is created with an abstract class or interface as model
  • Is a concise way of creating a class we use only once
  • Was used more often before lambda expressions (with functional interfaces)

Interface

Members:

  • Constant variable
  • Abstract method
  • Default method
  • Static method
  • Private method
  • Private static method

Default Interface Method:

  • Can only be declared within an interface
  • Must include a method body (default implementation)
  • Assumed to be public
  • Can't be abstract, final or static
  • Can be overridden
  • Must be overridden if another default method with the same name is inherited

Static Interface Method:

  • Assumed to be public
  • Can't be marked abstract or final
  • Is not inherited

Private Interface Methods:

  • Can't be used outside the interface
  • Mostly to prevent code duplication
  • Can only be called by default and other private methods

Private Static Interface Methods:

  • Can't be used outside the interface
  • Mostly to prevent code duplication
  • Can also be used in static methods

Functional Programming

Functional interfaces are used as the basis for lambda expressions in functional programming. A functional interface is an interface with a single abstract method.

Functional Interface:

  • Can hold one abstract method
  • Can override any amount of abstract methods from object
  • Can hold any amount of other non-abstract methods

Predefined functional interfaces:

  • Predicate
  • ... (more in chapter 3 & 4)

Lambda:

  • Infers the types from the surrounding context
  • Can use variables from 3 places:
    • The parameters
    • Local variables created in the lambda body
    • Variables outside the lambda referenced from the body
  • When var is used in params, all params need to be var
  • Variables referenced from the lambda body need to be effectively final

Chapter 2: Annotations

Annotations allow us to add metadata to our code. Before annotations this metadata often had to be provided by XML or JSON.

Advantages:

  • Metadata in the class
  • Fewer files in the project

Annotation:

  • Is public or package-private (default)
  • Is created with an annotation
  • Without any elements is called a marker annotation
  • Elements without default values are considered required
  • A default value must be a non-null constant expression
  • Elements can be declared with a(n):
    • Primitive
    • String
    • Class
    • Enum
    • Annotation
    • Array of the above
  • Elements are implicitly abstract and public
  • Elements can't be marked final
  • Variables are implicitly public static final
  • They can be applied to:
    • Classes, interfaces, enums and modules
    • Variables (static, instance and local)
    • Methods and constructors
    • Parameters (method, constructor, lambda)
    • Cast expressions
    • Other annotations

Value:

The element name for 'value' can be omitted:

  • Value can be optional or required
  • There can be no other elements required
  • The annotation can not provide values for other annotations

If other optionals are defined in the annotation the element name for value is required.

Annotation-Specific Annotations

@Target

We can specify a declaration type with @Target and limit the types our custom annotation can be used for.

ElementType values:

  • TYPE
  • FIELD
  • METHOD
  • PARAMETER
  • CONSTRUCTOR
  • LOCAL_VARIABLE
  • ANNOTATION_TYPE
  • PACKAGE
  • TYPE_PARAMETER
  • TYPE_USE
  • MODULE

@Retention

We can specify the behaviour of the compiler when it comes to retaining annotation information with @Retention.

RetentionPolicy values:

  • SOURCE
  • CLASS
  • RUNTIME (*Uses reflection)

@Documented

Will make the annotation to which it is applied documented in the Javadocs.

@Inherited

Will make the annotation be inherited by subclasses.

@Repeatable

Will make the annotation usable more than once on a type.

This annotation needs another annotation passed to the value element, which takes an array of the annotation you are creating as its value.

Javadoc Annotations

Javadoc has its own annotations that are not capitalized. They are used mainly for Javadoc styling.

Built-In Annotations

@Override

Override is a marker annotation used to indicate a method is overriding an inherited method. It will not compile if the method is not actually being overridden.

@FunctionalInterface

FunctionalInterface is a marker annotation used to indicate functional interfaces. It will not compile if the interface is not actually fit the Single Abstract Method rule.

@Deprecated

Deprecated is a marker annotation used to indicate a method that will be removed from the API. Not to be confused with the @deprecated from Javadocs.

@SuppressWarnings

SuppressWarnings is a marker annotation used to suppress warnings from the compiler.

Values:

  • Deprecation
  • Unchecked

@SafeVarargs

SafeVarargs is a marker annotation used to suppress warnings about unsafe operations using varargs. It can only be used on methods or constructors using varargs that are either private, static or final.

Chapter 3: Generics and Collections

Functional Interfaces:

  • Supplier
  • Consumer
  • BiConsumer
  • Predicate
  • BiPredicate
  • Function
  • BiFunction
  • UnaryOperator

Method reference: Method references are used to refer to a method of a functional interface. They are even more compact than a lambda expression. Each time when you are using a lambda expression referring to a method, you can replace your lambda expression with a method reference. They prevent the redundant repeat of the parameter.

Four formats:

  • Static methods
  • Instance methods on an instance
  • Instance methods on a parameter
  • Constructors

Collections

Collection Interfaces:

  • List
    • Ordered
    • Allows duplicate
  • Set
    • Not ordered
    • Does not allow duplicate
  • Queue
    • Specific order (fifo, priority, reversed priority, ...)
    • Allows duplicate
  • Map
    • Key- / value pairs
    • Does not allow duplicate keys

The behavior of these interfaces can change depending on the underlying implementation.

Collection Methods:

  • add()

boolean add(E element)

  • remove()

boolean remove(Object o)

  • isEmpty() and size()

boolean isEmpty()
int size()

  • clear()

void clear()

  • contains()

boolean contains(Object o)

  • removeIf()

boolean removeIf(Predicate<? super E> filter)

  • forEach()

void forEach(Consumer<? super T> action)

List

Creating a list with factory methods:

  • Arrays.asList(varargs):

    • Returns fixed size list backed by an array
    • Can replace element
    • Can't add or delete elements
    • Values in array effect list and vice versa
  • List.of(varargs):

    • Returns immutable list
    • Can't replace, add or remove elements
  • List.copyOf(collection):

    • Returns immutable list
    • Can't replace, add or remove elements

List Methods:
The list interface adds some more specific methods and overloads to the ones in Collection.

  • add()

void add(int index, E element)

  • get()

E get(int index)

  • remove()

E remove(int index)

  • replaceAll()

void replaceAll(UnaryOperator op)

  • set()

E set(int index, E e)

Implementations of List:

  • ArrayList: Fast lookup, slower to add and remove
  • LinkedList: Fast to lookup, add and remove at start or end
  • Vector: concurrency

Set

Creating a set with factory methods:

  • Set.of(varargs)
    • Returns immutable set
    • Can't replace, add or remove elements
  • Set.copyOf(collection)
    • Returns immutable set
    • Can't replace, add or remove elements

Implementations of Set:

  • HashSet: Fast
  • TreeSet: Sorted but slower / Null not allowed / Requires the object to implement comparable or a comparator as a parameter
  • LinkedHashSet

Queue

Queue Methods:
The queue interface adds some more specific methods and overloads to the ones in Collection. Also, add() and some others functions* throw an exception on failure.

  • element()*

E element()

  • offer()

boolean offer(E element)

  • remove()*

E remove()

  • poll()

E poll()

  • peek()

E peek()

Implementations of Queue:

  • LinkedList: Can insert at front and back (Fifo, Lifo)
  • PriorityQueue: Ordered
  • ArrayDeque: Fast
  • Stack: concurrency

Map

Creating a map with factory methods:

  • Map.of(key, value, key, value, ...)
    • Number of parameters must be even (or in pairs)
    • Can't take an array like List.of and Set.of()
    • Returns immutable map
    • Can't replace, add or remove elements
  • Map.copyOf(map)
    • Can't take just any collection like List.copyOf and Set.copyOf()
    • Returns immutable map
    • Can't replace, add or remove elements

Map Methods:
The map interface adds some more specific methods and overloads to the ones in Collection.

  • containsKey()

boolean containsKey(Object key)

  • containsValue()

boolean containsValue(Object value)

  • entrySet()

Set<Map.entry<K, V>> entrySet()

  • forEach()

void forEach(BiConsumer<? super K, ? super V> action)

  • get()

V get(Object key)

  • getOrDefault()

V getOrDefault(Object key, V default)

  • keySet()

Set keySet()

  • merge()

V merge(K key, V value, Function<? super V, ? super V, ? extends V> remappingFunction)

  • put()

V put(K key, V value)

  • putIfAbsent()

V putIfAbsent(K key, V value)

  • remove()

V remove(Object key)

  • replace()

V replace(K key, V value)

  • replaceAll()

void replaceAll(BiFunction<? super K, ? super V, ? extends V> function))

  • values()

Collection values()

Implementations of Map:

  • HashMap: Fast
  • TreeMap: Ordered by keys / Null not allowed / Requires the object to implement comparable or a comparator as a parameter
  • LinkedHashMap
  • HashTable: concurrency

Sorting

Comparable

An interface we should implement on our objects when we want to specify the way they should be sorted.

  • Package java.lang

  • One parameter

    public interface Comparable { int CompareTo(T o); }

When implementing comparable:

  • Check for null
  • Keep compareTo() and equals() consistent

Comparator

We don't always have or need a comparable interface. Sometimes we want different sorting methods. This is where the Comparator shines.

  • Package java.util

  • Two parameters

    public interface Comparator { int compare(T o1, T o2); }

Example lambda:

(o1, o2) -> o1.getField() - o2.getField()

In theory both Comparable and Comparator are functional interfaces, but only Comparator should be used as such. The comparator can be defined with a lambda or method reference. However, comparable should be implemented to the class it compares.

Comparator Methods:

  • comparing(function)
  • comparingDouble(function)
  • comparingInt(function)
  • comparingLong(function)
  • naturalOrder()
  • reverseOrder()

Chainable methods:

  • reversed()
  • thenComparing(function)
  • thenComparingDouble(function)
  • thenComparingInt(function)
  • thenComparingLong(function)

Generics

Generics are use where we don't want to be type specific and are creating functionality that do not need to have a connection to the types they work with. Collections make a lot of use of generics.

Naming convention:

  • E for an element
  • K for a map key
  • V for a map value
  • N for a number
  • T for a generic data type
  • S, U, V, ... for multiple generic types

Type Erasure:
Type erasure can be explained as the process of enforcing type constraints only at compile time and discarding the element type information at runtime.

For example:

class Crate<T> {
  private T content;

  public void loadCrate(T content){
      this.content = content;
  }

  public T unloadCrate(){
      return content;
  }
}

Will be compiled to:

class Crate {
  private Object content;

  public void loadCrate(Object content){
      this.content = content;
  }

  public Object unloadCrate(){
      return content;
  }
}

Generic Interfaces

Interfaces can use generic types too:

public interface Shippable<T> {
  void ship(T t);
}

When implemented to a class we can choose to specify a type or a generic type. We can also just use Object instead of generics.

Generic Methods

We can also use them in methods:

public static <T> Crate<T> ship(T t){
    return new Crate<>();
}

We declare the formal type parameter before the return type.

We can call this method normally, or define the type:

Crate.ship("package")
Crate.<String>ship("package")

What we can't do with generics

  • Call a constructor (new T)
  • Create an array of a generic type
  • Call instanceof
  • Use a primitive type as a generic type
  • Create a static variable as a generic type

Bounding Generic Types

Wildcards:

  • Unbounded wildcard
    • ?
    • Any type
  • Upper-bounded wildcard
    • ? extends type
    • This type or any subtype
  • Lower-bounded wildcard
    • ? super type
    • This type or any supertype

Chapter 4: Functional Programming

Functional Interfaces:

  • Supplier
public interface Supplier<T> {
  T get();
}
  • Consumer
public interface Consumer<T> {
  void accept(T t);
}
  • BiConsumer
public interface Biconsumer<T, U> {
  void accept(T t, U u);
}
  • Predicate
public interface Predicate<T> {
  test(T t);
}
  • BiPredicate
public interface BiPredicate<T, U> {
  test(T t, U u);
}
  • Function
public interface Function<T, R> {
  R apply(T t);
}
  • BiFunction
public interface BiFUnction<T, U, R> {
  R apply(T t, U u);
}
  • UnaryOperator
public interface UnaryOperator<T> extends Function<T, T> {
  T apply(T t);
}
  • BinaryOperator
public interface BinaryOperator<T> extends BiFunction<T, T, T> {
  T apply(T t1, T t2);
}

Convenience Methods:

  • Consumer
    • andThen()
  • Function
    • andThen()
    • compose()
  • Predicate
    • and()
    • negate()
    • or()

Optional

The purpose of an optional is to provide a type-level solution for representing optional values instead of null references.

Advantages over null:

  • Statement by API there might not be a value
  • Functional programming
  • Chaining optional calls

Factory Methods:

  • Optional.empty()
  • Optional.of()
  • Optional.ofNullable()

Methods:

  • isPresent()
  • get()
  • ifPresent(Consumer c)
  • orElse(T other)
  • orElseGet(Supplier s)
  • orElseThrow()
  • orElseThrow(Supplier s)

Streams

Streams are like an assembly line, where Java is the foreman putting operators to work. Every previous operation has to complete before the next can start.

Pipeline flow:

  • Source
  • Intermediate operations
  • Terminal operation

Stream Sources

Factory Methods:

  • Finite
    • Stream.empty()
    • Stream.of()
  • Infinite
    • Stream.generate()
    • Stream.iterate()

Collection API:

  • stream()
  • parallelStream()

Terminal Operations

  • count()
  • min()
  • max()
  • findAny()
  • findFirst()
  • allMatch()
  • anyMatch()
  • noneMatch()
  • forEach()
  • reduce()
  • collect()

Intermediate Operations

  • filter()
  • distinct()
  • limit()
  • skip()
  • map()
  • flatMap()
  • sorted()
  • peek()

Primitive Streams

Types:

  • IntStream
  • LongStream
  • DoubleStream

Factory Methods:

  • Finite
    • Stream.empty()
    • Stream.of()
  • Infinite
    • Stream.generate()
    • Stream.iterate()

Primitive Stream Methods:

  • average()

OptionalDouble average()

  • boxed()

Stream boxed()

  • max()

OptionalInt max()

  • min()

OptionalLong min()

  • range(long a, long b)

IntStream range()

  • rangeClosed()

IntStream rangeClosed(int a, int b)

  • sum()

int sum()

  • summaryStatistics()

IntSummaryStatistics summaryStatistics()

Optionals with Primitive Streams

Types:

  • OptionalInt
  • OptionalDouble
  • OptionalLong

Summary Statistics

We can only use one terminal operation on a stream once. If we want to do more calculations like getting an average, min and max and more, we can use the summary statistics methods with our primitive streams.

  • IntSummaryStatistics
  • LongSummaryStatistics
  • DoubleSummaryStatistics

Method:

  • summaryStatistics()

Functional Interfaces for Primitives

Boolean~:

  • BooleanSupplier

Int- Long- and Double~:

  • IntSupplier

  • IntConsumer

  • IntPredicate

  • IntFunction

  • IntUnaryOperator

  • IntBinaryOperator

  • ToIntFunction

  • ToIntBiFunction

  • IntToLongFunction

  • IntToDoubleFunction

  • ObjIntConsumer

All of these also have their Double and Long variations.

Advanced Concepts

Streams and underlying data:
Streams only are created when they are called. If a collection gets updated after the stream was described, but before it is called, these changes will affect the result when the stream is called?

Chaining optionals:
We can use flatMap() to remove an unnecessary layer and transform one optional type to another.

Handling checked exceptions in a lambda:

  • Catch and turn into unchecked exception (ugly)
  • Create a wrapper method with a try/catch and use the wrapper in the lambda

Grouping/Partitioning Collectors

  • averagingInt(ToIntFunction f)
  • counting()
  • groupingBy(Function f, Supplier s, Collector dc)
  • joining(CharSequence cs)
  • maxBy(Comparator c)
  • minBy(Comparator c)
  • mapping(Function f, Collector dc)
  • partitioning(Predicate p, Collector dc)
  • summarizingInt(ToIntFunction f)
  • summingInt(ToIntFunction f)
  • toList()
  • toSet()
  • toCollection(Supplier s)
  • toMap(Function k, Function v, BinaryOperator m, Supplier s)

Chapter 5: Exceptions, Assertions and Localizations

We handle exceptions with try-statements.

Try:

  • try
  • catch
  • finally

Needs either a catch or finally block.

Try-with resources:

  • try
  • catch
  • finally + implicit

Doesn't need catch or finally block, because resources are closed in an implicit finally block.

Unchecked Exceptions:

  • ArithmeticException
  • ArrayIndexOutOfBoundsException
  • ArrayStoreException
  • ClassCastException
  • IllegalArgumentException
    • NumberFormatException
  • IllegalStateException
  • MissingResourceException
  • NullpointerException
  • UnsupportedOperationException

Checked Exception:

  • IOException
    • FileNotFoundException
    • NotSerializableException
  • ParseException
  • SQLException

We can't list an exception in a multi-catch block that inherits from one of the others. We can list them in consecutive catch blocks, but only with the most specific one first.

Custom exceptions:

  • Unchecked exception inherit from RuntimeException
  • Checked Exceptions inherit from Exception

Automating Resource Management

Closing resources is paramount for Java to be able to garbage collect the objects. Connections to resources left open will lead to resource leaks making our program vulnerable to attacks.

Resources need to implement AutoCloseable. They will be closed before any catch- or finally block.

We can reference resources that are effectively final (not reassigned). Even though it is a bad idea, we can make method calls on them before the try block, but not after. The resource has than been closed.

Suppressed Exceptions

The first exception thrown in the current try block is the primary exception. Any other exceptions thrown by the resources are considered suppressed exceptions.

If the exception isn't caught it will be thrown to the caller and eventually the main function would handle it.

We do not want to lose exceptions, so we want to make sure no exceptions can be thrown in the finally block. Since resource management was added in Java 7 with backward compatibility and this behaviour existed before, this is considered a bad practice.

Assertions

Examples:

assert boolean_expression;
assert boolean_expression: error_message;

Short for:

if(!boolean_expression) throw new AssertionError(error_message);

Assertions are disabled by default. We can run our code with assertions on:

  • For one class:

java -ea Rectangle

  • For the whole program:

java -ea:be.dog.d.steven... my.programs.Main

  • For the whole program but one class:

java -ea:be.dog.d.steven... -da:be.dog.d.steven.SomeClass my.program.Main

We don't want assert-statements to alter the outcome of our code. They are only used when debugging, and this would make our code run different in a test run compared to in production.

Dates and Times

New API:

  • LocalDate
  • LocalTime
  • LocalDateTime
  • ZonedDateTime

Creating dates or times uses Factory Methods because the

  • of()

Date/time symbols for formatting:

  • y: year
  • M: Month
  • d: Day
  • h: Hour
  • m: Minute
  • s: Second
  • a: am/pm
  • z: Time zone
  • Z: Time zone offset

Internationalization

Examples:

  • es
  • nl
  • nl_BE
  • en_GB
  • en_UK

Localizing Numbers

NumberFormat Methods:

  • getInstance()
  • getNumberInstance()
  • getCurrencyInstance()
  • getPercentInstance()
  • getIntegerInstance()

These take an optional locale as a parameter, without it the default will be used.

Custom NumberFormat:

  • #: Omit if no digit exists
  • 0: 0 if no digit exists

Localizing Dates

DateTimFormatter Methods:

  • ofLocalizedDate(dateStyle)
  • ofLocalizedTime(timeStyle)
  • ofLocalizedDateTime(dateStyle, timeStyle)
  • ofLocalizedDateTime(dateTimeStyle)

Locale.setDefault() allows a second Category parameter to further specify the setting of the Locale, allowing finer-grained control over the Locale options.

Resource Bundles

Order looking for a bundle:

  1. Requested locale
  2. Language locale
  3. Default locale
  4. Default language locale
  5. Default bundle
  6. MissingResourceException

Formatting messages:
We can use parameters in our string resources from a bundle using {0}, {1}, ...

Example:

MessageFormat.format(rb.getString("someFormattedStrinInBundle), "param1", "param2")

This format() function takes in a vararg of strings. Too few varargs will make the placeholders visible. Too many varargs will simply be ignored.

Properties

The properties class is like a HashMap<String, String>. It is commonly used in handling values that may not exist.

Chapter 6: Modular Applications

Directives:

- exports <package>
- exports <package> to <module>
- opens <package>
  -> Also enables reflection API
- requires <module>
- requires transitive <module>
  -> Recursive dependency
- requires static <module>
  -> Doesn't load on startup
- uses <interface>
- provides <interface> with <class>

Types of Modules:

  • Named Modules
    • On module path
    • module-info.java file in root
    • One or more packages in root
  • Automatic Modules
    • On module pat
    • Exports all packages
    • One or more packages in root
    • Java automatically determines the module name
      • Automatic-Module-Name in MANIFEST.MF (META-INF)
      • JAR-file name: holiday-calendar-1.0.0.jar -> holiday.calendar
        • Remove .jar
        • Remove version
        • Replace non-letters with .
        • No double .
        • No leading or trailing .
  • Unnamed Modules
    • On class path
    • Doesn't work like a module
    • Does not export packages to named or automatic modules

Built in modules:

java --list-modules

Java:

  • java.base
  • java.compiler
  • java.datatransfer
  • java.desktop
  • java.instrument
  • java.logging
  • java.management
  • java.management.rmi
  • java.naming
  • java.net.http
  • java.prefs
  • java.rmi
  • java.scripting
  • java.se
  • java.security.jgss
  • java.security.sasl
  • java.smartcardio
  • java.sql
  • java.sql.rowset
  • java.transaction.xa
  • java.xml
  • java.xml.crypto

Jdk:

  • jdk.accessibility
  • jdk.aot
  • jdk.attach
  • jdk.charsets
  • jdk.compiler
  • jdk.crypto.cryptoki
  • jdk.crypto.ec
  • jdk.crypto.mscapi
  • jdk.dynalink
  • jdk.editpad
  • jdk.hotspot.agent
  • jdk.httpserver
  • jdk.incubator.foreign
  • jdk.incubator.jpackage
  • jdk.internal.ed
  • jdk.internal.jvmstat
  • jdk.internal.le
  • jdk.internal.opt
  • jdk.internal.vm.ci
  • jdk.internal.vm.compiler
  • jdk.internal.vm.compiler.management
  • jdk.jartool
  • jdk.javadoc
  • jdk.jcmd
  • jdk.jconsole
  • jdk.jdeps
  • jdk.jdi
  • jdk.jdwp.agent
  • jdk.jfr
  • jdk.jlink
  • jdk.jshell
  • jdk.jsobject
  • jdk.jstatd
  • jdk.localedata
  • jdk.management
  • jdk.management.agent
  • jdk.management.jfr
  • jdk.naming.dns
  • jdk.naming.rmi
  • jdk.net
  • jdk.nio.mapmode
  • jdk.sctp
  • jdk.security.auth
  • jdk.security.jgss
  • jdk.unsupported
  • jdk.unsupported.desktop
  • jdk.xml.dom
  • jdk.zipfs

Example file:

// Animatronics.java
package zoo.dinos;

import java.time.*;
import java.util.*;
import sun.misc.Unsafe;

public class Animatronic {
private List<String> names;
private LocalDate visitDate;

    public Animatronic(List<String> names, LocalDate visitDate) {
        this.names = names;
        this.visitDate = visitDate;
    }
    
    public void unsafeMethod() {
        Unsafe unsafe = Unsafe.getUnsafe();
    }
}

Compile:

javac zoo/dinos/*.java

Create a JAR:

jar -cvf zoo.dino.jar .

List dependencies:

jdeps zoo.dino.jar

Summarize dependencies:

jdeps -s zoo.dino.jar

Get unsupported API from jdk:

jdeps --jdk-internals zoo.dino.jar

Migration strategies:

  • Bottom-up:
    • From: unnamed on classpath
    • To: named on module path
  • Top-down:
    • Move all modules to the module path first
    • From: automatic on module path
    • To: named on module path

Cyclic dependencies: We fix cyclic dependencies with creating another module that holds the shared code.

Creating a Service

Service with implementation:

provides <path.to.Service> with <path.to.Implementation>

Part of service:

  • Service provider interface
    • module-info.java: -exports
  • Service locator
    • module-info.java:
      • exports
      • requires
      • uses

Not part of the service:

  • Service provider
    • module-info.java:
      • requires
      • provides
  • Consumer
    • module-info.java:
      • requires

ServiceLoader<S> has 2 methods: load(Class<S> service) and stream(). The method stream() returns a stream of Provider<S>, so we need to call get() to retrieve the wanted values out of the providers.

ServiceModule

public class Main {
    public static void main (String[] args){
        ServiceLoader<ProductManager> sl = ServiceLoader.load(ProductManager.class);
        ProductManager pm = sl.findFirst().get();
    }
}

Most likely we will use some other logic to determine what implementation to use, other than findFirst().

Chapter 7: Concurrency

Thread

A thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler, which is typically a part of the operating system. The implementation of threads and processes differs between operating systems, but in most cases a thread is a component of a process. Multiple threads can exist within one process, executing concurrently and sharing resources such as memory, while different processes do not share these resources. In particular, the threads of a process share its executable code, the values of its dynamically allocated variables and non-thread-local global variables at any given time.

  • System threads
  • User defined threads

This distinction means that all Java applications are multi-threaded. Daemon threads, like garbage collection, are threads that do not prevent the JVM from exiting when the program finishes.

Scheduling:

  • Context switches: Storing the state of a thread to later restore the thread and continue the process
  • Thread priorities: A numeric value (in Java) associated with the thread indicating its priority

Runnable

Runnable is an interface used to define the work a thread will execute.

@FunctionalInterface
public interface Runnable() {
  void run();
}

The runnable interface:

  • Does not take any parameters
  • Does not return a value
  • Can be used as lambda
  • Can be implemented to a class

Creating a thread using the Thread class:

  • Define the thread
    • Runnable object or lambda
    • Class that extends Thread
      • To create own priority-based thread
  • Start the thread

Java does not guarantee any order of execution.

Asynchronous:
Without waiting for the result of other threads

Methods:

  • start(): starts a new thread
  • run(): runs code but does not start a new thread
  • shutdown()
  • isShutdown()
  • isTerminated()

Concurrency API

The Executors class provides factory methods:

  • newSingleThreadExecutor()
  • newSingleThreadScheduledExecutor()
  • newCashedThreadPool()
  • newFixedThreadPool()
  • newScheduledThreadPool()

ExecutorService Methods:

  • execute()
void execute(Runnable command)
  • submit()
Future<?> submit(Runnable task)  

<T> Future<T> submit(Callable<T> task)
  • invokeAll()
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InteruptedException
  • invokeAny()
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InteruptedException, ExecutionException
  • awaitTermination
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
  • isTerminated
boolean awaitTermination()

Unlike execute() and submit(), invokeAll() and invokeAny() execute synchronously. This means they are executed in order and can execute a List of tasks.

Future

Returned instance by various API, with useful methods to determine the state of a task.

Future Methods:

  • isDone()

boolean isDone()

  • isCancelled()

boolean isCancelled()

  • cancel()

boolean cancel(boolean mayInterruptIfRunning)

  • get()

V get()
V get(long timeout, TimeUnit unit)

Callable

Allows for more details to be retrieved than Runnable.

@FunctionalInterface
public interface Callable<V>{
  V call() throws Exception;
}

The callable interface:

  • Does not take any parameters
  • Returns a generic Type
  • Can be used as lambda

Scheduling Tasks

ScheduledExecutorService Methods:

  • schedule()
schedule(Callable<V> callable, long delay, TimeUnit unit)

schedule(Runnable command, long delay, TimeUnit unit)
  • scheduleAtFixedRate()
scheduleAtFixedRate(Runnable command, long initialDelay, long delay, TimeUnit unit)
  • scheduleWithFixedDelay()
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

Thread Pool

A pool of threads allowing tasks to be executed concurrently.

Example of a fixed size thread pool:

Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())

Thread safety: Because some operations aren't thread safe there are multiple ways to support thread safety.

Atomic Classes

  • AtomicBoolean
  • AtomicInteger
  • AtomicLong

Atomic Methods:

  • get()
  • set()
  • getAndSet()
  • incrementAndGet()
  • getAndIncrement()
  • decrementAndGet()
  • getAndDecrement()

Synchronized Blocks

We can synchronize execution in a synchronized block. We can synchronize on any object, making this object final ensures it is not reassigned after threads start using it.

Examples:

synchronized(this) { ... }

private final Object anyObject = new Object();
synchronized(anyObject) { ... }

We can also use the synchronized keyword on methods:

private synchronized void someMethod() { ... }

Cost: We should avoid synchronization whenever we can, because it comes at a high performance cost.

Lock Framework

The lock framework offers more functionality than a synchronized block:

  • Request lock without blocking
  • Request a lock while blocking for specified amount of time
  • Create locks with fairness property, where the lock is granted to threads in the order they were requested

We always need to release locks, and we shouldn't release locks that don't exist. In other words, the number of releases has to be equal to the number of locks granted.

  • ReentrantLock()
  • ReentrantReadWriteLock()
  • ...

Example:

Lock lock = new ReentrantLock();
try {
  lock.lock();
  // Protected code
} finally {
  lock.unlock();
}

Methods:

  • lock()

void lock()

  • unlock()

void unlock()

  • tryLock()

boolean tryLock()
boolean tryLock(long timeout, TimeUnit unit)

Cyclic Barrier

Cyclic barriers allow us to better manage multithreaded tasks, by making all threads stop and wait at logical barriers.

CyclicBarrier b1 = new CyclicBarrier(3);
CyclicBarrier b2 = new CyclicVarrier(3, () -> System.out.println("some task to perfrom when all threads at barrier"));
...
b1.await(); b2.await();

These will make all threads wait for the (in this case) three threads to complete. We should have a thread pool at least the size of the barrier limit to prevent the code to hang.

Concurrent Collections

Collections that provide thread safe reading and writing access.

  • ConcurrentHashMap<>()

  • ConcurrentLinkedQueue<>()

  • ConcurrentSkipListSet<>()

    • Like TreeSet<>()
  • ConcurrentSkipListMap<>()

    • Like TreeMap<>()
  • CopyOnWriteArrayList<>()

  • CopyOnWriteArraySet<>()

  • LinkedBlockingQueue<>()

BlockingQueue

Additional Methods:

  • offer(E element, long timeout, TimeUnit unit)
  • poll(long timeout, TimeUnit unit)

Collection API methods

  • synchronizedCollection(Collection c)
  • synchronizedList(List list)
  • synchronizedMap(Map<K,V> m)
  • synchronizedNavigableMap(NavigableMap<K,V> m)
  • synchronizedNavigableSet(NavigableSet s)
  • synchronizedSet(Set s)
  • synchronizedSortedMap(SortedMap<K,V> m)
  • synchronizedSortedSet(SortedSet s)

The collections that are returned are thread safe. However, the maps can't be used to iterate over and modify themselves like the ConcurrentHshMap!

Liveness

Issues:

  • Deadlock: Two or more threads are blocked forever
  • Starvation: A thread is perpetually denied access to a shared resource or lock
  • Livelock: Two threads trying to resolve a deadlock, restarting part of the process indefinitely

Race Conditions

A race condition occurs when two or more threads can access shared data, and they try to change it at the same time. Because the thread scheduling algorithm can swap between threads at any time, you don't know the order in which the threads will attempt to access the shared data. Therefore, the result of the change in data is dependent on the thread scheduling algorithm, i.e. both threads are "racing" to access/change the data.

Parallel Streams

The stream API has built-in concurrency features.

On a stream:

  • parallel(): Intermediate operation on an existing stream. Calling a terminal operation on it will also make the original unavailable.
  • isParallel(): Checks if a stream is parallel. Some operations like flatmap() create a new stream that is not parallel by default.

On a collection:

  • parallelStream(): Returns a parallel stream from a collection.

Parallel Decomposition:
The process of taking a task and breaking it up into smaller peaces.

Most operations will behave different when it comes to order for parallel streams.

Order operations will have the same result for parallel as for serial streams:

  • skip()
  • limit()
  • findFirst()
  • ...

These ordered operation will take more time for a parallel stream to complete. Sometimes making the stream unordered can improve performance.

Requirements for a parallel reduction with collect():

  • The stream is parallel
  • The parameter of the collect() operation has the Characteristics.CONCURRENT characteristic
  • Either the stream is unordered, or the collector has the characteristic Characteristics.UNORDERED

Collector method:

characteristics()

Stateful Operations

A stateful operation is the one whose result depends on any state that might change during the execution of the pipeline. Stateless operations retain no state during the execution of the pipeline.

We want to avoid using stateful operations, so our functions can be used in parallel streams.

Chapter 8: I/O

Java IO (Input/Output) streams are flows of data you can either read from, or write to. Streams are typically connected to a data source, or data destination, like a file or network connection.

File

The File class can indicate both files and directories in the file structure.

Methods:

  • delete()

boolean delete()

  • exists()

boolean exist()

  • getAbsolutePath()

String getAbsolutePath()

  • getName()

String getName()

  • getParent()

String getParent()

  • isDirectory()

boolean isDirectory()

  • isFile()

boolean isFile()

  • lastModified()

long lastModified()*

  • length()

long length()

  • listFiles()

File[] listFiles()

  • mkdir()

boolean mkdir()

  • mkdirs()

boolean mkdirs()

  • renameTo()

boolean renameTo(File dest)

  • toPath()

Path toPath()

File path:

  • Absolute
  • Relative

Classifications:

  • Byte stream / Character stream / ...
  • Input stream / Output stream
  • Low-level stream / High-level stream

Abstract base classes:

  • Byte streams:
    • InputStream
    • OutputStream
  • Character streams:
    • Reader
    • Writer

Concrete stream classes:

  • Low-level:
    • FileInputStream
    • FileOutputStream
    • FileReader
    • FileWriter
  • High-level:
    • BufferedInputStream
    • BufferedOutputStream
    • BufferedReader
    • BufferedWriter
    • ObjectInputStream
    • ObjectOutputStream
    • PrintStream
    • PrintWriter

Common operations

InputStream

  • read()

public int read() throws IOException
public int read(byte[] b) throws IOException
public int read(byte[] b, int offset, int length) throws IOException

Reader

  • read()

public int read() throws IOException
public int read(char[] b) throws IOException
public int read(char[] b, int offset, int length) throws IOException

OutputStream

  • write()

public void write(int b) throws IOException
public void write(byte[] b) throws IOException
public void write(byte[] b, int offset, int length) throws IOException

Writer

  • write()

public void write(int b) throws IOException
public void write(char[] b) throws IOException
public void write(char[] b, int offset, int length) throws IOException

Both the byte and character streams use int to be able to handle the byte-sized 256 characters of ASCII + special values, like -1 to indicate the end of the stream for example.

Closing Streams

Streams are resources and should be closed, so we do not create resource leaks!

  • With close() method
  • By using try with resources

Manipulating Input Streams

  • marSupported()

boolean markSupported()

  • mark()

void mark(int readLimit)

  • reset()

void reset() throws IOException

  • skip()

long skip(long n) throws IOException

Flushing Output Streams

Requests that all accumulated data be written immediately to disk.

  • flush()

void flush() throws IOException

Buffering I/O Streams

The buffered classes contain a number of performance improvements for managing data in memory.

Serializing

Serializing and deserializing objects is a process with which we can save our objects to files.

The serializable interface is a marker interface which we use for marking data-oriented classes that we prepared a class to be properly serialized.

SerialVersionUID is used to keep track of objects that have been serialized with older versions of a class.

Conditions:

  • Class must be marked with Serializable
  • Every instance member of the class must be serializable, transient or have a null value at time of serialization.
    • This must be true recursively so...

Deserializing

Java will call the constructor of the first non-serializable parent class.

  • Transient modifier is used for fields that do not make sense to be serialized like passwords for instance. The value will be set to the default Java value (0, null, ...)
  • Static variables will get whatever value was set last (on startup it will be the value the class is initialized with)
  • Any constructors or instance initialization blocks in the class itself are ignored

There are other more popular API than I/O-streams for serialization.

Printing Data

PrintStream and PrintWriter do not have corresponding input streams.

PrintStream(OutputStream out)
PrintStream(File file)
PrintStream(String fileName)

PrintWriter(Writer out)
PrintWriter(File file)
PrintWriter(String fileName)
PrintWriter(OutputStream out)

System.out and System.err are printstreams.

Methods:

  • print()
  • println()
  • format()

Formatting

Symbols used in format():

  • %s : String
  • %d : int
  • %f : float/double
  • %n : system-dependent line separator

Console

Factory method:

System.getConsole()

Might return null, so null checks are good practice before using the console.

Methods:

  • reader()
  • writer()
  • format()
  • readLine()
  • readPassword()

Chapter 9: NIO

The primary use of Java NIO is to access files via a channel and buffers. The NIO.2 enhanced it to stream-based I/O as well. Therefore, NIO now provides the capability for channel-based I/O, stream-based I/O, and for Path and File system operations. New features added to NIO.2 extensively extended the capability of its predecessor.

Path

The Path class can indicate both files and directories in the file structure.

File path:

  • Absolute
  • Relative

Symbolic link: A special file within a file system that serves as a reference or pointer to another file or directory.

Factory method: (Java 11: NIO.2)

Path.of("some/path.txt")

Or with vararg:

Path.of("some", "path.txt")

Or with a URI:

Path.of(URI uri)

Factory method: (Before Java 11: NIO)

Paths.get("some/path.txt")

Or with vararg:

Paths.get("some", "path.txt")

Or with a URI:

Paths.get(URI uri)

Method:

  • toUri()

URI toUri()

  • toFile()

File toFile()

URI

  • Local:
    • file://
  • Remote:
    • http://
    • https://
    • ftp://

Example:

Uri uri = new URI("file://some/path.txt"):

FileSystem

Factory method:

FileSystem.getDefault()

Method:

  • getPath()

Path getPath(String first, String... more)

Example:

Path path = FileSystem.getDefault().getPath("some/path.txt")

NIO.2 Features

Path Symbols

  • . : Reference to the current directory
  • .. : Reference to the parent directory

Optional Arguments

  • LinkOption
    • NOFOLLOW_LINKS
  • StandardCopyOption
    • ATOMIC_MOVE
    • COPY_ATTRIBUTES
    • REPLACE_EXISTING
  • StandardOpenOption
    • APPEND
    • CREATE
    • CREATE_NEW
    • READ
    • TRUNCATE_EXISTING
    • WRITE
  • FileVisitOption
    • FOLLOW_LINKS

Most methods take a vararg of these options, even if there is only one possibility, for future proofing.

Interacting with Paths

Path methods:

  • toString()

String toString()

  • getNameCount()

int getNameCount()

  • getName()

Path getName(int index)

  • subPath()

Path subPath(int beginIndex, int endIndex)

  • getFileName()

Path getFileName()

  • getParent()

Path getParent()

  • getRoot()

Path getRoot()

  • isAbsolute()

boolean isAbsolute()

  • toAbsolutePath()

Path toAbsolutePath()

  • resolve()

Path resolve(Path other)
Path resolve(String other)

  • relativize()

Path relativize()

  • normalize()

Path normalize()

  • toRealPath()

Path toRealPath(LinkOption... options) throws IOException

The root is not considered part of the path.

Files methods:

  • exists()

boolean exists(Path path, LinkOption... options)

  • isSameFile()

boolean isSameFile(Path path, Path path2) throws IOException

  • createDirectory()

Path createDirectory(Path path, FileAttribute<?>... attrs) throws IOException

  • createDirectories()

Path createDirectories(Path path, FileAttribute<?>... attrs) throws IOException

  • copy()

Path copy(Path source, Path target, CopyOption... options) throws IOException

  • move()

Path move(Path source, Path target, CopyOption... options) throws IOException

  • delete()

void delete(Path path) throws IOException

  • deleteIfExists()

boolean deleteIfExists(Path path) throws IOException

  • newBufferedReader()

BufferedReader newBufferedReader(Path path) throws IOException

  • newBufferedWriter()

BufferedWriter newBufferedWriter(Path path) throws IOException

  • readAllLines()
List<String> readAllLines(Path path) throws IOException

File Attributes

Files attribute methods:

  • isDirectory()

boolean isDirectory(Path path, LinkOption... options)

  • isSymbolicLink()

boolean isSymbolicLink(Path path)

  • isRegularFile()

boolean isRegularFile(Path path, LinkOptions... options)

  • isHidden()

boolean isHidden(Path path) throws IOException

  • isReadable()

boolean isReadable(Path path)

  • isWritable()

boolean isWritable(Path path)

  • isExecutable()

boolean isExecutable(Path path)

  • size()

long size(Path path) throws IOException

  • getLastModifiedTime()

FileTime getLastModifiedTime(Path path, LinkOptions... options) throws IOException

View types:

  • BasicFileAttributes
    • BasicFileAttributeView
  • DosFileAttributes
    • DosFileAttributeView
  • PosixFileAtributes
    • PosixFileAtributeView

Files attribute view methods:

  • readAttributes()
<A extends BasicFileAttributes> A readAttributes(Path path, Class<A>, type, LinkOption... options) throws IOException
  • getFileAttributeView()
<V extends FileAttributeView> V getFileAttributeView(Path path, Class<V>, type, LinkOption... options)

BasicFileAttributeView method:

  • setTimes()

void setTimes(FileTime lastModifiedTime, FileTime lastAccessTime, FileTime createTime)

Functional Programming with NIO.2

  • list()
Stream<Path> list(Path dir) throws IOException
  • walk()
Stream<Path> walk(Path start, FileVisitOption... options) throws IOException

Stream<Path> walk(Path start, int maxDepth, FileVisitOption... options) throws IOException

Traversing a tree can be done depth first or breadth first. The walk() method traverses the tree depth first. A maximum depth can be given as a parameter to limit the number of levels down from the root to be visited.

Compared to other methods the walk() method by default does NOT follow symbolic links. We can use the FileVisitOption.FOLLOW_LINKS to change this behaviour. When enabled we should be cautious not to walk the whole file system or enter circular paths.

  • find()
Stream<Path> find(Path start, int maxDepth, BiPredicate<Path,BasicFilterAttributes> matcher, FileVisitOption... options) throws IOException
  • lines()
Stream<Path> lines(Path path) throws IOException

The lines() method lazily reads line by line where the readAllLines() method eagerly reads the whole file before continuing.

Chapter 10: JDBC

Java Database Connectivity Language (JDBC): Access data as rows and columns.
Java Persistence API (JPA): Access data through Java objects using Object Relational Mapping.

Structured Query Language (SQL): Used to interact with records in relational databases.

*Add derby.jar to the project and run SetupDerbyDatabase to set up a Derby DB to run the code examples.

CRUD:

- Create: INSERT
- Read:   SELECT
- Update: UPDATE
- Delete: DELETE

Interfaces:

  • Driver: Establishes connection
  • Connection: Sends commands to DB
  • PreparedStatement: Executes SQL query
  • CallableStatement: Executes commands stored in DB
  • ResultSet: Reads results of query

URL

Format:
Protocol : subprotocol :// subname

jdbc:postgres://localhost:5432/zoo

DriverManager:

  • getConnection(String url)
  • getConnection(String url, String userName, String password)

Connection

Methods:

  • getConnection() : PreparedStatement
  • prepareCall() : CallableStatement

PreparedStatement

  • Statement
    • PreparedStatement
    • CallableStatement

Advantages over Statement:

  • Performance
  • Security
  • Readability
  • Future use

Executing PreparedStatement:

  • executeUpdate()
    • Returns the number of rows inserted/updated/deleted
  • executeQuery()
    • Returns a ResultSet
  • execute()
    • Returns a boolean stating if there is a ResultSet we can retrieve with getResultSet()

Batching statements:

  • addBatch()
  • executeBatch()

Bind Variables and Parameters

We can use '?' in our sql queries to bind paramets to when executing them with a method.

Example:

public static void register(Connection conn, int key, int type, String name) throws SQLException {
    String sql = "INSERT INTO names VALUES(?, ?, ?)";

    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.setInt(1, key);
        ps.setInt(2, type);
        ps.setString(3, name);
        ps.executeUpdate();
    }
}

Notice that JDBC starts counting columns with 1!

More PreparedStatement methods:

  • setInt()
  • setString()
  • setBoolean()
  • setDouble()
  • setLong()
  • setByte()
  • setFloat()
  • setObject()
  • ...

ResultSet

ResultSet methods:

  • next()
  • getInt()
  • getString()
  • getBoolean()
  • getDouble()
  • getLong()
  • getByte()
  • getFloat()
  • getObject()
  • ...

We use next() in if or while statements to check if there is a value.

Callable Statement

CallableStatement interface is used to call the stored procedures and functions. We can have business logic on the database by the use of stored procedures and functions that will make the performance better because these are precompiled.

CallableStatement types:

  • No parameters
  • IN
  • OUT
  • INOUT

Methods:

  • executeQuery()
  • execute()
  • registerOutParameter()
  • setInt()
  • setString()
  • setBoolean()
  • setDouble()
  • setLong()
  • setByte()
  • setFloat()
  • setObject()
  • ...

Chapter 11: Security

Secure Objects:

  • Limit accessibility
    • Private members
  • Restrict extensibility
    • Final class
  • Make object immutable
    • Final class
    • Private instance variables
    • No setter methods
    • Don't allow a referenced mutable object to be modified
      • No getters for objects that are mutable
      • Create delegate methods or return a copy of the mutable object
    • Use a constructor to set all properties of the object, making a copy or clone if needed

object.clone()

  • Cloneable not implemented
    • An exception is thrown
  • Cloneable implemented
    • When clone() is not overridden
      • A shallow copy is returned
    • When clone() is overridden
      • Behavior depends on implementation

Injection and Input Validation

Properly using bind variables in PreparedStatements prevents injection. Statements or improper use of PreparedStatements are vulnerable to SQL injecting, changing their behavior.

Similarly, we can check inputs from users to be what we expect. We hardcode a check on the input or use a whitelist or blacklist for allowed/disallowed inputs.

Confidential Information

In Output

Avoid sensitive information usage in:

  • Writing to a log
  • Printing exceptions or stack traces
  • System.out and System.err messages
  • Writing to data files

In Memory

In case of a crash the program might create a memory dump file. We do not want sensitive information to stay in memory.

Console.readPassword() uses char[]:

  • Compared to a char[], a String can exist in the string pool for a very long time
  • We can assign null to the value of the array
char[] password = Console.readPassword();
Arrays.fill(password, 'x');
LocalDate dateOfBirth = getDateOfBirth();
// Use date of birth
dateOfBirth = null;

Limiting File Access

We can implement security policies to limit the access to files.

Example:

grant {
    permission java.io.FilePermission
    "C:\\Water\\Fish.txt",
    "read, write";
};

Serializing & Deserializing

We can use transient to indicate fields that we do not want to write to disk. (Blacklist)

We can specify fields to be serialized in a private static final ObjectStreamField[]. (Whitelist)

We never decrypt passwords! Passwords usually get encrypted and stored, so password inputs can be encrypted and then compared to it.

Serialization methods:

  • writeObject()
    • Serializes optionally using PutField
  • readObject()
    • Deserializes optionally using GetField
  • writeReplace()
    • Allows replacement of objects before serialization
  • readResolve()
    • Allows replacement of objects after deserialization

Serialization methods can be annotated with @Serial to perform compile-time checks for the serialization-related members of a class.

Constructing Sensitive Objects

Practices:

  • Final methods
  • Final classes
  • Private constructors

Preventing DoS Attacks

A 'Denial of Service' attack is a cyber-attack in which the perpetrator seeks to make a machine or network resource unavailable to its intended users by temporarily or indefinitely disrupting services of a host connected to the Internet. Denial of service is typically accomplished by flooding the targeted machine or resource with superfluous requests in an attempt to overload systems and prevent some or all legitimate requests from being fulfilled.

Prevent resource leaks

Use try with resources statements when using resources.

Avoid very large resources

Methods handling very large resources make the program vulnerable to DoS attacks. Keep files small and check their size before using them.

Including potentially large resources

Any files that we didn't create are suspect. Sometimes a 'zip bomb' is used that get incrementally bigger when they are read.

Overflowing numbers

Number types have a maximum value, once exceeded they can become negative or start over from 0 depending on the type. When checking for sizes we have to be aware of this.

Wasting Data Structures

Prevent malicious use of data structures to slow down your program, like the creation of excessively large arrays or hashmaps with bad hash functions for example.

More Resources

OWASP Open Source Foundation for Application Security - List of top 10 security issues.

CSA The Cloud Security Alliance - Egregious Eleven.

Iron-Clad Java By Jim Manico & August Detlefsen