yazz.com
yazz.com

Reputation: 58786

How can I throw an exception in Clojure?

I wish to throw an exception and have the following:

(throw "Some text")

However it seems to be ignored.

Upvotes: 50

Views: 24323

Answers (3)

dskrvk
dskrvk

Reputation: 1378

If you want to throw an exception and include some debugging info in it (in addition to a message string), you can use the built-in ex-info function.

To extract the data from the previously-constructed ex-info object, use ex-data.

Example from clojuredocs:

(try
  (throw 
    (ex-info "The ice cream has melted!" 
       {:causes             #{:fridge-door-open :dangerously-high-temperature} 
        :current-temperature {:value 25 :unit :celcius}}))
  (catch Exception e (ex-data e))

In a comment kolen mentioned slingshot, which provides advanced functionality that allows you not only to throw objects of arbitrary type (with throw+), but also use a more flexible catch syntax to inspect data inside thrown objects (with try+). Examples from the project repo:

tensor/parse.clj

(ns tensor.parse
  (:use [slingshot.slingshot :only [throw+]]))

(defn parse-tree [tree hint]
  (if (bad-tree? tree)
    (throw+ {:type ::bad-tree :tree tree :hint hint})
    (parse-good-tree tree hint)))

math/expression.clj

(ns math.expression
  (:require [tensor.parse]
            [clojure.tools.logging :as log])
  (:use [slingshot.slingshot :only [throw+ try+]]))

(defn read-file [file]
  (try+
    [...]
    (tensor.parse/parse-tree tree)
    [...]
    (catch [:type :tensor.parse/bad-tree] {:keys [tree hint]}
      (log/error "failed to parse tensor" tree "with hint" hint)
      (throw+))
    (catch Object _
      (log/error (:throwable &throw-context) "unexpected error")
      (throw+))))

Upvotes: 11

edoloughlin
edoloughlin

Reputation: 5901

clojure.contrib.condition provides a Clojure-friendly means of handling exceptions. You can raise conditons with causes. Each condition can have its own handler.

There are a number of examples in the source on github.

It's quite flexible, in that you can provide your own key, value pairs when raising and then decide what to do in your handler based on the keys/values.

E.g. (mangling the example code):

(if (something-wrong x)
  (raise :type :something-is-wrong :arg 'x :value x))

You can then have a handler for :something-is-wrong:

(handler-case :type
  (do-non-error-condition-stuff)
  (handle :something-is-wrong
    (print-stack-trace *condition*)))

Upvotes: 10

dbyrne
dbyrne

Reputation: 61011

You need to wrap your string in a Throwable:

(throw (Throwable. "Some text"))

or

(throw (Exception. "Some text"))

You can set up a try/catch/finally block as well:

(defn myDivision [x y]
  (try
    (/ x y)
    (catch ArithmeticException e
      (println "Exception message: " (.getMessage e)))
    (finally 
      (println "Done."))))

REPL session:

user=> (myDivision 4 2)
Done.
2
user=> (myDivision 4 0)
Exception message:  Divide by zero
Done.
nil

Upvotes: 82

Related Questions