java generics compile error, generic class on the stack - java

I'm not sure why this doesn't work in Java:
import java.util.Map;
public class FreqCounter<T,R> {
private Map<T, Integer> hist;
private R item;
public FreqCounter (final R item_) {
item = item_;
}
public T getMostFrequentElement() {
T most_frequent_element = T();
Integer highestcount = 0;
for(T t : item) {
Integer count = hist.get(t);
if(count == null) {
hist.put(t, 1);
}
else {
hist.put(t, count + 1);
}
if(count + 1 > highestcount) {
most_frequent_element = t;
highestcount = count + 1;
}
}
return most_frequent_element;
}
}
class HelloWorld {
public static void main(String[] args) {
String s = "aaabbcccc";
FreqCounter<Character, Integer> counter = new FreqCounter<Character, Integer>(s);
}
}
Problem lines:
1. T most_frequent_element = T();
2. for(T t : item)
3. FreqCounter<Character, Integer> counter = new FreqCounter<Character, Integer>(s);
Cannot find symbol: method T()
required: array or java.lang.Iterable, found: R
Required java.lang.Integer
Found: java.lang.String
reason: actual argument java.lang.String cannot be converted to java.lang.Integer by method invocation conversion
What I was trying to do was make a class that could count how many times an element in an iterable container shows up. Originally I just wanted to make it to count characters in a string but I thought I could make it more general. I think some of this would work in C++?
Also, does FreqCounter<Character, Integer> counter = new FreqCounter<Character, Integer>(s); need to be "newed" as opposed to declared on the stack?

T is a Generic type, not a real one, and one of the limitations of generics is that you cannot instantiate a new one (which is what I think you were trying to do here).
What you can do though is assign, call methods in, keep references too, duplicate references too, etc.
What you probably actually wanted to do was pull the set of Ts out of the keySet of the Map.
T t = null;
int count = 0;
for (Entry<T, Integer> e: hist.entrySet()) {
if (e.getValue() > count) {
count = e.getValue();
t = e.getKey();
}
}
return t;
Java Generics provide a lot of the same functionality that C++ templates do, but they work in quite a different way. Quite apart from anything else you only have one ArrayList class no matter how many different ways you instantiate one. The generics are used for compiler time type checking and then erased and are not present at all during run time.

Related

When building containers why is using Java Generics better than using the Object Class? (Java Generics & DataStructures)

