Programming cljr-working with Java

Source: Internet
Author: User
Tags finally block
Document directory
  • Calling Java
  • Optimizing for performance
  • Exception Handling
Working with Java

In this chapter, you will see how clojure access to Java is convenient, elegant, and fast:
• Calling Java isSimple and Direct.
Clojure provides syntax extensions for accessing anything you cocould reach from Java code: classes, instances, constructors, methods, and fields.
Although you will typically call Java code directly, you can also wrap Java APIs and use them in a more functional style.

• Clojure isFast, Unlike extends other dynamic versions on the JVM.
You can use M support for primitives and arrays, plus type hints, to cause clojure's compiler to generate the same code that a Java compiler wowould generate.

• Java code can call clojure code, too. clojure can generate Java classes on the fly. on a one-off basis, you can use proxy, or you can generate and save classes with gen-and-save-class.

 

• Clojure's exception handling is easy to use. Better yet, explicit exception handling is rarely necessary.
Clojure's exception primitives are the same as Java's. However, clojure does not require you to deal with checked exceptions and makes it easy to clean up resources using the with-open idiom.

 

Calling javaaccessing constructors, methods, and fields

Creating a Java object

(new java.util.Random)java.util.Random@4f1ada
 
(def rnd (new java.util.Random))
 
(. rnd nextInt)
-791474443

Import package

(import '(java.util Random Locale)        '(java.text MessageFormat))

 

.. Macro

The .. macro is great if the result of each operation is an input to the next.

