Want this course?
Course: JVM Fundamentals for Clojure
Every now and then you'll have to use Java arrays. Usually it's because a method returns an array. But sometimes you'll have to create one. This lesson goes over just that--consuming and creating Java arrays in Clojure.
Very often, when you're inter-opping with some Java code, the Java code will return an array or it will need an array. So we have to know how to deal with arrays. Java arrays are built-in, and they're typically made using the array syntax in Java. And so you don't really think of them as having a constructor, like, you wouldn't say new, and then give it the name of a class, you actually use this array syntax. So we have to work around that because there's no nicely named constructor.
In fact, let's take a look. In Clojure, you can do something like this: int-array, and let's make an empty array, so an array of size zero. We'll go over the options for this in a minute. Okay, so I have an object that's an array of type zero, size zero, it's made for ints. And look at that constructor name. It's open square bracket I, well, that's the class name. Capital I.
The I is for int and that open bracket is for array. And we can actually see, what is the class of this thing. There it is. Now of course, you can't type that as valid Clojure code, it's not gonna work. So that's why all these things have little functions to help you make them. So there's int-array, there's boolean-array, right, oh wow, look at that letter.
Who would've guessed that? You can make an array of any type of a class, so you can make, oh. I don't wanna go into that too much right now. We'll go into it in a little bit. What I do wanna say is that, these are seqable, so if I do boolean-array and I wanna turn it into a seq, I can do that. It's empty so it's gonna return nil when I do seq. I can make something that's five.
Another thing is, these things take an initial value, so I can say, well, I want five trues. You can also pass it, instead of a number, like before we were passing it a number, you can pass it the values. True, true, false in a collection. Any kind of sequence, anything that's seqable. So that's a good way to be able to create arrays like that.
We usually, in Clojure, will have a seq and we can convert it into an array of a specific type, and that's just what Java will need. There's things that we can, oh, let's look at this, I wanna see how big is this, alength. That's a nice Clojure function, and basically what it does is calls, oh, is that not a thing? Dot length. Oh, hmm. I thought class, arrays had a dot length on them. I'm wrong. Anyway, you can get the array length like that. Some nice things, all these things start with a, so you can do aset, I wanna set the first one's a false, and of course it's a mutable thing, an array, so I'll have to do something a little special, so let's call our array a.
We're going to take this code, put it here. So we have to find a new array and of course, if I look at it like this, I can see the values. If I look at it like this, I can't see the values. So I get the values like this. Now I'm gonna do aset on a, the first one to false. Now when I do a, the first one is false. So, it's a mutable thing. It's mutable, you've got all the warnings of having mutable state right there. But there's some nice stuff, like, if I have this array a, and I want to map over it, so what's gonna happen is, Clojure is going to map, I need to make better names.
Okay. Let's do def array is, let's do an int, int-array. So I'm making some nice names to demonstrate something. So let's say it's gonna be range of 10. Array, we see that it's type array of integer, and if we do seq on it, we'll see that it's got zero through nine. All right, so now I'm gonna do something like this, amap. Amap is like your typical for-loop that loops through an array, except what it's doing is it's looping through the array and putting the values into a new array.
So I'll do a taking of the array, I gave it the name of the index, you know how in a for-loop, you're gonna have some value, some variable like i. Now we're gonna have a return value and you're gonna give it that name. You can give it whatever name you want, but I'm gonna say this is a return value. Initially, array is going to have, ret is gonna be a clone of that array, so all the same values and same length, obviously. And then you put an expression, and what's gonna happen is the values of ret are gonna be the subsequent return values of that expression. So I could do something like aget, that's how you get from an array, array i.
That just means I'm going to be putting the same value in there. And then what did I get back? I'm gonna do *1 to get the last thing, and I got the same thing. Let's do something else. Let's do inc. Now we're gonna do seq on that, now we notice that now we're starting with one and we get all the way to 10. So this expression is evaluated for each element in array, and the value of it is put into that index in ret. So it's like map, but it's just copying from, it's putting the value into a new array. And it's a little bit more complicated cuz it's not a function. I don't really use it, I don't know if I've ever used this, but you can use it if you want. There's something very similar called areduce. So it's gonna take our array and it's gonna have the index and return value. It's just the name of return value. So you can refer to ret in this expression, that's what that's saying.
Now we're gonna give it an initial value, so I'm gonna sum up this list. So I'm gonna make that a zero and the expression is going to be + ret, which is the return value, not an array, it's the return value, and aget array i. And there we get the sum. Okay, this would be the same as doing reduce + 0 array, except it doesn't create intermediate stuff, it's really like a for-loop. Okay, I don't use that that much.
Another thing you might want is aclone, so that makes a new one each time, it's just copying the memory. You often want to take some stuff and put it into an array, you already have a collection, so there's this thing called to-array, and you could give it a collection like range 100, boom, and if I do seq of that, see it made an array. Look at the type, it's always gonna be type object, and there's the seq view of that but the array is still there. Now, if you wanna have the type, you have to do into-array. And I'll do range 100 and we'll see what that gives us. Now see, this creates an array of type java.lang.Long, which is not the primitive type. See, this is only gonna give you the, the class version, the boxed version. It's an object instead of a primitive.
All right, there's a lot of stuff you can do with arrays. I don't really use them that much. I'll show you the one case where I have to go look in the docs, how to do arrays. So if I go to, I'm gonna open my browser, this is the String class, you see at the top, standard string. There is a method called format. Now look at this: it takes a string, which is the format string, this is like printf, like s printf in c. Okay, it takes a format string and then it takes this thing like a dot dot dot on object, it's called args. Java has this syntax now that lets you splat out arguments. So in Java, in Java I would write static, so I do String.format, something like number % d. And then I would put, oh number, string, %s, something like that. And then I'd put 1.8 and Java. So what it's saying is you can put any number of arguments after it. Now, there's actually no way to directly do this in Clojure, because when Clojure does the introspection, it's gonna see that this is one argument. And what is actually happening behind the scenes when the Java compiler gets to this code, is it's making an array of args. So it's actually just one argument.
So you think you could do something like String/format number %d string %s and 1.8 and Java, and if we run this, it's gonna say, oh, string cannot be cast to, right. So what's happening, I know, this is one of those cryptic messages that you have to learn how to interpret, what it's saying is it sees that there are three arguments, one, two, three, and so it's looking at this one. And it's saying, wait a second, you gave me a string for the first argument. See, this one has three arguments. You gave me a string and, hello, this is not a locale, so I don't know what to do. Really we wanna use this one, so we actually need to make it into two. So how do we do that?
Well, we can always just package these up as a collection, any kind of collection of vector, we want them in the right order. And so then we do into-array, or make-array, cuz it's gotta be an object, always an object. Array Now, if I run it, oh, wrong number of arguments passed to make-array, oh, sorry, not make-array. The one I showed you before, to-array. Java lang double, well, that's just a conversion problem.
There we go. Used the wrong thing. Let's put a %f. And there we have it, it made the right string. So this is the case where I use this, where I use arrays. Everything else, I usually don't. You might, if you really need arrays, the docs are pretty good and it'll show you how to do it. If you get something that looks like this, object open square bracket, you know you have an array, you can always just turn it into a vec or turn it into a seq. Like, if I have this, just looks like, what is that, totally un-readable, boom, turn it into a vec, I can see it now. Very useful at the rebel.