So I have been reviewing my data structures and came across an interesting thought regarding Java generics and the Object class. I have implemented and run a "generic bag" in two different ways (Notice below: IObjectBag.java, ObjectBag.java, IGenericBag.java, and GenericBag.java) and have used them both (Notice: Below main.java and Output). I have removed some of the unnecessary code as per stack overflow rules but if you want the full implementation, let me know.
Also, I have researched the topic in many websites, books and courses in addition to looking at the source code for the ArrayList class here and I understand that my GenericBag is a better option than my ObjectBag but not well enough to explain it in a practical way during an interview. And I am confused that my GenericBag uses more casting operations than my ObjectBag in its implementation (see Remove and PrintBag).
So, other than the syntactic sugar, why is my GenericBag better? Please use my classes as examples.
Are there any important differences in runtime/overhead/space/time I am not noticing?
How would you answer this question or expect it to be answered in an interview?
Bonus questions: If you want, please answer the bonus questions in the Main and GenericBag comments (I think I can answer them myself though, just want to hear your opinion).
IObjectBag interface:
public interface IObjectBag {
void add(Object item);
Object remove(Object item) throws NoSuchElementException;
boolean isEmpty();
int find(Object item);
Object get(int index);
int numItems();
}
ObjectBag class:
public class ObjectBag implements IObjectBag {
private Object [] items; // the java class attribute that will hold out "ints"
private int numItems;
public static void printBag(IObjectBag bag) {
for(int i = 0; i < bag.numItems(); i++) {
System.out.println(bag.get(i));
}
}
public ObjectBag(int size) {
this.items = new Object[size]; // fills array with null values
this.numItems = 0;
}
public void add(Object item){
// adds item to end of bag
}
public Object remove(Object item) {
int index = this.find(item);
if(index == -1) throw new NoSuchElementException("oops nothing found");
Object out = this.items[index];
this.items[index] = null;
this.numItems -= 1;
if(index + 1 != this.items.length && this.items[index + 1] != null) {
for(int i = index; i < this.items.length; i++) {
if(i + 1 != this.items.length) this.items[i] = this.items[i + 1];
}
this.items[this.items.length - 1] = null;
}
return out;
}
public int find(Object item) {
// return index given item or -1
}
public Object get(int index) {
// returns item given index
}
}
IGenericBag class:
public interface IGenericBag <T> {
void add(T item);
T remove(T item) throws NoSuchElementException;
boolean isEmpty();
int find(T item);
T get(int index);
}
GenericBag class:
public class GenericBag<T> implements IGenericBag<T> {
// private T[] items; can't use this b/c see comment in constructor
private Object[] items;
private int numItems;
public static void printBag(GenericBag bag) {
for(int i = 0; i < bag.numItems(); i++) {
System.out.println(bag.get(i));
}
}
public GenericBag(int size) {
// this.items = new T[size]; Bonus: throws generic array creation error (why?)
this.items = new Object[size];
this.numItems = 0;
}
public void add(T item){
this.items[this.numItems] = item;
this.numItems += 1;
}
public T remove(T item) {
int index = this.find(item);
if(index == -1) throw new NoSuchElementException("oops nothing found");
T out = (T) this.items[index];
this.items[index] = null;
this.numItems -= 1;
if(index + 1 != this.items.length && this.items[index + 1] != null) {
for(int i = index; i < this.items.length; i++) {
if(i + 1 != this.items.length) this.items[i] = this.items[i + 1];
}
this.items[this.items.length - 1] = null;
}
return out;
}
public int find(Object item) {
// given object return index or throw exception
}
public T get(int index) {
return (T) this.items[index];
}
}
Main class:
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
System.out.println("Hello StackOverFlow!");
Object int1 = new Integer(1);
Object int2 = new Integer(2);
Object int3 = new Integer(3);
/* using my object bag ************************************************/
System.out.println("using my object bag");
IObjectBag myObjectBag = new ObjectBag(3);
myObjectBag.add(int1);
myObjectBag.add(int2);
myObjectBag.add(int3);
myObjectBag.remove(int2);
ObjectBag.printBag(myObjectBag);
/* using my generic bag ***********************************************/
System.out.println("using generic bag");
// Bonus Question: using object like above causes error at add method (why?)
Integer int4 = new Integer(4);
Integer int5 = new Integer(5);
Integer int6 = new Integer(6);
GenericBag<Integer> myGenericBag = new GenericBag<Integer>(3);
//Bonus Question: using Interface decllaration like above causes error in print bag (why?)
myGenericBag.add(int4);
myGenericBag.add(int5);
myGenericBag.add(int6);
myGenericBag.remove(int4);
GenericBag.printBag(myGenericBag);
}
}
Output:
Hello StackOverFlow!
using my object bag
1
3
using generic bag
5
6
Problems with your ObjectBag that are 'automaticaly' solved by the type safety offered by your GenericBag implementation:
Accessing an entry returns Object, at this stage you do not know of what type Object is.
You can insert any types of Objects (mixed) e.g a String and an Integer into the same list, this is an anti pattern and causes non readable code (try it with your Generics bag!)
Because your compiler knows the type of your GenericBag after you have declared it, at any stage of your code if you hover over your genericBag instance you will know its type, this makes your code more readable and also extendable for other people
Generics also offer way more, imagine you want your GenericBag to only accept numbers, then you could write it as follows:
public class GenericBag<T extends Number>
My suggestion for you is to read some articles on Java basics and especially Generics, having a praxis based way of learning is a good thing, but there are plenty articles that can give you some very nice theoretical insight on the matter.
https://www.baeldung.com/java-generics
Reason of using, let's say, GenericBag<String> over ObjectBag is essentially the same as for using String (or any other type) over an Object:
Type safety.
You declare that some method returns a collection of Strings and nothing else, thus preventing yourself from putting there other objects, or trying to treat what you get from a bag as some other type. This might sound stupid when you have 100 lines of code, but this may save you lot of debugging time when you work with decent codebase.
Although, type safety is not a silver bullet, it is just an instrument, that some people find useful and some don't. I'm pretty sure it is a popular holywar topic for any programming forum.
If you feel comfortable working without this paradigm (Javascript background, right?), you might consider trying some dynamically typed language like Python instead of Java.