(.getLocation (.getCodeSource (.getProtectionDomain (.getClass '(1 2)))))
 
(.. '(1 2) getclass getprotectiondomain getcodesource getlocation); Use the .. macro version for clarity? Write less parentheses?

Doto

Sometimes you don't care about the results of method CILS and simply wantMake several callon the same object.

The doto macro makes it easy to make several callon the same object:

(doto class-or-inst & member-access-forms)

As"Do" in doto suggests, You can use dotoCause side effectsIn the mutable Java World. For example, use doto to set multiple system properties:

(doto (System/getProperties)  (.setProperty "name" "Stuart")  (.setProperty "favoriteColor" "blue"))

 

The following table lists the syntax sugar of basic syntax and response,

 

Using Java collections

Clojure's collections supplant the Java collections for most purposes.

Clojure's collections are concurrency-safe, have good performance characteristics, and implement the appropriate Java Collection interfaces.

So, you shoshould generally prefer clojure's own collections when you are working in clojure and even pass them back into Java when convenient.

It is unclear why Java Collection should be used in clojure...

 

Convenience Functions

Memfn macro

Try passing. touppercase to map in order to upcase a vector of strings:

(map .toUpperCase ["a" "short" "message"])java.lang.Exception:\Unable to resolve symbol: .toUpperCase in this context

Only clojure function can be used as a parameter. For Java method, memfn should be used for encapsulation.

The problem is that touppercase () is a Java method, not a clojure function.

This member-as-function idiom is a common one, so clojure provides the "member function" memfn macro to wrap methods for you:

(map (memfn toUpperCase) ["a" "short" "message"])("A" "SHORT" "MESSAGE")

As a preferred alternative to memfn, you can use an anonymous function to wrap a method call:

(map #(.toUpperCase %) ["a" "short" "message"])("A" "SHORT" "MESSAGE")

Instance?

Checking whether an object is an instance of a certain class. clojure provides the instance? Function for this purpose:

(instance? Integer 10)true(instance? Comparable 10)true(instance? String 10)false

String format

Java provides a string format method. because the message signature for Java's format is slightly inconvenient to call in clojure and because string formatting is so common, clojure provides a wrapper: (format FMT-string & ARGs)

You use format like this:

(format "%s ran %d miles today" "Stu" 8)"Stu ran 8 miles today"

 

Optimizing for performanceusing primitives for performance

In the preceding sections,Function parameters carry no type information.

Clojure simply does the right thing. Depending on your perspective, this is either a strength or a weakness.

It's a strength, because your code is clean and simple and can take advantage of duck typing.

But it's also a weakness, because a reader of the Code cannot be certain of data types and because doing the right thing carries some performance overhead.

Clojure parameters do not contain type information. Of course they are relatively simple and clear. Naturally, the compiler needs to do more things. Therefore, if efficiency is high, you can specify the type.

 

For example, for the following example, Sum

(defn sum-to [n]  (loop [i 1 sum 0]    (if (<= i n)      (recur (inc i) (+ i sum))      sum)))

For a time test without a specified parameter type version,

(dotimes [_ 5] (time (sum-to 10000))) ;dotimes will execute its body repeatedly, here 5 times"Elapsed time: 0.778 msecs""Elapsed time: 0.559 msecs""Elapsed time: 0.633 msecs""Elapsed time: 0.548 msecs""Elapsed time: 0.647 msecs"

To speed things up, you can ask clojure to treat N, I, and sum as ints:

(Defn integer-sum-to [N]

(Let [n (INT n)]

(Loop [I (INT 1) sum (INT 0)]

(If (<= I n)

(Recur (inc I) (+ I sum ))

Sum ))))

It can be seen that, after specifying a type, the efficiency is improved a lot,

(dotimes [_ 5] (time (integer-sum-to 10000)))"Elapsed time: 0.207 msecs""Elapsed time: 0.073 msecs""Elapsed time: 0.072 msecs""Elapsed time: 0.071 msecs""Elapsed time: 0.071 msecs"

Clojure's convenient math operators (+,-, and so on) Make sure their results do not overflow.

Maybe you can get an even faster function by using the unchecked version of +, unchecked-add:

You can also improve efficiency when you do not check whether an overflow operation is performed. However, this optimization cannot be used unless necessary because it is difficult to maintain. Once overflow causes data errors, it is difficult to troubleshoot.

(defn unchecked-sum-to [n]  (let [n (int n)]    (loop [i (int 1) sum (int 0)]      (if (<= i n)(recur (inc i) (unchecked-add i sum))sum))))

 

Adding type hints

Clojure supports adding type hints to function parameters, let bindings, variable names, and expressions. These type hints serve three purposes:

• Optimizing critical performance paths

• Documenting the required type

• Enforcing the required type at runtime

(defn wants-a-string [#^String s] (println s))
# ^ String S is equal to # ^ {: Tag string} s. Because tags are too common, the default tag is not written.

 

Creating and compiling Java classes in clojure

Often, clojure's Java API will not be sufficient for Integrating JAVA code with clojure code.

Extends Java libraries require you to implement a special interface or extend a special base class.

Fortunately, clojure can create real Java classes, with methods that can be called like any other Java method, without requiring you to write any "wrapper" code in Java.

For calling Java libraries, sometimes interface or class needs to be passed in. In a simple example, the sax library of Parse XML must be passed in a class or interface that implements handles, therefore, Java classes must be directly generated in clojure.

Skip and then add

To use a SAX Parser, You need to implement a callback mechanic.

The easiest way is often to extend the defaulthandler class. In clojure, you can extend a class withProxyFunction:

(proxy class-and-interfaces super-cons-args & fns)

(DEF print-element-handler (proxy [defaulthandler] [] (startelement; For the handle function of startelement [URI local qname atts] (println (Format "saw element: % s "QNAME )))))

 

Exception Handling

In Java code, exception handling crops up for three reasons:

• Wrapping checked exceptions (checked exceptions, http://blog.sina.com.cn/s/blog_492c74050100031s.html)

Checked exceptions

Java's checked exceptions mustBe explicitly caught or rethrownFrom every method where they can occur.

This seemed like a good idea at first: checked exceptions cocould use the type system to rigorously document error handling, with compiler enforcement. most Java programmers now consider checked exceptions a failed experiment, because their costs in code bloat and maintainability outweigh their advantages. for more on the history of checked exceptions, see http://tinyurl.com/checked-exceptions-mistake


• Using a Finally block to clean up nonmemory resources such as file and network handles

• Responding to the problem: ignoring the exception, retrying the operation, converting the exception to a nonexceptional result, and so on

In Java, why is Exception Handling required,

First, for checked exceptions, you must handle, catch, or rethrown

Second, you need to release resources in the Finally block, such as files and networks.

Finally, if you do not want the program to simply stop because of the exception, you need to perform restoration and ignore operations. For example, when a webpage is crawled and an exception occurs, you need to repeat it several times or continue crawling.


In clojure, things are similarSimpler. The try and throw special forms give you all the capabilities of Java's try, catch, finally, and throw.

But you shoshould not have to use them very often, because of the following reasons:

• You do not have to deal with checked exceptions in clojure.It seems that only Java has checked exceptions.

• You can use macros suchWith-openTo encapsulate resource cleanup.

To put it bluntly, the first two methods do not need to be processed or simply in clojure, and only the third method cannot be avoided...

 

Keeping Exception Handling simple

The absence of exception wrappers makes idiomatic clojure code easier to read, write, and maintain than idiomatic Java. that said, nothing prevents you from explicitly catching, wrapping, and rethrowing exceptions in clojure. it simply is not required. you shoshouldCatch exceptions when you plan to respond to them in a meaningful way.

 

Cleaning up resources, for outside of garbage-collected memory

Garbage collection will clean up resources in memory. if you use resources that live outside of garbage-collected memory, such as file handles, you need to make sure that you clean them up, even in the event of an exception. in Java, this is normally handled in a Finally block.

If the resource you need to free follows the Convention of having a close method, you can use clojure's with-open macro:

(with-open [name init-form] & body)

Clojure uses with-open for good encapsulation. You no longer have to write finally blocks on your own...

The following example shows how to use open file in Split to ensure that the file will be closed with-open, which is very simple.

(use '[clojure.contrib.duck-streams :only (spit)])(spit "hello.out" "hello, world"); from clojure-contrib(defn spit [f content]  (with-open [#^PrintWriter w (writer f)]  (.print w content)))

 

Of course, you are not satisfied with the default finally logic. You can implement it by yourself.

If you need to do something other than close in a Finally block, the clojure try form looks like this:

(try expr* catch-clause* finally-clause?); catch-clause -> (catch classname name expr*); finally-clause -> (finally expr*)
 
(try (throw (Exception. "something failed")) (finally  (println "we get to clean up")))

 

Responding to an exception

The most interesting case is when an exception handler attempts to respond to the problem in a Catch Block.

As a simple example, consider writing a function to test whether a particle class is available at runtime:

For example, is the test class ready in the current environment?

; not caller-friendly(defn class-available? [class-name]  (Class/forName class-name))

This approach is not very caller-friendly. The caller simply wants a yes/no answer but instead gets an exception:

(class-available? "borg.util.Assimilate")java.lang.ClassNotFoundException: borg.util.Assimilate

The problem is that it is not very friendly and can directly throw exceptions, making it awkward to use, so you can encapsulate it and provide yes/no

; better-class-available(defn class-available? [class-name]  (try    (Class/forName class-name) true   (catch ClassNotFoundException _ false))) 
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.