Using Clojure, how do I create the following object? The object is taken from java code (From Effective Java):
NutritionFacts cocaCola =
new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();
While it's hard to argue with the concision in the other answers1, .. has somewhat fallen out of favor, replaced by the more versatile ->. Personally I prefer :
(-> (NutritionFacts$Builder. 240 8)
(.calories 100)
(.sodium 350)
(.carbohydrates 27)
(.build))
It's a couple more characters, but you gain two things:
. is right there.Most importantly, every other answer to this question has gotten the classname wrong: Java's NutritionFacts.Builder is language sugar over the real JVM class named NutritionFacts$Builder, and that class is the one Clojure must refer to (since we are not using javac to compile our code).
1 I do disagree with the doto suggestion: it works only because this Builder class happens to implement its method-chaining by mutating a single instance and then returning it. doto is great for Java objects that require in-place mutation, but when a class is kind enough to pretend it's immutable you should really be using the method-chaining version (ie, ->).
Use .. macro. It's two consecutive dots. It allows just what you need - to consecutively call next Java method on the result of the previous.
I don't have a REPL around, but your line should translate to something like:
(.. (NutritionFacts.Builder. 240 8)
(calories 100)
(sodium 350)
(carbohydrates 27)
(build))
I'm only starting with Clojure, but it looks like standard method invocation to me:
(doto
(NutritionFacts.Builder. 240 8)
(.carbohydrates 27)
(.sodium 35)
(.calories 100)
(.build)
)
EDIT:
As @Goran Jovic points out, this calls all methods on the object created in the first form.
So it works in this case since the Java code uses method chaining, but is not more generally applicable.
doto and .. is that doto calls methods on one object defined by the first form, and .. does each invocation on the result of the previous one. In this case it is the same since Java methods keep returning the object being built.This thread is a couple of years old, and the thread-first macro is still preferred way as far as i can tell, but the $ syntax is not needed. The slash (/) works as well:
(-> (Caffeine/newBuilder)
(.maximumSize 10000)
(.build))
(Caffeine/newBuilder) is a call to a static method (Java Caffeine.newBuilder()) whereas (NutritionalFacts$Builder.) is a call to the constructor of a static class (Java new NutritionalFacts.Builder()), so this really isn't any different from the accepted answer.