How to add List<Future<Object>> into Set<Object>?

during the development of ExecutorService, it became necessary to put List in Set . How can this be done?
public class Executor {
private Set<List<Future<Object>>> primeNumList = Collections.synchronizedSet(new TreeSet<>());
Set<List<Future<Object>>> getPrimeNumList() {
return primeNumList;
}
#SuppressWarnings("unchecked")
public void setup(int min, int max, int threadNum) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
List<Callable<Object>> callableList = new ArrayList<>();
for (int i = 0; i < threadNum; i++) {
callableList.add(new AdderImmediately(min + i, max, threadNum));
}
List<Future<Object>> a = executorService.invokeAll(callableList);
primeNumList.add(a); // here i try to add Future list into Set
System.out.println(primeNumList);
executorService.shutdown();
}
My class in which I process the values ​​and return them via call (). After that they fall into the List from where I want them to be placed in the final Set
public class AdderImmediately implements Callable {
private int minRange;
private int maxRange;
private Set<Integer> primeNumberList = new TreeSet<>();
private int step;
AdderImmediately(int minRange, int maxRange, int step) {
this.minRange = minRange;
this.maxRange = maxRange;
this.step = step;
}
#Override
public Object call() {
fillPrimeNumberList(primeNumberList);
return primeNumberList;
}
private void fillPrimeNumberList(Set<Integer> primeNumberList) {
for (int i = minRange; i <= maxRange; i += step) {
if (PrimeChecker.isPrimeNumber(i)) {
primeNumberList.add(i);
}
}
}
}
Is it somehow possible to implement? Because what I have now, I get a ClassCastException. Or am I not understanding something?)
Exception:
Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1294)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
at java.util.Collections$SynchronizedCollection.add(Collections.java:2035)
at Executor.setup(Executor.java:22)
at Demo.main(Demo.java:47)
You are not able to catch the error at compile time because you have used #SuppressWarnings("unchecked"). On removing that, there's a compile warning at this statement: callableList.add(new AdderImmediately(min + i, max, threadNum));
The second problem is, you haven't used generic form while creating AdderImmediately class. You are clearly returning, Set<Integer> type from the call method. If you use the proper generic form in your case, i.e., Callable<Set<Integer>>, the problem becomes clear in the above line. The type of callableList is List<Callable<Object>>. You cannot add an element of type Callable<Set<Integer>> into it.
Because you had added the elements of incorrect type by suppressing generic warnings, you are getting ClassCastException at runtime.
I'd recommend you to read the chapters on Generics from Effective Java 3rd edition to better understand these concepts.

How do I return a Number object of the same concrete type as one passed in?

