Skip to content

Java ​

Collections ​

How to choose from Collection types:

mermaid
flowchart TD
    START(["Which Java Collection should I use?"]) --> IMMUT{"Are the contents fixed at creation,<br/>so nothing is ever added or removed?"}

    IMMUT -->|Yes| IMM_KV{"Does each entry map<br/>a key to a value?"}
    IMM_KV -->|Yes| R_MAPOF[["Map.of()"]]
    IMM_KV -->|No| IMM_UNIQ{"Must duplicate elements<br/>be rejected?"}
    IMM_UNIQ -->|Yes| R_SETOF[["Set.of()"]]
    IMM_UNIQ -->|No| R_LISTOF[["List.of()"]]

    IMMUT -->|No| KV{"Does each entry map<br/>a key to a value?"}
    KV -->|Yes| MAP_MT{"Will more than one thread touch it<br/>while it is being mutated?"}
    KV -->|No| UNIQ{"Must duplicate elements<br/>be rejected?"}
    UNIQ -->|Yes| SET_MT{"Will more than one thread touch it<br/>while it is being mutated?"}
    UNIQ -->|No| PROC{"Will elements be consumed in a processing order —<br/>FIFO, LIFO or priority — rather than read by index?"}
    PROC -->|Yes| Q_MT{"Will more than one thread touch it<br/>while it is being mutated?"}
    PROC -->|No| LIST_MT{"Will more than one thread touch it<br/>while it is being mutated?"}

    %% ---------------- MAPS ----------------
    MAP_MT -->|Yes| MAP_SORT_MT{"Must the keys stay sorted, or do you<br/>need range queries over them?"}
    MAP_SORT_MT -->|Yes| R_CSLM[["ConcurrentSkipListMap"]]
    MAP_SORT_MT -->|No| R_CHM[["ConcurrentHashMap"]]

    MAP_MT -->|No| MAP_SORT{"Must the keys stay sorted, or do you<br/>need range queries over them?"}
    MAP_SORT -->|Yes| R_TREEMAP[["TreeMap"]]
    MAP_SORT -->|No| MAP_ORD{"Must iteration follow insertion order,<br/>or access order for an LRU cache?"}
    MAP_ORD -->|Yes| R_LHM[["LinkedHashMap"]]
    MAP_ORD -->|No| MAP_ENUM{"Are all the keys constants<br/>of a single enum?"}
    MAP_ENUM -->|Yes| R_ENUMMAP[["EnumMap"]]
    MAP_ENUM -->|No| MAP_WEAK{"Should an entry disappear<br/>once its key is unreachable?"}
    MAP_WEAK -->|Yes| R_WHM[["WeakHashMap"]]
    MAP_WEAK -->|No| MAP_ID{"Must keys be matched by reference,<br/>ignoring equals?"}
    MAP_ID -->|Yes| R_IHM[["IdentityHashMap"]]
    MAP_ID -->|No| R_HM[["HashMap"]]

    %% ---------------- SETS ----------------
    SET_MT -->|Yes| SET_SORT_MT{"Must the elements stay sorted, or do you<br/>need range queries over them?"}
    SET_SORT_MT -->|Yes| R_CSLS[["ConcurrentSkipListSet"]]
    SET_SORT_MT -->|No| SET_COW{"Is the set small, with reads and iteration<br/>vastly outnumbering writes?"}
    SET_COW -->|Yes| R_COWAS[["CopyOnWriteArraySet"]]
    SET_COW -->|No| R_CHMKS[["ConcurrentHashMap.newKeySet()"]]

    SET_MT -->|No| SET_SORT{"Must the elements stay sorted, or do you<br/>need range queries over them?"}
    SET_SORT -->|Yes| R_TS[["TreeSet"]]
    SET_SORT -->|No| SET_ORD{"Must iteration follow<br/>insertion order?"}
    SET_ORD -->|Yes| R_LHS[["LinkedHashSet"]]
    SET_ORD -->|No| SET_ENUM{"Are all the elements constants<br/>of a single enum?"}
    SET_ENUM -->|Yes| R_ES[["EnumSet"]]
    SET_ENUM -->|No| R_HS[["HashSet"]]

    %% ---------------- LISTS ----------------
    LIST_MT -->|Yes| LIST_COW{"Do reads and iteration vastly outnumber writes,<br/>and does the list stay small?"}
    LIST_COW -->|Yes| R_COWAL[["CopyOnWriteArrayList"]]
    LIST_COW -->|No| R_SYNCL[["Collections.synchronizedList()"]]

    LIST_MT -->|No| LIST_MID{"Will you insert or remove often<br/>at the head or in the middle?"}
    LIST_MID -->|Yes| LIST_IDX{"Do you also need to index into it<br/>at an arbitrary position?"}
    LIST_IDX -->|Yes| R_AL[["ArrayList"]]
    LIST_IDX -->|No| R_LL[["LinkedList"]]
    LIST_MID -->|No| R_AL

    %% ---------------- QUEUES ----------------
    Q_MT -->|Yes| Q_BLOCK{"Should a consumer wait<br/>when nothing is available?"}
    Q_BLOCK -->|Yes| Q_PRIO_MT{"Should priority decide the order<br/>instead of arrival?"}
    Q_PRIO_MT -->|Yes| R_PBQ[["PriorityBlockingQueue"]]
    Q_PRIO_MT -->|No| Q_DELAY{"Does an element become eligible<br/>only after a delay?"}
    Q_DELAY -->|Yes| R_DQ[["DelayQueue"]]
    Q_DELAY -->|No| Q_HAND{"Is it a direct handoff,<br/>with no buffering at all?"}
    Q_HAND -->|Yes| R_SQ[["SynchronousQueue"]]
    Q_HAND -->|No| Q_BOUND{"Should the capacity be bounded,<br/>so producers feel backpressure?"}
    Q_BOUND -->|Yes| R_ABQ[["ArrayBlockingQueue"]]
    Q_BOUND -->|No| Q_ENDS_B{"Do you need to insert and take<br/>at both ends?"}
    Q_ENDS_B -->|Yes| R_LBD[["LinkedBlockingDeque"]]
    Q_ENDS_B -->|No| R_LBQ[["LinkedBlockingQueue"]]

    Q_BLOCK -->|No| Q_ENDS_NB{"Do you need to insert and take<br/>at both ends?"}
    Q_ENDS_NB -->|Yes| R_CLD[["ConcurrentLinkedDeque"]]
    Q_ENDS_NB -->|No| R_CLQ[["ConcurrentLinkedQueue"]]

    Q_MT -->|No| Q_PRIO{"Should priority decide the order<br/>instead of arrival?"}
    Q_PRIO -->|Yes| R_PQ[["PriorityQueue"]]
    Q_PRIO -->|No| R_AD[["ArrayDeque"]]

    classDef dec fill:#e9eef3,stroke:#64798c,stroke-width:1px,color:#16202b;
    classDef plain fill:#d9e8f8,stroke:#1d5fa8,stroke-width:1.4px,color:#0d2d4f;
    classDef conc fill:#fbeacf,stroke:#b06a12,stroke-width:1.4px,color:#4a2c05;
    classDef imm fill:#d9ecdf,stroke:#1d7a45,stroke-width:1.4px,color:#0e3a20;

    class IMMUT,IMM_KV,IMM_UNIQ,KV,UNIQ,PROC,MAP_MT,MAP_SORT_MT,MAP_SORT,MAP_ORD,MAP_ENUM,MAP_WEAK,MAP_ID,SET_MT,SET_SORT_MT,SET_COW,SET_SORT,SET_ORD,SET_ENUM,LIST_MT,LIST_COW,LIST_MID,LIST_IDX,Q_MT,Q_BLOCK,Q_PRIO_MT,Q_DELAY,Q_HAND,Q_BOUND,Q_ENDS_B,Q_ENDS_NB,Q_PRIO dec;
    class R_MAPOF,R_SETOF,R_LISTOF imm;
    class R_TREEMAP,R_LHM,R_ENUMMAP,R_WHM,R_IHM,R_HM,R_TS,R_LHS,R_ES,R_HS,R_LL,R_AL,R_PQ,R_AD,R_SYNCL plain;
    class R_CSLM,R_CHM,R_CSLS,R_COWAS,R_CHMKS,R_COWAL,R_PBQ,R_DQ,R_SQ,R_ABQ,R_LBD,R_LBQ,R_CLD,R_CLQ conc;

Exceptions ​

How to choose from Throwable types:

mermaid
flowchart TD
    START(["Which Java exception should I throw?"]) --> JVM{"Is the JVM itself broken or exhausted —<br/>memory, stack depth, class loading?"}

    JVM -->|Yes| R_ERROR[["Throw nothing — let the Error propagate"]]
    JVM -->|No| WRAP{"Are you catching a low-level failure and<br/>passing it across an API boundary?"}

    WRAP -->|Yes| WRAP_ADD{"Must the caller tell this apart from<br/>every other failure of the same call?"}
    WRAP_ADD -->|Yes| R_CUSTOM_W[["Custom exception, original passed as the cause"]]
    WRAP_ADD -->|No| R_RTE_W[["UncheckedIOException / RuntimeException, with the cause"]]

    WRAP -->|No| BUG{"Is the condition a bug in the calling code —<br/>a broken contract rather than a circumstance?"}
    BUG -->|Yes| ARG{"Is the problem with an argument<br/>the caller passed in?"}
    BUG -->|No| CHECK{"Could the caller do something useful about it —<br/>retry, fall back, ask the user — instead of just failing?"}

    %% ---------------- PROGRAMMING ERRORS ----------------
    ARG -->|Yes| ARG_NULL{"Is it null where<br/>null is not allowed?"}
    ARG_NULL -->|Yes| R_NPE[["NullPointerException — Objects.requireNonNull()"]]
    ARG_NULL -->|No| ARG_IDX{"Is it an index or range<br/>outside the bounds?"}
    ARG_IDX -->|Yes| R_IOOBE[["IndexOutOfBoundsException"]]
    ARG_IDX -->|No| ARG_TYPE{"Is it an object of the<br/>wrong runtime type?"}
    ARG_TYPE -->|Yes| R_CCE[["ClassCastException"]]
    ARG_TYPE -->|No| ARG_NUM{"Is it text that should<br/>have been a number?"}
    ARG_NUM -->|Yes| R_NFE[["NumberFormatException"]]
    ARG_NUM -->|No| R_IAE[["IllegalArgumentException"]]

    ARG -->|No| OP{"Is the operation one this implementation<br/>will never support at all?"}
    OP -->|Yes| R_UOE[["UnsupportedOperationException"]]
    OP -->|No| STATE{"Are the arguments fine, but the receiver<br/>in the wrong state for this call?"}
    STATE -->|Yes| STATE_CME{"Was a collection structurally modified<br/>while it was being iterated?"}
    STATE_CME -->|Yes| R_CME[["ConcurrentModificationException"]]
    STATE_CME -->|No| STATE_MON{"Was wait / notify called without<br/>holding the object's monitor?"}
    STATE_MON -->|Yes| R_IMSE[["IllegalMonitorStateException"]]
    STATE_MON -->|No| R_ISE[["IllegalStateException"]]

    STATE -->|No| ARITH{"Is it an arithmetic impossibility —<br/>division by zero, overflow you checked for?"}
    ARITH -->|Yes| R_ARITH[["ArithmeticException"]]
    ARITH -->|No| R_AE[["AssertionError — a branch that cannot be reached"]]

    %% ---------------- RECOVERABLE CONDITIONS ----------------
    CHECK -->|No| U_IO{"Is it an I/O failure raised where no checked<br/>exception can be declared — a lambda in a stream?"}
    CHECK -->|Yes| IO{"Does it come from I/O — a file,<br/>socket, stream or database?"}

    IO -->|Yes| IO_DB{"Is it a database<br/>or JDBC call?"}
    IO_DB -->|Yes| R_SQLE[["SQLException"]]
    IO_DB -->|No| IO_SUB{"Must the caller tell it apart<br/>from other I/O failures?"}
    IO_SUB -->|Yes| R_IOSUB[["An IOException subclass — FileNotFoundException, …"]]
    IO_SUB -->|No| R_IOE[["IOException"]]

    IO -->|No| INT{"Is a blocking call<br/>being interrupted?"}
    INT -->|Yes| R_IE[["InterruptedException — or restore the interrupt flag"]]
    INT -->|No| PARSE{"Is external text failing to parse<br/>into the expected shape?"}
    PARSE -->|Yes| R_PARSE[["ParseException"]]
    PARSE -->|No| DOMAIN{"Does the caller need data about the failure<br/>that no standard type carries?"}
    DOMAIN -->|Yes| R_CUSTOM[["Custom exception extending Exception"]]
    DOMAIN -->|No| R_STD[["The closest standard checked exception"]]

    %% ---------------- UNCHECKED CONDITIONS ----------------
    U_IO -->|Yes| R_UIOE[["UncheckedIOException"]]
    U_IO -->|No| U_EMPTY{"Is there simply nothing to hand back —<br/>an exhausted iterator or an empty Optional?"}
    U_EMPTY -->|Yes| R_NSEE[["NoSuchElementException"]]
    U_EMPTY -->|No| U_TIME{"Is a date or time value invalid,<br/>or does it fail to parse?"}
    U_TIME -->|Yes| R_DTE[["DateTimeParseException / DateTimeException"]]
    U_TIME -->|No| U_EXEC{"Was work handed to an executor that is<br/>shut down or over capacity?"}
    U_EXEC -->|Yes| R_REE[["RejectedExecutionException"]]
    U_EXEC -->|No| U_ASYNC{"Did an asynchronous task fail<br/>or get cancelled?"}
    U_ASYNC -->|Yes| R_CFE[["CompletionException / CancellationException"]]
    U_ASYNC -->|No| U_DOMAIN{"Does the caller need data about the failure<br/>that no standard type carries?"}
    U_DOMAIN -->|Yes| R_CUSTOM_U[["Custom exception extending RuntimeException"]]
    U_DOMAIN -->|No| R_RTE[["RuntimeException"]]

    classDef dec fill:#e9eef3,stroke:#64798c,stroke-width:1px,color:#16202b;
    classDef unchk fill:#d9e8f8,stroke:#1d5fa8,stroke-width:1.4px,color:#0d2d4f;
    classDef chk fill:#fbeacf,stroke:#b06a12,stroke-width:1.4px,color:#4a2c05;
    classDef cust fill:#d9ecdf,stroke:#1d7a45,stroke-width:1.4px,color:#0e3a20;
    classDef err fill:#f6dcdc,stroke:#a8323b,stroke-width:1.4px,color:#4a0f14;

    class JVM,WRAP,WRAP_ADD,BUG,ARG,ARG_NULL,ARG_IDX,ARG_TYPE,ARG_NUM,OP,STATE,STATE_CME,STATE_MON,ARITH,CHECK,IO,IO_DB,IO_SUB,INT,PARSE,DOMAIN,U_IO,U_EMPTY,U_TIME,U_EXEC,U_ASYNC,U_DOMAIN dec;
    class R_RTE_W,R_NPE,R_IOOBE,R_CCE,R_NFE,R_IAE,R_UOE,R_CME,R_IMSE,R_ISE,R_ARITH,R_UIOE,R_NSEE,R_DTE,R_REE,R_CFE,R_RTE unchk;
    class R_SQLE,R_IOSUB,R_IOE,R_IE,R_PARSE,R_STD chk;
    class R_CUSTOM_W,R_CUSTOM,R_CUSTOM_U cust;
    class R_ERROR,R_AE err;