When I call printArray in my pvsm, the error I keep receiving is:
Exception in thread "main" java.lang.ClassCastException:
java.base/[Ljava.lang.Object; cannot be cast to java.base/[Ljava.lang.Integer
I know the problem is with the R[] result = (R[]) list.toArray(). I have no idea how to convert the ArrayList to an array and cast it to a generic at the same time. Note I cannot change the parameters of the function map or add any new functions.
public class Homework2 {
public static void main(String[] args){
Function<Integer,Integer> function = new CalculateSuccessor();
Double[] d= {2.0,4.0,8.0};
Integer[] i= {2,4,8};
printArray(map(function,i));
}
#SuppressWarnings("unchecked")
public static <R,D> R[] map(Function<R,D> function, D[] array){
ArrayList<R> list = new ArrayList<>();
for (D element: array){
list.add(function.apply(element));
}
// THIS LINE OF DAMN CODE
R[] result = (R[]) list.toArray();
return result;
}
public static <R> void printArray(R[] array){
System.out.print("{ ");
for (R element: array){
System.out.print(element + ", ");
}
System.out.print("}");
}
public static class CalculateSuccessor implements Function<Integer,Integer> {
#Override
public Integer apply(Integer parameter) {
return parameter * 2;
}
} //End CalcSuc
} //End Homework2
In another class I have
public interface Function<R,D> {
public R apply(D parameter);
}
which you need for the function.apply. My professor insisted we use this instead of importing Function.
Part one, you need the Class<R> in order to dynamically create an array R[]. I would prefer Arrays.toString over implementing my own version of that. I also needed a Function<D, R> (not a Function<R, D>). But making those changes like
public static void main(String[] args) {
Function<Integer, Integer> function = new CalculateSuccessor();
Double[] d = { 2.0, 4.0, 8.0 };
Integer[] i = { 2, 4, 8 };
System.out.println(Arrays.toString(map(Integer.class, function, i)));
}
public static <R, D> R[] map(Class<R> cls, Function<D, R> function, D[] array) {
ArrayList<R> list = new ArrayList<>();
for (D element : array) {
list.add(function.apply(element));
}
return list.toArray((R[]) Array.newInstance(cls, list.size()));
}
I get
[4, 8, 16]
You can extract the type information from the Function<D,R> because you implemented it with an actual class. So together with #Elliott Frisch answer.
public static <R, D> R[] map(Function<D, R> function, D[] array) {
ArrayList<R> list = new ArrayList<>();
for (D element : array) {
list.add(function.apply(element));
}
Class<?> componentClass = extractReturnType(function)
return list.toArray((R[]) Array.newInstance(componentClass, list.size()));
}
private static Class<?> extractReturnType(Function<?, ?> function) {
Type[] interfaces = function.getClass().getGenericInterfaces();
for(Type iface:interfaces) {
if (iface instanceof ParameterizedType && Function.class.equals(((ParameterizedType) iface).getRawType())) {
return (Class<?>) ((ParameterizedType) iface).getActualTypeArguments()[1];
}
}
throw new IllegalArgumentException("Unable to extract type information");
}
Related
I am struggling with understanding why the addAll() method from ArrayList does not work.
I have my class:
public class XList<E> extends ArrayList<E> {...
}
With a method:
public XList<E> union(XList<E> input) {
System.out.println(this);//
System.out.println(input);
this.addAll(input);
return this;
}
System.out.println indicates, that correct values are in the given lists, but after adding, "this" does not get updated, and is returned without modification.
Could you please clue me in, on the root of the problem?
Any help greatly appreciated.
SSCCE:
public class Main {
public static void main(String[] args) {
XList<Integer> list1 = new XList<>(1, 3, 9, 11);
XList<Integer> list2 = XList.of(5, 6, 9);
List<Integer> m1 = list1.union(list2);
System.out.println(m1);
}
}
class XList<E> extends ArrayList<E> {
private List<E> lista;
public XList(E a, E b, E c) {
lista = new ArrayList<>();
lista.add(a);
lista.add(b);
lista.add(c);
}
public XList(E a, E b, E c, E d) {
lista = new ArrayList<>();
lista.add(a);
lista.add(b);
lista.add(c);
lista.add(d);
}
static XList of(Integer a, Integer b, Integer c) {
return new XList(a, b, c);
}
public XList<E> union(XList<E> input) {
System.out.println("this: " + this);
System.out.println("input: " + input);
this.addAll(input);
return this;
}
public String toString() {
return lista.toString();
}
Your problem is that your XList confusingly both extends ArrayList and also contains a list as a field. That means that XList basically is two separate lists: it's a list itself and it also includes a different separate list
If I were you I'd remove "extends ArrayList" and replace
this.addAll(input);
With
this.lista.addAll(input.lista);
I have assignment in java ,I need help please.
I tried to solve it but I have some problem that can't understand them.
Assignment is:
In this exercise, use the Template method pattern to define an abstract class Filter with a public method filter (the template method) that calls the method accept (the hook method) that can be implemented in different ways in the different concrete classes. Write a test program by extending the class Filter and defining accept so that only strings of at most three characters are accepted.
public abstract class Filter<T> {
public abstract T[] filter(T[] list);
public abstract boolean accept(T val);
}
public class FilterTest<T> extends Filter<T> {
private int capacity = 0;
public FilterTest(int cap) {
this.capacity = cap;
}
#Override
public T[] filter(T[] list1) {
#SuppressWarnings("unchecked")
T[] finalList = (T[]) Array.newInstance(list1.getClass().getComponentType(), capacity);
int counter = 0;
for (T t : list1) {
if (accept(t)) {
finalList[counter] = t;
counter++;
}
}
return finalList;
}
public void printArray(T[] list2) {
for (int i = 0; i < list2.length; i++) {
if (list2[i] != null) {
System.out.print(list2[i] + " ");
}
}
System.out.println();
}
#Override
public boolean accept(T val) {
return String.valueOf(val).length() > 0 &&
String.valueOf(val).length() <= 3;
}
public static void main(String[] args) {
FilterTest<String> filterTest = new FilterTest<>(8);
String[] lists = {
"Hi", "here", "is", "the", "AOOP", "course", "at", "University"
};
System.out.print("My original list is: ");
filterTest.printArray(lists);
System.out.print(" The filtered list is: ");
String[] filteredList = filterTest.filter(lists);
filterTest.printArray(filteredList);
}
}
Here is comment from my teacher:
"not correct, only the accept method should be abstract in the Filter class, the filter method should be already implemented in the Filter class and not be abstract all implementation will be the same, only the accept method changes for different filters)".
I don't understand what should I do now, how the code will be correct.
help please,
Thanks
I assume that Filter should look something like this
public abstract class Filter<T> {
public T[] filter(T[] list1) {
#SuppressWarnings("unchecked")
T[] finalList = (T[]) Array.newInstance(list1.getClass().getComponentType(), capacity);
int counter = 0;
for (T t : list1) {
if (accept(t)) {
finalList[counter] = t;
counter++;
}
}
return finalList;
}
public abstract boolean accept(T val);
}
You can even declare Filter<T> as an interface and have a default implementation for filter. Have a look here
How to make this method generic to return a List of any type currently it returns a List of String:
public static List<String> splitCommaSeparatedStringToListAnyDataTypeArray(String s) {
List<String> ints = new ArrayList<>();
if (isNull(s)) {
return ints;
}
String[] split = s.split(COMMA);
for (String st : split) {
ints.add(String.valueOf(st));
}
return ints;
}
Assuming that you use Java 8, you could use a Function to convert a String to a given type, you would then rewrite your method as next:
public static <T> List<T> splitCommaSeparatedStringToList(String s,
Function<String, T> function) {
if (isNull(s)) {
return Collections.emptyList();
}
// Convert the array of String into a List of T
return Arrays.stream(s.split(COMMA)).map(function).collect(Collectors.toList());
}
Your initial method would be the equivalent of splitCommaSeparatedStringToList(myInputString, String::valueOf).
For previous version of Java, the logic is the same, simply use FluentIterable from Google Guava to replace the Stream and use com.google.common.base.Function instead of java.util.function.Function as mapper function.
public static <T> List<T> splitCommaSeparatedStringToList(String s,
Function<String, T> function) {
if (isNull(s)) {
return Collections.emptyList();
}
return FluentIterable.from(Arrays.asList(s.split(COMMA))).transform(function).toList();
}
only replace List<String> with List<?>
public static List<?> splitCommaSeparatedStringToListAnyDataTypeArray(String s) {
List<String> ints = new ArrayList<>();
if (isNull(s)) {
return ints;
}
String[] split = s.split(COMMA);
for (String st : split) {
ints.add(String.valueOf(st));
}
return ints;
}
Why does following code not throws exception?
import java.util.ArrayList;
import java.util.List;
#SuppressWarnings("unchecked")
public class MainRunner {
public static void main(String[] args) {
List<String> s = new ArrayList<String>() {
{
add("a");
add("1");
add("1");
}
};
// List<Integer> i = (List<Integer>) listConvertor(s, new Integer("1"));
List<Integer> i = (List<Integer>) listConvertor(s, Integer.class);
System.out.println(i);
}
#SuppressWarnings("unchecked")
public static <T, P> List<?> listConvertor(List<T> inputList, P outputClass) {
List<P> outputList = new ArrayList<P>(inputList.size());
for (T t : inputList) {
outputList.add((P) t); // shouldn't be classCastException here?
}
return outputList;
}
}
I want to return List<P> instead of List<?> . But when I write List<P> , it means List<Class<P>> . i.e. in above case , it means List<Class<Integer>> , but I want List<Integer> as return.
I want below code: (so that i don't have to cast again at when method returns)
List<Integer> i = listConvertor(s, Integer.class);
System.out.println(i);
}
#SuppressWarnings("unchecked")
public static <T, P> List<P> listConvertor(List<T> inputList, P outputClass) {
List<P> outputList = new ArrayList<P>(inputList.size());
for (T t : inputList) {
outputList.add((P) t); // shouldn't be classCastException here?
}
return outputList;
}
}
This should do the job with minimal fuss:
public static <T, P> List<P> listConvertor(List<T> inputList, Class<P> outputClass) {
List<P> outputList = new ArrayList<P>(inputList.size());
for (T t : inputList) {
if( !outputClass.isInstance(t) )
throw new ClassCastException("Faked CCException");
#SuppressWarnings("unchecked")
P p = (P) t;
outputList.add(p);
}
return outputList;
}
no cast on the caller side
exception if inappropriate types are in the source list.
public static <T, P> List<P> listConvertor(List<T> inputList, Class<P> outputClass) {
remember, you are passing a Class Object, not an Integer Object.
No, of course it does not throw an exception. Generics are for compile time checks, not run-time. At run time, all your lists are List<Object> and the cast is made implicitly by the JVM.
Edit : in your code,
for (T t : inputList) {
outputList.add((P) t); // shouldn't be classCastException here?
}
is actually compiled to
for (Object t : inputList) {
outputList.add((Object) t); // shouldn't be classCastException here? -- no
}
For example, with your code, if you do i.get(0).getClass() you will then get a ClassCastException as the item cannot be converted from String to Integer.class (note: the same would apply however you do it as you cannot implicitly cast a String to an Integer. Period.)
If this is really what you want to do, cast T to P (for example, cast strings to a numeric value), then I suggest you use another pattern. For example :
static interface ClassConverter<F,T> {
public T convert(F o);
}
static class StringToIntConverter implements ClassConverter<String,Integer> {
public Integer convert(String o) {
try {
return Integer.parseInt(o);
} catch (NumberFormatException e) {
return 0;
}
}
}
public static void main(String[] args) {
List<String> s = new ArrayList<String>() {
{
add("a");
add("1");
add("1");
}
};
// List<Integer> i = (List<Integer>) listConvertor(s, new Integer("1"));
List<Integer> i = (List<Integer>) listConvertor(s, new StringToIntConverter());
System.out.println(i);
System.out.println(i.get(0).getClass().getName());
}
public static <T, P> List<P> listConvertor(List<T> inputList, ClassConverter<T, P> c) {
List<P> outputList = new ArrayList<P>(inputList.size());
for (T t : inputList) {
outputList.add(c.convert(t)); // cast handled by the class method == safer
}
return outputList;
}
Than all you need to do is implement the ClassConverter interface to any types you wish to covert T to P and pass it to your listConverter method.
import java.util.ArrayList;
import java.util.List;
public class MainRunner {
public static void main(String[] args) {
List<String> s = new ArrayList<String>() {
{
add("a");
add("1");
add("1");
}
};
List<Integer> i = listConvertor(s, Integer.class);
System.out.println(i);
}
public static <T, P> List<P> listConvertor(List<T> inputList, Class<P> outputClass) {
List<P> outputList = new ArrayList<P>(inputList.size());
for (T t : inputList) {
outputList.add((P) t); // shouldn't be classCastException here?
}
return outputList;
}
}
Same as #A.H.'s answer, but much simplified using Class.cast(), and also got rid of the unnecessary T:
public static <P> List<P> listConvertor(List<?> inputList, Class<P> outputClass) {
List<P> outputList = new ArrayList<P>(inputList.size());
for (Object t : inputList) {
P p = outputClass.cast(t);
outputList.add(p);
}
return outputList;
}
Ran into an issue with generics and array types that I am unable to solve. It boils down to this. In the following code, how can I convert a generic List into an Array of the same generic type, while using a factory method ("T convert(String value)") to convert each individual element of the input generic List:
#Test
public void test(){
List<String> integers = Arrays.asList("1", "2", "3", "4");
Integer[] integerArray = new TypeConverter<Integer[]>(Integer[].class).convert(integers);
assertEquals(4, integerArray.length);
assertEquals(1, integerArray[0].intValue());
assertEquals(2, integerArray[1].intValue());
assertEquals(3, integerArray[2].intValue());
assertEquals(4, integerArray[3].intValue());
}
public class TypeConverter<T>{
Class<T> type;
public TypeConverter(Class<T> type) {
this.type = type;
}
T convert(List<String> values){
List output = new ArrayList();
for (String value : values) {
//have to use Object.class here since I cant get the non-array type of T:
output.add(new TypeConverter(type.getComponentType()).convert(value));
}
return (T) output.toArray();
}
T convert(String value){
//convert to an int;
if(type == Integer.class){
return (T) new Integer(Integer.parseInt(value));
}
return null;
}
}
As you can see, my naive approach was to simply use the toArray Method, and cast the result like so:
(T) value.toArray()
but this results in a ClassCastException:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer
Is there a way to solve this that I am not seeing or should I take another approach?
Edit
Here's the concrete code that I am trying to fix. Specifically the visitArray() method:
https://github.com/johncarl81/transfuse/blob/master/transfuse/src/main/java/org/androidtransfuse/analysis/adapter/AnnotationTypeValueConverterVisitor.java
You may use the alternate version of List.toArray that takes as a parameter the type of the array you want to get.
toArray Method
You may create an empty array with some method of the Array class.
Array.newInstance
So having the expected type you just use Array.newInstance(type, 0); and pass in the result to the toArray method.
Edit:
Since your generic type is an array, you need to get the type of the components, try this:
Object[] array = (Object[]) Array.newInstance(type.getComponentType(), 0);
return (T) output.toArray(array);
Your value conversion method has a little something I'll let you figure out how to solve :)
Cheers!
Don't try to cast to T, try casting to T[], as you are handling an array of T's.
I suggest ditching the reflection and reference arrays.
Slightly abusing inheritance:
public abstract class StringConverter<T> {
public List<T> convert(List<String> values) {
List<T> output = new ArrayList<>();
for (String value : values) {
output.add(convert(value));
}
return output;
}
public abstract T convert(String value);
}
public static StringConverter<Integer> toInteger() {
return new StringConverter<>() {
public Integer convert(String value) {
return Integer.parseInt(value);
}
};
}
This works for me:
import java.util.*;
import java.lang.reflect.*;
public class Foo {
public static void main(String[] args) {
new Foo().test();
}
public void test(){
List<String> integers = Arrays.asList("1", "2", "3", "4");
Integer[] integerArray = new TypeConverter<Integer>(Integer.class).convert(integers);
System.out.println(Arrays.deepToString(integerArray));
}
public class TypeConverter<T>{
Class<T> type;
public TypeConverter(Class<T> type) {
this.type = type;
}
T[] convert(List<String> values){
List<T> output = new ArrayList<>();
for (String value : values) {
output.add(convert(value));
}
return output.toArray((T[]) Array.newInstance(type, output.size()));
}
T convert(String value){
if(type == Integer.class){
return (T) new Integer(Integer.parseInt(value));
}
else if(type == Long.class){
return (T) new Long(Long.parseLong(value));
}
return null;
}
}
}
return (T) values.toArray(); should be return (T)output.toArray( new Integer[0])
no, you have to hard code new Integer[0]