0

Given an array of strings representing values and another string representing a primitive type, I need to parse the values strings into an array of the give primitive type, e.g. "double" and ["1", "2", "3"] would become [1.0, 2.0, 3.0].

The first solution that comes to mind would look something like this:

String format = "int16";
String[] values = {"1", "2", "3"};
switch (format)
{
    case "int16":
        short[] short_values = new short[values.length];
        for (int i = 0; i < values.length; i++) short_values[i] = Short.parseShort(values[i]);
        foo(short_values);
        break;
}

While this works, I can't help but feel like there is a more elegant way of doing this. Is there some way in Java to store a reference to a static method and a reference to a primitive type so that you could so something like this:

Functor parser;
Type type;

switch (format)
{
    case "int16":
        parser = Short.parseShort;
        type = short;
        break;
}
List<type> value_list = new ArrayList<>();
for (String value : values) value_list.add(parser(value));
foo(value_list.toArray(new type[0]);

Assuming that's not possible, is there any other way that I might be able to improve upon the first solution?

Thanks

3 Answers 3

2

@Couper example is pretty nice. You can also do something like this.

public class MainClass {

    public static void main(String[] args) {
        String format = "int16";
        String[] values = {"1", "2", "3"};
        ParserInterface pi = null;
        Class<?> classType = null;
        switch(format) {
        case "int16":
            pi = Short::parseShort;
            classType = Short.class;
            break;
        }
        for(String value : values) {
            System.out.println(classType.cast(pi.parse(value)));
        }
    }

}

@FunctionalInterface
interface ParserInterface {
    public Object parse(String data);
}

You can make use of functional interface to hold a method reference and set a class type to type case the parsed value. It worked for me! Please share your feedback and concerns.

Sign up to request clarification or add additional context in comments.

3 Comments

I think this is a better solution because you can implement the parsing and doesn't rely on the class constructor.
This looks super close to what I need! Is there a way I can use the classType variable to create either an array or an arraylist?
You can't create an array or a List at runtime, but you can use the List like this: List<T> l = new ArrayList<>(); for (String value : values) { l.add((T) classType.cast(pi.parse(value))); }
2

If you are working with Java 8 or higher, and if you don't mind the resulting array being "boxed" types instead of primitives (Integer, Double, etc.), then streams can be an elegant solution.

Here is a code example:

import java.util.Arrays;
import java.util.stream.Stream;

public class Streams {
    public static void main(String [] args) {
        String[] values = {"1", "2", "3"};
        String format = "double";

        Stream<String> stream = Arrays.stream(values);
        Object [] arr = null;

        switch (format) {
            case "int16":
                arr = stream.map(Short::parseShort).toArray();
                break;

            case "double":
                arr = stream.map(Double::parseDouble).toArray();
                break;
        }

        for (Object o : arr) System.out.println(o);
    }
}

If you want primitive arrays, you can use stream methods mapToInt and mapToDouble (with parameters such as Integer::intValue), but you will have to define a separate array for each case.

You can also use another stream to unbox the whole array later in the code, as described here: (Un)boxing primitive arrays in Java

Comments

1

You can do something like this:

private <T> T parse(String value, Class<T> type) {
    try {
        return type.getConstructor(String.class).newInstance(value);
    } catch (Exception e) {
        return null;
    }
}

This works as long as the that class that you need to cast to has a constructor with a single String parameter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.