Imports

CS2030java.util
BooleanCondition<T>::testfunction.Predicate<T>::test
Producer<T>::producefunction.Supplier<T>::get
Consumer<T>::consumefunction.Consumer<T>::accept
Transformer<T, R>::transformfunction.Function<T, R>::apply
Transformer<T, T>::transformfunction.UnaryOp<T>::apply
Combiner<S, T, R>::combinefunction.BiFunction<S, T, R>::apply
Maybe<T>Optional<T>

java.util.Optional<T>

has empty, of, ofNullable, get, orElseGet etc.

java.util.stream.Stream<T>

  • count: Long count()
  • generate: Stream<T> generate(Supplier<? extends T> s)
  • iterate: Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
  • iterate: Stream<T> iterate(T seed, UnaryOperator<T> f)
  • limit: Stream<T> limit(long maxSize)
  • of: Stream<T> of(T t) (single element stream)
  • of: Stream<T> of(T... values)
  • distinct: Stream<T> distinct()
  • peek: Stream<T> peek(Consumer<? super T> action)
  • allMatch: boolean allMatch(Predicate<? super T> predicate)
  • anyMatch: boolean anyMatch(Predicate<? super T> predicate)
  • noneMatch: boolean noneMatch(Predicate<? super T> predicate)
  • map: <R> Stream<R> map(Function<? super T,? extends R> mapper)
  • flatMap: <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
  • filter: Stream<T> filter(Predicate<? super T> predicate)
  • reduce: Optional<T> reduce(BinaryOperator<T> accumulator)
    • If one element, it is returned directly. If 0 element, empty returned
  • reduce: T reduce(T identity, BinaryOperator<T> accumulator)
  • reduce: <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
  • skip: Stream<T> skip(long n)
  • sorted: Stream<T> sorted(Comparator<? super T> comparator)
  • toArray: Object[] toArray() (probably dont use?)
  • toList: List<T> toList() (probably dont use?)
  • Creating stream
    • Any java.util.Collection (List, Set, Queue etc.) have .stream()
    • import java.util.Arrays → Arrays.stream(arr)
    • Stream.of(indiv items or array)
    • Stream.generate() and Stream.iterate()

java.util.Map<K, V>

  • containsKey: boolean containsKey​(Object key)
  • containsValue: boolean containsValue(Object key)
  • values: Collection<V> values()
  • keySet: Set<K> keySet()
  • put: V put​(K key, V value) (overwrites if exists)
  • get: V get​(Object key) (returns null if not exists)
  • remove: V remove​(Object key)
  • remove: boolean remove​(Object key, Object value) (removes if mapping exists)
  • replace: V replace​(K key, V value)
  • replace: boolean replace​(K key, V oldValue, V newValue) (replace if mapping exists)
  • size: int size()
  • isEmpty: boolean isEmpty()

String.valueOf()?

  • same as calling Object.toString(), unless null, in which case it returns "null"

java.util.concurrent.CompletableFuture

Creating

  • CompletableFuture.supplyAsync(Supplier<U> supplier): Run a task asynchronously and return its result.
  • CompletableFuture.runAsync(Runnable runnable): Run a task asynchronously without a result.
  • CompletableFuture.completedFuture(T value): Create a CompletableFuture that’s already successfully completed.

Chaining

  • thenApply(Function<? super T,? extends U> fn): Apply a function to the result of the previous stage (synchronously).
  • thenApplyAsync(Function<? super T,? extends U> fn): Apply a function to the result of the previous stage (asynchronously).
  • thenAccept(Consumer<? super T> action): Consume the result of the previous stage (synchronously).
  • thenAcceptAsync(Consumer<? super T> action): Consume the result of the previous stage (asynchronously).
  • thenCompose(Function<? super T, ? extends CompletionStage<U>> fn): Chain asynchronous operations where the next depends on the previous result.

Getting Result

  • get(): Wait for the result (can throw exceptions).
  • join(): Wait for the result (throws CompletionException on error).
  • getNow(T valueIfAbsent): Get the result if available, otherwise return a default value.

