2

If I have a reference of type Object and I know that this is an array, but I don't know what kind of array, what is the best way to generate a nice String?

Or in other words, what is the best / nicest implementation for the following method:

private static String anyArrayToString(Object someArray) {
    if (!someArray.getClass().isArray()) {
        throw new IllegalArgumentException("someArray is not an array!");
    }
    return ???;
}

I am aware of the methods from Arrays, namely Arrays.toString(int[]), Arrays.toString(double[]), etc. These do not work here because they are strongly typed and I don't feel like having a big if-else-if cascade. (although this is my plan B if no better solution can be found)

Ideally I would want a method that works on Object references such as System.arraycopy which checks dynamically if the passed reference is an array or not.

why do I not know what kind of array it is?

Because I get the object reference via reflection after iterating over all get-methods of a different object. It is part of a utility method that finds arbitrary differences between two complex objects even if these differences are nested deep.

Thank you very much.

Edit:

This is NOT a duplicate of What's the simplest way to print a Java array? because here the element type of the array is unknown and we only have a reference to Object rather than some specific array type.

Nic.Star
  • 150
  • 1
  • 7
  • If you want an isArray(Object object) method you can do a try - catch. Have you tried? – AM13 Jan 14 '20 at 11:27
  • isArray is a method of the Java standard library. What is missing is a general toString method that prints the contents of the array rather than its depth and hashcode. – Nic.Star Jan 14 '20 at 11:35
  • this got closed a duplicate but yea, there isn't single method for this sadly, you need to check type yourself. Tho you can avoid having if/else cascade by creating a `Map>` and put to it toString functions for each primitive array. – GotoFinal Jan 14 '20 at 12:18
  • I do not think my question is a duplicate. This is a very different situation which is not covered by the answers to the other thread. I would like to have it reexamined. – Nic.Star Jan 14 '20 at 13:17
  • I didn't vote for closing this, and I agree that its a bit different case, but also there isn't really any other special solution for this. Unless some very unoptimal ones, like creating an iterator using Arrays reflection class and getting elements by index. – GotoFinal Jan 15 '20 at 10:28
  • That would have been an acceptable answer that could have helped others in a similar situation. In my opinion that is preferable to closing this question and linking it to another that contains no answer at all. – Nic.Star Jan 15 '20 at 12:02
  • @Kayaman I have found a nice solution now which I would like to submit as an answer to my question. It uses the Java8 Stream API for a nice, functional solution: return "[" +IntStream.range(0, Array.getLength(array)) .mapToObj(i -> Array.get(array, i)) .map(Objects::toString) .reduce("", (l, r) -> l+", "+r) +"]"; – Nic.Star Jan 17 '20 at 13:40
  • @Nic.Star go ahead, I was a bit too quick with my fingers, sorry about that. – Kayaman Jan 18 '20 at 11:41

1 Answers1

2

The cleanest and most concise way of doing this would be to use the Java8 Stream API and the methods from the Array utility class.

The static method Array.getLength takes a reference of type Object. If that reference points to an array, the length of that array is returned. Otherwise an exception is thrown. Tne static method Array.get works accordingly to give access to individual array elements.

private static String anyArrayToString(Object someArray) {
    if (!someArray.getClass().isArray()) {
        throw new IllegalArgumentException("someArray is not an array!");
    }
    return "[" + IntStream.range(0, Array.getLength(someArray))
                     .mapToObj(i -> Objects.toString(Array.get(someArray, i)))
                     .reduce("", (l, r) -> l+", "+r)
               + "]";
}
Nic.Star
  • 150
  • 1
  • 7
  • This will produce results like `[, 1, 2, 3]` for `{1, 2, 3}`. The call to `reduce` should be changed to `.reduce("", (l, r) -> (l != "" ? l + ", " : "") + r)` to avoid the leading comma and whitespace. – trsft Jan 22 '22 at 10:19