I have the following incomplete class. It implements a method that takes any Number object as a parameter and constrains it to a limit stored in a long and then returns the original value or the constrained value. However, the returned constrained value must be of the same concrete type as the input parameter.
public class Max implements Constraint {
long max;
public Number constrain(Number n) {
if (n.longValue() <= max) {
return n;
}
// return a number of the type passed in with value max
}
}
There are other questions about creating an object of the same type as another, but the answers assume a no-arg constructor is available and this is not the case for the numeric types.
I have played with:
n.getClass().getConstructor(new Class<?>[] { n.getClass() }).newInstance(max);
but I still have issues about passing in the right parameter even here. I am back to square one. In any case, it isn't very elegant.
I know I can do it with a lot of if statements, but I am looking for something smarter.
Because the constuctor of SubClasses of Number takes primitives as parameter, you cannot look for the constructore that has the Wrapper Class as parameter
The constructor that they all have, is the String one
long max;
public Number constrain(Number n) {
if (n.longValue() <= max)
try{
return n.getClass()
.getConstructor(String.class)
.newInstance(String.valueOf(max));
}catch(Exception ex){ex.printStackTrace();}
return n;
}
public static void main(String[]args){
Max m = new Max();
m.max = 10;
System.out.println(m.constrain(new Double(25)).getClass()); // class java.lang.Double
System.out.println(m.constrain((int) 18).getClass()); // class java.lang.Integer
}
Working DEMO
with Java 5 or hogher you can use a generic in your methods like this
package test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Assert;
public class Max {
Number max;
public <T extends Number> T constrain(T n) {
if (n.floatValue() <= max.floatValue()) {
return n;
} else {
return castTo(max, n.getClass());
}
}
#SuppressWarnings("unchecked")
private <T extends Number> T castTo(Number max2, Class<? extends Number> class1) {
if (class1.equals(AtomicInteger.class)) {
return (T) new AtomicInteger(max2.intValue());
} else if (class1.equals(AtomicLong.class)) {
return (T) new AtomicLong(max2.longValue());
// these case are dangerous to handle
} else if (class1.equals(BigDecimal.class)) {
return (T) BigDecimal.valueOf(max2.doubleValue());
} else if (class1.equals(BigInteger.class)) {
return (T) BigInteger.valueOf(max2.longValue());
// Std Case
} else if (class1.equals(Byte.class)) {
return (T) (Byte) max2.byteValue();
} else if (class1.equals(Double.class)) {
return (T) (Double) max2.doubleValue();
} else if (class1.equals(Float.class)) {
return (T) (Float) max2.floatValue();
} else if (class1.equals(Integer.class)) {
return (T) (Integer) max2.intValue();
} else if (class1.equals(Long.class)) {
return (T) (Long) max2.longValue();
} else if (class1.equals(Short.class)) {
return (T) (Short) max2.shortValue();
} else {
throw new IllegalArgumentException("Can't handle this kind of Number : " + class1.getName());
}
}
public static void main(String[] args) {
Max max = new Max();
max.max = 32;
Integer constrain = max.constrain(33);
Assert.assertEquals(Integer.class, constrain.getClass());
Assert.assertEquals(max.max, constrain);
Double constrain2 = max.constrain(33d);
Assert.assertEquals(Double.class, constrain2.getClass());
Assert.assertEquals(max.max.doubleValue(), constrain2, 0);
Float constrain3 = max.constrain(33f);
Assert.assertEquals(Float.class, constrain3.getClass());
Assert.assertEquals(max.max.floatValue(), constrain3, 0);
Short constrain4 = max.constrain((short) 33);
Assert.assertEquals(Short.class, constrain4.getClass());
Assert.assertEquals(max.max.shortValue(), constrain4, 0);
Byte constrain5 = max.constrain((byte) 33);
Assert.assertEquals(Byte.class, constrain5.getClass());
Assert.assertEquals(max.max.byteValue(), constrain5, 0);
Long constrain6 = max.constrain(33l);
Assert.assertEquals(Long.class, constrain6.getClass());
Assert.assertEquals(max.max.longValue(), constrain6, 0);
BigDecimal constrain7 = max.constrain(BigDecimal.valueOf(33));
Assert.assertEquals(BigDecimal.class, constrain7.getClass());
BigInteger constrain8 = max.constrain(BigInteger.valueOf(33));
Assert.assertEquals(BigInteger.class, constrain8.getClass());
AtomicInteger constrain9 = max.constrain(new AtomicInteger(33));
Assert.assertEquals(AtomicInteger.class, constrain9.getClass());
AtomicLong constrain10 = max.constrain(new AtomicLong(33));
Assert.assertEquals(AtomicLong.class, constrain10.getClass());
}
}
but inside your code to construct all child of number there no common constructor the safest way is to reduce the case you want handle here i didn't handle all Striped64 children
I discovered:
import org.apache.commons.beanutils.ConvertUtils;
...
return (Number)ConvertUtils.convert(max, n.getClass());
I haven't looked at the source, but I doubt it is very clever inside. I believe it just hosts a collection of type converters.
So this is an alternative - not better than the other answers, but at least it is concise.
Edit - v3 - without String.
If you only talk about members of Numbers that allows primitive type as the input of constructor like Float/Double/Integer/Long/..., the following could work:
//Number n is valid someInput;
//Note this only works for Classes that take a single numeric value as input
Class type = (Class) n.getClass().getDeclaredField("TYPE").get(n);
return n.getClass().getConstructor(type).newInstance(max)
Things like BigInteger will not work with this one.
Edit - v2
It seems like, for primitive types n, if the "Number n" is replaced by different signatures and by using Integer.TYPE (or Float.TYPE and etc.) you might pass in the 'int' as parameters of getConstructor. You may use n.TYPE here (but as a reminder TYPE is the class member, and it may pop some warning).
n.getClass().getConstructor(n.TYPE).newInstance(max);
Still, as #azro pointed out: if you insist not using string and want it smart, you still need branches and it could be nastier: you need to consider all subclasses of Number, including BigInteger.
True, casting it to string is nasty, but otherwise, you may need to wrap each subclass of Number with an extra class that allows the non-primitive type as args of the constructor. I barely think if-statements is nastier.
Original Answer
I am not very familiar with Reflection.
But a major problem here is the constructor of Numbers are either String or primitive types like 'int', and you cannot really utilize 'int' as the input of getConstructor.
at least, the following may work.
//assume n is some Number object.
n.getClass().getConstructor(String.class).newInstance(max.toString());
This works as classes like Float/Integer/BigInt.../ have constructors that take String as the input.

