Error Handling

Libraries: slingshot (throw+/try+ with arbitrary data), failjure (monadic error handling), cognitect anomalies (a standard vocabulary of error categories: :cognitect.anomalies/not-found, /unavailable, /incorrect, ...).

;; try / catch / finally
(try
  (/ 1 0)
  (catch ArithmeticException e
    (println "Math error:" (.getMessage e))
    :div-by-zero)
  (catch Exception e
    (println "Other error" e))
  (finally
    (println "cleanup")))

;; ex-info: exceptions carrying data (the idiomatic Clojure way)
(defn withdraw [balance amount]
  (when (> amount balance)
    (throw (ex-info "Insufficient funds"
                    {:type ::insufficient-funds :balance balance :requested amount})))
  (- balance amount))

(try
  (withdraw 50 100)
  (catch clojure.lang.ExceptionInfo e
    (let [{:keys [type balance requested]} (ex-data e)]
      (println (ex-message e) "- short by" (- requested balance)))))

(ex-cause e)                       ; the wrapped cause
(Throwable->map e)                 ; data view of an exception (with :via, :trace, :cause)

;; with-open: resource management (calls .close)
(with-open [rdr (clojure.java.io/reader "data.txt")]
  (count (line-seq rdr)))

;; Returning errors as data (an alternative to exceptions)
(defn parse-age [s]
  (if-let [n (parse-long s)]
    (if (<= 0 n 150) {:ok n} {:error :out-of-range :value n})
    {:error :not-a-number :value s}))
(parse-age "42")             
…