Exceptions

  • exceptionally(Function<Throwable,? extends T> fn): Provide a fallback value if an exception occurs.
  • handle(BiFunction<? super T, Throwable,? extends U> fn): Handle both successful results and exceptions.
  • whenComplete(BiConsumer<? super T, ? super Throwable> action): Perform an action after completion, regardless of success or failure.

Generic Arrays

new Pair<String, Integer>[2]; // error
class Abc<S, T> {
	private S[] arr; // ok
	// ...
	new Pair<S, T>[2]; // error
	this.arr = new S[2]; // error
	this.arr = (S[]) new Object[2]; // ok, but produces warning
	// to suppress this warning:
	@SuppressWarnings("unchecked") // be careful of how items can be added to the array
	S[] a = (S[]) new Object[2];
	this.arr = a;
}
@SuppressWarnings("unchecked")
Queue<Passenger>[] q = (Queue<Passenger>[]) new Queue<?>[nStops];
this.queues = q; // Queue<Passenger> <: Queue<?>

Weird Types

  1. Exact Type Parameter (<T> or TypeName): Use When You Need Invariance
    • Use an exact type parameter when the code depends on knowing the precise type for both input and output operations relative to the generic type.
  2. Unbounded Wildcard (?): Use When the Type Doesn’t Matter
    • If the code works for any type and doesn’t rely on type-specific operations, ? offers maximum flexibility.
  3. Upper-Bounded Wildcard (? extends Type): Use for Covariance (Reading/Producers)
    • Use ? extends Type for input parameters representing data sources (producers) from which you will read Type instances.
  4. Lower-Bounded Wildcard (? super Type): Use for Contravariance (Writing/Consumers)
    • Use ? super Type for input parameters representing data destinations (consumers) into which you will write Type instances.
  5. Bounded Type Parameter (<T extends Type>): Use When Defining Constrained Generic Methods/Types
    • Use <T extends Bound> when declaring a generic method or type where the logic requires the type T to have the methods/properties defined by Bound, and you need to refer to T specifically in the implementation.

Monads

  • Informally, a monad design will have these functions
    • flatMap: A function that
      • Takes another function that takes in an unwrapped value, and returns a wrapped value, after applying an operation
      • Unwraps the current object, and applies the input function to it, then consolidates the results into a wrapped value
      • M<T> -> (T -> M<U>) -> M<U>
    • unit/of: A function that takes in an unwrapped value, and wraps it, without additional context
  • Formally, where Monad is a type that is a monad, and monad is an instance of the type:
    • Left identity: Monad.of(a).flatMap(x -> f(x)) == f(a)
    • Right identity: monad.flatMap(x -> Monad.of(x)) == monad
    • Associative: monad.flatMap(x -> f(x)).flatMap(x -> g(x)) == monad.flatMap(x -> f(x).flatMap(y -> g(x)))

Immutable

  • Class: final (prevents subclasses that break immutability)
  • Fields: final
  • return new instances when modification needed

Primitive types

  • byte short int long float double
  • char int

Modifiers

  • Class
    • Public: Accessible from any other class
    • Private: Only accessible from within the same class
    • Static: Can only be used in nested classes
    • Final: Class cannot be inherited from
    • Abstract: Class cannot be instantiated, has to be inherited
    • Protected: Accessible within the same package & by subclasses
    • (no modifier): Only accessible within the same package
  • Field
    • Public: Accessible from any other class
    • Private: Only accessible from within the same class
    • Static: Shared between all instances of the class
    • Final: Value cannot be changed after initialisation (can only be assigned once)
    • Protected: Accessible within the same package & by subclasses
    • (no modifier): Only accessible within the same package
  • Method
    • Public: Accessible from any other class
    • Private: Only accessible from within the same class
    • Static: Can be called without creating an instance of the class
    • Final: Cannot be overridden in subclasses
    • Abstract: Implementation not provided, subclasses have to implement it
    • Protected: Accessible within the same package & by subclasses
    • (no modifier): Only accessible within the same package

Nested Classes

  • Can access fields and methods of container class, even private ones
    • Need to access using qualified this: Container.this.x
  • A private nested class can be returned, but not directly used (Container.Nested) outside of the container class

public class field static: accessed through Class or instance non-static: accessed through instance only

nested class static & non-static: accessed through Class