Passing the method to method

I have a method which uses Deque. In 1 place, sometimes I want to Deque.pullFirst() and sometimes Deque.pullLast(). It should depend on one of the arguments passed to the method. How do this with Java 8?
This is my try with Callable I know that it doesn't work but now you can understand what I want to achieve:
public class AppMain {
public void iterateThroughQueue(Callable callable) { // error
Deque<Integer> deq = new ArrayDeque<>();
deq.add(1);
deq.add(2);
deq.add(3);
for (int i = 0; i < 3; i++) {
System.out.println(callable.apply(deq)); // error!
}
System.out.println("size after iteration = " + deq.size());
}
public static void main(String[] args) {
AppMain.iterateThroughQueue(Deque::pollFirst); // error!
}
}
Method references are either:
Consumer<T>, which means they take a parameter and return nothing. For example System.out::println is a Consumer<String>.
Producer<T>, which means they take no parameter and return something. For example UUID::randomUUID is a Producer<UUID>.
Function<T,Z>, which means they take a parameter of type T (can be the instance on which to apply the method) and return a result of type Z, in your case Deque::pollFirst take is a Function<Deque<Integer>, Integer>. Another example is deq::add where deq is an instance of Deque<Integer> which would be a Function<Integer, Boolean> .
So you should be using Function<Deque<Integer>, Integer> instead of Callable which is for something completely different. Also iterateThroughQueue(...) need to be static.
Callable will not work here, but Function will.
You could try instead this:
public static void iterateThroughQueue(Function<Deque<Integer>, Integer> function) {
Deque<Integer> deq = new ArrayDeque<>();
deq.add(1);
deq.add(2);
deq.add(3);
for (int i = 0; i < 3; i++) {
System.out.println(function.apply(deq));
}
System.out.println("size after iteration = " + deq.size());
}
public static void main(String[] args) {
iterateThroughQueue(Deque::pollFirst);
}
This prints:
1
2
3
size after iteration = 0

