iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 21
0
Software Development

擁抱 Clojure系列 第 21

[第 21 天] 擁抱 Clojure:與 Java 共舞(三)

與 Java 共舞(三)

從 Clojure 呼叫 Java

有用的工具函式

doto

doto 巨集將第一個參數傳遞給其後運算式當作第一個參數。它將以下層疊的運算式:

(let [array (java.util.ArrayList.)]
  (.add array 11)
  (.add array 3)
  (.add array 7)
  array)
;; => [11 3 7]

轉換成:

(doto (java.util.ArrayList.)
  (.add 11)
  (.add 3)
  (.add 7))
;; => [11 3 7]

使用 doto 簡化了許多繁瑣的步驟。

memfn

因爲 Java 類型的方法無法在 Clojure 當作一級函式,所以與 map 等函式配合時,需要多一層匿名函式包裝:

(map #(.length %) ["Happy" "New" "Year"])
;; => (5 3 4)

使用 memfn 可以將執行個體的方法轉換成 Clojure 中的函式,與高階函式搭配使用:

(map (memfn length) ["Happy" "New" "Year"])
;; => (5 3 4)

處理例外

例外是程式運行中發生非預期的問題時,產生出來的類型。根據產生的例外,做適當的處理或善後,是健壯穩定的程式必要的條件。Clojure 使用在 Java 中處理例外的關鍵字 trycatchfinally,作爲例外處理的建構單元:

(defn divide-by [denom]
  (try
    (/ 1 denom)
    (catch ArithmeticException e
      (.printStackTrace e))
    (finally
      (println "Divided by" denom))))

以上範例在 try 運算式內計算以 1 除以參數,如果發生 ArithmeticException 例外(除以 0),則會印出該例外的除錯堆疊資訊,finally 則是不論 try 運算式是否產生例外,都會進入 finally 運算式內運行。

Clojure 程式發生不可預期的錯誤時,可以使用 throw 來拋出例外:

(throw (IllegalStateException. "Illegal state exeption"))
;; => IllegalStateException Illegal state exeption

值得注意的是,使用 throw 丟出的例外類型,必須是 java.lang.Throwable 或是它的子類別。

從 Java 呼叫 Clojure

大多數時間都是從 Clojure 端呼叫 Java,也會有要從 Java 端呼叫 Clojure 的時候。使用時首先引入 clojure.java.api.Clojure 類別,它提供了找尋 Var 物件、解析程式與存取命名空間的方法。

找到欲存取的 Var 物件後,以其實作的 IFn 介面進行調用,即可呼叫該 Var 物件代表的函式:

import clojure.java.api.Clojure;
import clojure.lang.IFn;
IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);

或是引入 Clojure 的命名空間

IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));

或者是引入 Clojure 的高階函式來使用:

IFn map = Clojure.var("clojure.core", "map");
IFn inc = Clojure.var("clojure.core", "inc");
map.invoke(inc, Clojure.read("[1 2 3]"));

回顧

從本篇文章中你了解到如何載入 Java 套件與類別,知道了讀取類別成員的方法,還有可以用來建立匿名與具名型別的巨集。還了解到如何將 Clojure 序列轉換成 Java 陣列的方式,以及例外處理的各個建構子。除此之外,還學會了如何由 Java 調用 Clojure 函式與資料的方式。

還不賴吧?今天就先到這裡,下一篇文章再見囉!

(本篇文章同步刊登於 GitHub,歡迎在文章下方留言或發送 PR 給予建議與指教)


上一篇
[第 20 天] 擁抱 Clojure:與 Java 共舞(二)
下一篇
[第 22 天] 擁抱 Clojure:讀取器與詮釋資料(一)
系列文
擁抱 Clojure30

尚未有邦友留言

立即登入留言