HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Three methods to serialize 7-, 6-, and 3-dimensional int arrays

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
threearraysserializedimensionalmethodsandint

Problem

Here's some code I wrote which sends multi-dimensional arrays to a file, is there any way I can make a generic method?

public void sendSevenToFile(int[][][][][][][] seven, String filename) throws IOException {
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(filename));
    outputStream.writeObject(seven);
}

public void sendSixToFile(int[][][][][][] six, String filename) throws IOException {
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(filename));
    outputStream.writeObject(six);
}

public void sendThreeToFile(int[][][] three, String filename) throws IOException {
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(filename));
    outputStream.writeObject(three);
}

Solution

An array in Java is an object, not a primitive, so you can accept the parameter as Object, without specializing it as an array (you do not do that in your current code either, so you do not lose anything by this approach). Yes, you lose some type safety this way, but you can get it back during runtime by using .getClass().isArray(). Overall, my approach is:

/**
* Serializes an array of arbitrary dimensions to a file
* @param array    the array to serialize
* @param filename the name of the file to serialize array to
* @throws IllegalArgumentException if array is not an array
* @throws IOException              if some error was encountered during serialization
*/
public void serializeArrayToFile(Object array, String filename) throws IOException {
    if(!array.getClass().isArray()){
        throw new IllegalArgumentException("Cannot serialize non-array object " + array.toString());
    }
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(filename));
    outputStream.writeObject(array);
}


And just in case you want this to be absolutely specific for only int arrays of arbitrary dimensions,

/**
* Serializes an array of arbitrary dimensions to a file
* @param array    the array to serialize
* @param filename the name of the file to serialize array to
* @throws IllegalArgumentException if array is not an int array
* @throws IOException              if some error was encountered during serialization
*/
public void serializeArrayToFile(Object array, String filename) throws IOException {
    Class classOfArray = array.getClass();
    if(!classOfArray.isArray()){
        throw new IllegalArgumentException("Cannot serialize non-array object " + array.toString());
    }
    Class componentType = classOfArray.getComponentType();
    if(!(componentType.isPrimitive() && 
         int.class.isAssignableFrom(componentType)) {
        // Can also be `UnsupportedOperationException1, depending on required semantics
        throw new IllegalArgumentException(String.format(
                                           "Serialization of non-`int` array %s of component type %s is not allowed", 
                                            array.toString(), componentType.toString()));
    }
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(filename));
    outputStream.writeObject(array);
}


Note that a nice side-effect of this approach is that you can now serialize arrays of arbitrary dimensions!

Note the naming convention - I use serialize instead of send, as that is what you are actually doing. Although I do not do it here for purposes of compatibility with the existing project structure, you might consider making this method static as it does not depend on the implicit this.

Also, the first array.toString() isn't required, the string concatenation will do it implicitly, but in my policy for such cases, explicit is better than implicit.
Addendum

The OP asked in the comments as to how to determine the number of dimensions of an array if it has been casted to Object. This is possible via reflection, whether by descending the type hierarchy until the result of .getClass().isArray() is false (slow), or by counting the number of '[' characters in the result of .getClass().getName() (faster). I'll illustrate the second method, which has been suggested by @wizzwizz4 in the comments, as that is more practical in all respects (I do not consider it to be "hacky", as @wizzwizz4 does, as the result of getName() for the class of any array type is explicitly documented as here.

public static int getDimensionsOfArray(Object array) {
    return (int) array.getClass()
                                .getName()
                                .chars()
                                .filter(c -> c == '[')
                                .count();
}


I use Java 8 Streams here, but you could just as well do it with a loop (I like the declarative approach of using Streams, as my primary language is Scala). The cast to int exists because Stream.count() returns a long, as Streams are lazy and can theoretically hold an infinite number of elements.
References:

I referred to this StackOverflow answer for the array type verification code.

Code Snippets

/**
* Serializes an array of arbitrary dimensions to a file
* @param array    the array to serialize
* @param filename the name of the file to serialize <code>array</code> to
* @throws IllegalArgumentException if <code>array</code> is not an array
* @throws IOException              if some error was encountered during serialization
*/
public void serializeArrayToFile(Object array, String filename) throws IOException {
    if(!array.getClass().isArray()){
        throw new IllegalArgumentException("Cannot serialize non-array object " + array.toString());
    }
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(filename));
    outputStream.writeObject(array);
}
/**
* Serializes an array of arbitrary dimensions to a file
* @param array    the array to serialize
* @param filename the name of the file to serialize <code>array</code> to
* @throws IllegalArgumentException if <code>array</code> is not an <code>int</code> array
* @throws IOException              if some error was encountered during serialization
*/
public void serializeArrayToFile(Object array, String filename) throws IOException {
    Class<?> classOfArray = array.getClass();
    if(!classOfArray.isArray()){
        throw new IllegalArgumentException("Cannot serialize non-array object " + array.toString());
    }
    Class<?> componentType = classOfArray.getComponentType();
    if(!(componentType.isPrimitive() && 
         int.class.isAssignableFrom(componentType)) {
        // Can also be `UnsupportedOperationException1, depending on required semantics
        throw new IllegalArgumentException(String.format(
                                           "Serialization of non-`int` array %s of component type %s is not allowed", 
                                            array.toString(), componentType.toString()));
    }
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(filename));
    outputStream.writeObject(array);
}
public static int getDimensionsOfArray(Object array) {
    return (int) array.getClass()
                                .getName()
                                .chars()
                                .filter(c -> c == '[')
                                .count();
}

Context

StackExchange Code Review Q#158922, answer score: 6

Revisions (0)

No revisions yet.