Invoking a same method just once in java

I have four different classes classA, classB, classC and classD. All the four classes have the same static method search() which takes two string parameters. If i want to invoke static method search in four different classes from main class at once. How can I do that. For now my code is as follows for main class. I need to execute the same thing for other 3 classes also. How can i do that and display the results of other 3 in the same way as for classA. The way search is done in 4 classes r different but they should give the same result.
Main() {
Object[] zy;
for (String pattern : Read.arrayList) {
List<Integer> results = ClassA.findAll(pattern, dataToSearch);
zy = results.toArray();
for (int i = 0; i < zy.length; i++) {
System.out.println(" Pattern searched " + pattern + " match is found at index : "+ results);
}
}
if (zy.length == 0) {
System.out.println("Nothing matched");
}
}
I strongly recommend you change this to non-static methods. Look how easy and nice is when you will seperate an interface:
public interface Common {
List<Integer> findAll(String pattern, String dataToSearch);
}
public class A implements Common ...
public class B implements Common ...
public class C implements Common ...
public class D implements Common ...
// in main:
List<Common> allYourClasses = new ArrayList<Common>();
allYourClasses.add(new A());
allYourClasses.add(new B());
allYourClasses.add(new C());
allYourClasses.add(new D());
List<Integer> result = new ArrayList<Integer>();
for (Common c : allYourClasses) {
result.addAll(c.findAll(pattern, dataToSearch));
}
1 - You should NOT do this. Avoid static methods. One of the reason being they can not be called without the exact class. A group of classes that implement a simple interfaces will work faster, safer and better in every way
2 - You can (but you shouldn't) do something like this:
for (Class<?> clazz : new Class[] { ClassA.class, ClassB.class,
ClassC.class }) {
Object[] zy = null;
String dataToSearch = "";
String[] arrayList = { "a" };
for (String pattern : arrayList) {
List<Integer> results = findAllForClass(clazz, pattern,
dataToSearch);
zy = results.toArray();
for (int i = 0; i < zy.length; i++) {
System.out.println(" Pattern searched " + pattern
+ " match is found at index : " + results);
}
}
if (zy.length == 0) {
System.out.println("Nothing matched");
}
}
#SuppressWarnings("unchecked")
public static List<Integer> findAllForClass(Class<?> clazz, String pattern,
String dataToSearch) {
List<Integer> list = null;
try {
list = (List<Integer>) clazz.getDeclaredMethod("findAll", String.class,
String.class).invoke(null, pattern, dataToSearch);
} catch (Exception e) {
list = Collections.emptyList();
}
return list;
}
You see the #supresswarning and the try/catch? well, this is a hint: is telling you you this code is at least suspicious. It is in fact unsafe, non well performant, and is a stupid workaround.
(But we all did something like that once in our lives)
I can't really figure out why would anyone do that.
That said, you could have a method taking a Class as a parameter and calling the method explicitly by name (getMethod.../invoke()).
That puts you back in non static world and you can iterate over the classes you want to invoke. (But again, why use statics in the first place?)
Pseudo untested code:
public void invokeStatic(Class clazz, String method, Class<?> paramsTypes[], Object[] params) {
Method method = clazz.getMethod(method, paramsType);
method.invoke(params);
}
If you want to group all of the results together, just keep adding results to your list:
List<Integer> results = ClassA.findAll(pattern, dataToSearch);
results.addAll(ClassB.findAll(pattern, dataToSearch));
// etc.

Categories