Last active
February 17, 2018 22:43
-
-
Save manoelcampos/040d1b3878dca2fd1c1919f12d1ccb9b to your computer and use it in GitHub Desktop.
A functional, generic class to show how to get String values from an array and return such values converted to the generic type. This class provides default implementations for converting from String to classes representing primitive types.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Arrays; | |
import java.util.Objects; | |
import java.util.stream.Collectors; | |
import java.util.function.Function; | |
import java.lang.reflect.Array; | |
public class Option3<T>{ | |
private int length; | |
private String defaultValue; | |
private final Class<T> klass; | |
private final Function<String, T> conversionFunction; | |
/** | |
* Creates an Option3 that consider the values are primitives and therefore | |
* can be automatically converted from String internally. | |
* If the values aren't primitives, use the overloaded constructor to provide a conversion {@link Function}. | |
* | |
* @throws RuntimeException when the generic type isn't a class representing a primitive value | |
*/ | |
public Option3(final Class<T> klass){ | |
this(klass, Option3.<T>getDefaultConversionFunction(klass)); | |
} | |
public Option3(final Class<T> klass, final Function<String, T> conversionFunction){ | |
Objects.requireNonNull(conversionFunction); | |
this.conversionFunction = conversionFunction; | |
this.klass = klass; | |
} | |
@SuppressWarnings("unchecked") | |
private static <T extends Object> Function<String, T> getDefaultConversionFunction(final Class<T> klass){ | |
//If the generic type is String, there is no need for conversion | |
if(klass == String.class) | |
return value -> (T)value; | |
else if(klass == Short.class) | |
return value -> (T)Short.valueOf(value); | |
else if(klass == Integer.class) | |
return value -> (T)Integer.valueOf(value); | |
else if(klass == Long.class) | |
return value -> (T)Long.valueOf(value); | |
else if(klass == Float.class) | |
return value -> (T)Float.valueOf(value); | |
else if(klass == Double.class) | |
return value -> (T)Double.valueOf(value); | |
else | |
throw new RuntimeException( | |
"There is no way to convert option values from String to " + klass.getSimpleName() + | |
". Use the overloaded constructors to pass a conversion Function."); | |
} | |
public T getFirstValue(final String[] values){ | |
return getValues(values)[0]; | |
} | |
/** | |
* Gets the values of the Option3, excluding the Option3 name (the 0th element). | |
* @return an array containing the values (without the 0th element), if the values' length isn't as expected; | |
* or an array containing the default value if the length isn't as expected and there is a default value. | |
* @throws IllegalStateException when the length of values isn't as expected and there isn't a default value | |
*/ | |
public T[] getValues(final String[] values){ | |
if(defaultValue == null && values.length != length){ | |
throw new IllegalStateException("Wrong Option3 line passed, string options do only have 2 values"); | |
} | |
if(values.length == length) { | |
return createGenericArray(values, 1); | |
} | |
return createGenericArray(new String[]{defaultValue}); | |
} | |
private T[] createGenericArray(final String[] values){ | |
return createGenericArray(values, 0); | |
} | |
@SuppressWarnings("unchecked") | |
private T[] createGenericArray(final String[] values, final int startInclusive){ | |
final T[] array = (T[])Array.newInstance(klass, values.length-startInclusive); | |
//It was required to convert to list then to array in order to get an array of the generic type. | |
Arrays | |
.stream(values, startInclusive, values.length) | |
.map(this.conversionFunction) | |
.collect(Collectors.toList()) | |
.toArray(array); | |
return array; | |
} | |
/* Trying the implementation. */ | |
public static void main(String[] args) { | |
System.out.println(); | |
//Creates an Option3 of String values, which doesn't require a conversion Function. | |
Option3<String> strOpt = new Option3<>(String.class); | |
strOpt.length = 3; | |
String[] values = new String[]{"-o", "1", "2"}; | |
System.out.println("First String Value: " + strOpt.getFirstValue(values)); | |
System.out.println("String Values: " + Arrays.toString(strOpt.getValues(values))); | |
try{ | |
values = new String[]{"-o", "1"}; | |
//Error because the length of values isn't equal to 3 | |
System.out.println("First String Value: " + strOpt.getFirstValue(values)); | |
} catch(Exception e){ | |
System.out.println("\nError: " + e.getMessage() + "\n"); | |
} | |
strOpt.length = 2; | |
strOpt.defaultValue = "default value"; | |
values = new String[]{"-o"}; | |
System.out.println("First String Value: " + strOpt.getFirstValue(values)); | |
System.out.println("String Values: " + Arrays.toString(strOpt.getValues(values)) + "\n"); | |
//Creates an Option3 of Integer values, which will be automatically converted internally from String to Integer. | |
Option3<Integer> intOpt = new Option3<>(Integer.class); | |
intOpt.length = 3; | |
values = new String[]{"-o", "1", "2"}; | |
System.out.println("\nFirst Int Value: " + intOpt.getFirstValue(values)); | |
Integer[] intValues = intOpt.getValues(values); | |
System.out.println("Int Values: "); | |
for(Integer i: intValues){ | |
System.out.println(i); | |
} | |
System.out.println(); | |
values = new String[]{"-o", "99", "this value isn't a number and will throw an exception"}; | |
try { | |
System.out.println("First Int Value: " + intOpt.getFirstValue(values)); | |
intValues = intOpt.getValues(values); | |
System.out.println("Int Values: "); | |
for(Integer i: intValues){ | |
System.out.println(i); | |
} | |
}catch(RuntimeException e){ | |
System.out.println(e.getMessage()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment