I am getting complie time error if type is Integer for static method.
public static <T> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
then I replaced T everywhere with Integer still no problem.
public static <Integer> int countGreaterThan(Integer[] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
But once I change change Integer to different type Like R compilation error gone.
public static <R> int countGreaterThan(Integer[] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray)
if (e > elem) // no Compilation error
++count;
return count;
}
what is impact of Static method type to this > operator here?
In your case <Integer> is not the type java.lang.Integer but only the name of the type argument and shadows the actual wanted type. At this point, it could as well be <T>, <VAL> or <POTATO>.
In your case this would be equivalent to the following code
public static <POTATO> int countGreaterThan(POTATO[] anArray, POTATO elem) {
int count = 0;
for (POTATO e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
Since POTATO can be any type, the compiler dosen't know how to compare it to another element. The compiler doesn't know how to interpret e > elem.
When you change the type argument to something different than Integer, the code would become
public static <R> int countGreaterThan(Integer[] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray)
if (e > elem)
++count;
return count;
}
Here the type argument doesn't shadow the java.lang.Integer arguments anymore and the compiler knows how to interpret the comparison.
Edit: I posted this answer before your edit, which changed the context of your question.
You are shadowing Integer, the correct generic type to do this is the rather inscrutable T extends Comparable<? super T> like
public static <T extends Comparable<? super T>> int countGreaterThan(T[] anArray,
T elem) {
int count = 0;
for (T e : anArray) {
if (e.compareTo(elem) > 0) {
++count;
}
}
return count;
}
(and please use braces so flow control is clear). Also, if you're using Java 8+, it could be done with a Stream like
long count = Stream.of(anArray).filter(x -> x.compareTo(elem) > 0).count();
What you are doing with <Integer> is declaring a new type and calling it Integer. Note that this is NOT the same as java.lang.Integer, and is thus not eligible for comparing in this way.
By naming your new type R, you are allowing java.lang.Integer to be inferred when declaring variables of type Integer.
Related
Write a Java program to define a generic method that counts the number of elements in an array T [ ] that are greater than a specified element elem.
I have written my code as:
public class GenericMethods<E extends Comparable<E>> {
public static < E > void printArray( E[] inputArray ) {
// Display array elements
for(E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
public static < E > void countArray( E[] inputArray, int elem) {
int i=0;
for(E element : inputArray){
if(elem>element)
i++;
}
System.out.println(i);
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
Integer[] intArray = { 1, 2, 3, 4, 5 };
System.out.println("\nArray contains:");
printArray(intArray);
int elem=0;
System.out.println("Enter the specified number: ");
elem = sc.nextInt();
countArray(intArray, elem);
}
}
I get the following errors:
error: bad operand types for binary operator '>'
if(elem>element)
^
first type: int
second type: E
where E is a type-variable:
E extends Object declared in method countArray(E[],int)
1 error
One way is to require that your generic type parameter E is a Number.
Then you can use Number's intValue() method to convert each element of the array to an int, which can be compared to elem.
public static <E extends Number> void countArray(E[] inputArray, int elem) {
int i = 0;
for (E element : inputArray) {
if(elem > element.intValue ())
i++;
}
System.out.println(i);
}
you cant use > operator on object
you can do as Eran said or ensure E implements Comparable and use compareTo()
<E extends Comparable>
if(element.compareTo(new Integer(elem))<0)
I am stuck figuring out how I may solve this problem. The goal is to find the position of the minimum value of an Iterable (l) without loops. There is a similar problem here: How would I get the minVal without a loop and using only foldLeft?
But this can simply use a lambda. In this case I need to pass a class that implements BiFunction as the third argument to the foldLeft or foldRight call. How would you solve this? I started making a new class that implemented BiFunction, but got lost as to how I determine the position of the minimum value in l.
static <U,V> V foldLeft(V e, Iterable<U>l, BiFunction<V,U,V> f){
//BiFunction takes a U and V and returns a V
V ret = e;
for(U i : l) {
ret = f.apply(ret, i);
}
return ret;
}
static <U,V> V foldRight(V e, Iterable<U>l, BiFunction<U,V,V> f){
for(U u:l) {
e = f.apply(u, e);
}
return e
}
static <U extends Comparable<U>> int minPos(Iterable<U> l){
// write using fold. No other loops permitted.
int value = 0;
return value;
}
UPDATE: I have figured it out
class FindMinPos<U extends Comparable<U>> implements BiFunction<U, U, U> {
public Iterable<U> l;
public ArrayList<U> a = new ArrayList<U>();
public int minPos;
public FindMinPos(Iterable<U> l) {
this.l = l;
for(U i : l) {
a.add(i);
}
}
#Override
public U apply(U u, U u2) {
U minVal = u != null && u.compareTo(u2) <= 0 ? u : u2;
minPos = a.indexOf(minVal);
return minVal;
}
}
static <U extends Comparable<U>> int minPos(Iterable<U> l){
// write using fold. No other loops permitted.
int minPos = 0;
FindMinPos<U> f = new FindMinPos<U>(l);
U minValue = foldLeft(l.iterator().next(), l, f);
minPos = f.minPos;
return minPos;
}
If you fix the return type of minPos() to be consistent with the parameter, then you'd do it with a lambda expression like this:
static <U extends Comparable<U>> U minPos(Iterable<U> coll) {
return foldLeft((U) null, coll, (a, b) -> a != null && a.compareTo(b) <= 0 ? a : b);
}
Here is what I am trying to do :
class MyNumbers<T extends Number>{
private T[] array;
MyNumbers(T[] array){
this.array = array;
}
public void setArray(T[] array){
this.array = array;
}
public T[] getArray(){
return this.array;
}
public double avarage(){
double avg =0.0;
double sum =0.0;
for(T t: array){
sum += t.doubleValue(); // working
sum = sum+ t; // not working
}
return sum/array.length; }
}
As per autoboxing and unboxing rule sum = sum+ t; should work. but not working as T already extending with Number class .
Here is what I trying with following type:
public class BoundedTypeParam{
public static void main(String [] args){
Integer[] ints = {1,2,3,4,5,6};
MyNumbers<Integer> stats4Ints = new MyNumbers<>(ints);
System.out.println("Avg is same : "+ stats4Ints.avarage());
}
}
Any rule/concept that I am missing.
PS. I am aware with reifiable type, erasure
This has nothing to do with generics. It wouldn't work if you replaced T with Number.
There is no unboxing conversion from Number type to some primitive type, so Number cannot be an operand of a numeric operator.
The following code will fail to pass compilation for the exact same reason as your code - The operator += is undefined for the argument type(s) double, Number.
Number n = 5;
double sum = 0.0;
sum += n;
Arrays are not erased, and type coersion does not apply to them at all. double[] is never the same as Double[], and neither of the two coerse to Number[].
By binding type variable like this:
class Example<T extends Number> {
private T[] arr;
}
what you actually have at runtime is:
class com.Example {
private Number[] arr;
}
That in turn means that following code:
for(T t: array) {
<...snip...>
}
is compiled in this code:
for (Number t: array) {
<...snip...>
}
As you can see, there is no information about what type of number it is, and Java does not define any operators that work on Number classes, which evidenced by any library that did a custom Number, or even JDK itself with classes like BigInteger and BigDecimal.
I'm currently working on an assignment with a number of methods with parameters of type Set. In order to use these parameters in my program they have to be converted to arrays, and the conversion has to be done with time complexity no greater than O(N). I'm stumped, as I don't know the type of the set, or any properties at all about it. I can get the size of the set, but that's about it. I am not allowed to use ArrayList, or any other List or Set class. toArray() doesn't work, the compiler says it can't find the symbol. I obviously can't create a generic type array. What do I do now?
Here's a sample of the code. there are 6 more methods with headers similar to it.
public boolean equals(Set<T> s) {
T[] sArray = s.toArray(new T[s.size()]);
My error messages are as follows:
ArraySet.java:241: error: generic array creation
T[] sArray = s.toArray(new T[s.size()]);
^
ArraySet.java:241: error: cannot find symbol
T[] sArray = s.toArray(new T[s.size()]);
^
symbol: method toArray(T[])
location: variable s of type Set<T>
where T is a type-variable:
T extends Comparable<? super T> declared in class ArraySet
Edit: Updated so that ArraySet actually behaves like a Set...
Here's an example of how you could implement your equals(Set<T> s) method. Since not of all ArraySet was included in your question, I've had to assume how your ArraySet will work, and that it supports any reference type (generics).
The equal(Set<T> s) method, simply loops through the array and uses the contains(Object o) method on s. This is O(n) since worst case scenario you loop through all n element of the array. It will continue checking until it finds that it doesn't contain an element or all elements have been checked. Note that the loop won't start if the size() of the Set and the length of the array are not equal.
import java.util.Set;
public class ArraySet<T> {
private T[] array;
private int count;
private final int DEFAULT_CAPACITY = 16;
public ArraySet() {
array = (T[]) new Object[DEFAULT_CAPACITY];
count = 0;
}
public void add(T e) {
if (count < array.length && !contains(e)) {
array[count++] = e;
}
}
public boolean contains(T e) {
boolean hasElement = false;
int i = 0;
while (!hasElement && i < count) {
hasElement = array[i++].equals(e);
}
return hasElement;
}
public boolean equals(Set<T> s) {
boolean isEqual = s.size() == count;
int i = 0;
while (isEqual && i < count) {
isEqual = s.contains(array[i++]);
}
return isEqual;
}
}
Example of using ArraySet's equals(Set<T> s) method:
import java.util.HashSet;
import java.util.Set;
public class ArraySetTest {
public static void main(String[] args) {
Set<String> stringSet = new HashSet<>();
stringSet.add("Foo1");
stringSet.add("Foo2");
ArraySet<String> arraySet = new ArraySet<>();
arraySet.add("Foo1");
arraySet.add("Foo2");
System.out.println(arraySet.equals(stringSet));
}
}
I have written a small list sorter that works by using Key objects to extract specific "keys" from objects in comparable form. The sorter then sorts the list in accordance with all the keys in turn.
The sorter can sort using any set of keys that work on the given types of object. Each key is able to deal with one type of object and always returns the same type of comparable value.
class Sorter {
public interface Key<T, V extends Comparable<V>> {
public V get(T t);
}
static <T> void sort(List<T> data, final Key<T, ?> key[], final int dir[]) {
Collections.sort(list, new Comparator<T>() {
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final Comparable av = key[i].get(a), bv = key[i].get(b);
final int cmp = av.compareTo(bv);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
});
}
}
So, for example, you could have a JSONStringKey that extracts a String (which is Comparable), and you could have a separate JSONNumericKey that extracts a Double) (which is also Comparable). Values from two different keys will never be compared, but the same key across two different objects will be compared.
class JSONStringKey extends Sorter.Key<JSONObject, String> {
final String key;
JSONStringKey(String key) {this.key = key;}
public String get(JSONObject o) {return o.optString(key);}
}
class JSONNumericKey extends Sorter.Key<JSONObject, Double> {
final String key;
JSONNumericKey(String key) {this.key = key;}
public Double get(JSONObject o) {return o.optDouble(key);}
}
...
// sort by price descending then name ascending
final Key<JSONObject, ?> keys[] = { new JSONNumericKey("price"), new JSONStringKey("name") };
sort(list, keys, new int[]{-1, 1});
Java warns about this line in the sorter:
final Comparable av = key[i].get(a), bv = key[i].get(b);
It warns that av and bv are declared with raw types: Comparable instead of Comparable<?>. And they are. But if I change the type to Comparable<?>, then the next line, av.compareTo(bv) fails, because two different Comparable<?> are not necessarily the same type. In my specific implementation, they will be, but I don't know how to express that to the type system.
How can I tell the type system that av and bv have exactly the same type? I can't "fix" it by giving a specific type (e.g. Comparable<String>) because in my example, the first key in the loop returns String (which implements Comparable<String>) and the second key in the loop returns Double (which implements Comparable<Double>).
I could write #SuppressWarnings("rawtypes") on the key[i].get() lines and #SuppressWarnings("unchecked") on the av.compareTo(bv) line, but I want to have the types checked as far as possible.
EDIT: thanks to the answer from davmac, creating an intermediary method that fixes to a specific comparable type works correctly:
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final int cmp = compareKey(key[i], a, b);
if (cmp != 0) return cmp * dir[i];
}
}
private <V extends Comparable<V>> compareKey(Key<T, V> key, T a, T b) {
final V av = key.get(a), bv = key.get(b);
return av.compareTo(bv);
}
You need to use a type parameter to say that two 'unknown' types are the same. I thought that maybe you should change your method signature from:
static <T> void sort(List<T> data, final Key<T, ?> key[], final int dir[])
to
static <T,U> void sort(List<T> data, final Key<T,U> key[], final int dir[])
However, I don't think this would work with your full example, because the elements from the keys are not the same type:
// sort by price descending then name ascending
final Key<JSONObject, ?> keys[] = { new JSONNumericKey("price"), new JSONStringKey("name") };
sort(list, keys, new int[]{-1, 1});
So, instead, you could extract the relevant part from the sorter into a generic method:
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final Comparable<?> av = key[i].get(a), bv = key[i].get(b);
final int cmp = doCompareTo(av, bv);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
private <U extends Comparable<U>> int doCompareTo(U a, U b) {
return a.compareTo(b);
}
... but this wouldn't work either, because a Comparable<U> doesn't necessarily extend U. The problem is that your Keys return Comparable<V>, but you want to compare two of these; that's not possible. A Comparable<V> can be compared with a V, but not with another Comparable<V>.
In general, there are too many issues here to give you a simple solution. You need to re-think the types completely. For instance, if you want the Key's get method to return objects that are comparable with each other, then it should return V and not Comparable<V>.
I hope the suggestions above at least point you in the right direction.
The way you have them declared right now, you can use a private capture helper:
static <T> void sort(List<T> data, final Key<T, ?> key[], final int dir[]) {
Collections.sort(list, new Comparator<T>() {
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final int cmp = compareHelper(key[i], a, b);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
});
}
private static <T, U extends Comparable<U>> int compareHelper(Key<T, U> k, T a, T b) {
U av = k.get(a), bv = k.get(b);
return av.compareTo(bv);
}
Or you can get rid of V from Key altogether and make the constraint on sort only, which will be parameterized on U:
public interface Key<T, V> {
public V get(T t);
}
static <T, U extends Comparable<? super U>> void sort(List<T> data, final Key<T, U> key[], final int dir[]) {
Collections.sort(list, new Comparator<T>() {
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
U av = k.get(a), bv = k.get(b);
final int cmp = av.compareTo(bv);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
});
}