Solved

How do I change this parameter type?

Posted on 2011-09-22
19
260 Views
Last Modified: 2012-05-12
is there a way to make this program use CaseInsensitiveCompare<T> cmp as the second parameter in line 9 of the code below? It seems like my compare method won't work in line 10 if I change the parameter. Does my second parameter in findMax have to be Comparator<T> cmp?
import java.util.Comparator;

public class FunctionObject {
    public static void main(String[] args) {
      String [] arr = {"zebra", "alligator"};
      System.out.println(findMax(arr, new CaseInsensitiveCompare()));
    }

    public static <T> T findMax(T [] arr, Comparator<T> cmp){
        if(cmp.compare(arr[1], arr[0]) > 0)
            return arr[1];
        return arr[0];}
}

class CaseInsensitiveCompare implements Comparator<String>{
   public int compare(String lhs, String rhs){
      return lhs.compareToIgnoreCase(rhs);}
}

Open in new window

0
Comment
Question by:shampouya
  • 9
  • 7
  • 3
19 Comments
 
LVL 47

Expert Comment

by:for_yan
ID: 36583256
Your compare method would not work as
method
compareToIgnoreCase
is defined only for String, so it wil complain - makes sense

If you define some your own interface which
implements thios method and say <T extends thisIntrfaceName>
then it shoudl work
0
 

Author Comment

by:shampouya
ID: 36583338
So once I define my own interface, then my method would work like this?

public static <T> T findMax(T [] arr, CaseInsensitiveCompare <T extends myInterface> cmp) {}
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36583373
It will work, but the poroblem will be that you will not be able to
apply it to use it with String directly like that
System.out.println(findMax(arr, new CaseInsensitiveCompare<String>()));

because compiler does not know that String implements MyInterface
so you'll have to package your Strings in some custom wrapper class
which you'll declare will implement MyInterface

So it is probably leave it as it is, not to make the situation too complicated

0
 

Author Comment

by:shampouya
ID: 36583390
Ok, and is there a simple way to make this program capable of comparing two integers or two strings?
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36583469
This one works as you want:

import java.util.Comparator;

class CaseInsensitiveCompare<AnyType extends MyInterface<AnyType>> implements Comparator<AnyType>
{
   public int compare(AnyType lhs, AnyType rhs){
      // return 1;
      return lhs.compareToIgnoreCase(rhs);
   }
}

class TestProgram
{
   public static void main(String [] args){
      MyClass [] arr = {new MyClass("ZEBRA"), new MyClass("alligator"), new MyClass("crocodile")};


	  System.out.println(findMax(arr, new CaseInsensitiveCompare<MyClass> ()));
	}

    public static <AnyType extends MyInterface<AnyType>> AnyType findMax(AnyType [] arr, CaseInsensitiveCompare <AnyType> cmp)
    {
       int maxIndex = 0;

	   for(int i = 1; i < arr.length; i++){
	      if(cmp.compare(arr[i], arr[maxIndex]) > 0){
	         maxIndex = i;
	      }
		  }
	   return arr[maxIndex];
   }
}

interface MyInterface<T> {

    int compareToIgnoreCase(T o);
}




class MyClass implements MyInterface<MyClass>{
    String s;
    MyClass(String s){
        this.s = s;
    }

   public   int compareToIgnoreCase(MyClass c){
          return s.compareToIgnoreCase(c.toString());

      }


    public String toString(){
        return s;
    }
}

Open in new window


Output:

ZEBRA

Open in new window

0
 
LVL 47

Expert Comment

by:for_yan
ID: 36583604
I think the program  its original from (befire MyInterface) if you change compareToIgnoreCase()
to compareTo() then it will wotk for both String and Integer
but with CompareToIgnoreCase() it cannot work as Integer does not implement this method
0
 

Author Comment

by:shampouya
ID: 36583696
Oh ok, do you have the code in its original form so that it would accept String and Integer, without MyInterface?
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36583857
This is how it works.
At the time when you call generic method you should
replace the generic type with the actual one;
that's the point of generic methods -
you can comment out either forst pair of lines or the second -
it will work in both cases,
but if you have geneice class
CaseInsensitiveCompare
then at the type when you instatiate thos generic
calss you need to specify actula type
in the place of the generic

Still in one place of your code you may use this method
for Strings in another you may use this method
for Integers - that's why it is code reuse


import java.util.Comparator;

public class TestProgram {
    public static void main(String[] args) {
   //   String [] arr = {"zebra", "alligator","tttt","zubra"};
     //    System.out.println(findMax(arr, new CaseInsensitiveCompare<String>()));
          Integer [] arr = {2, 3, 1, 8};
      System.out.println(findMax(arr, new CaseInsensitiveCompare<Integer>()));
    }

    public static <T> T findMax(T [] arr, Comparator<T> cmp){
       int maxIndex = 0;

	   for(int i = 1; i < arr.length; i++){
	      if(cmp.compare(arr[i], arr[maxIndex]) > 0){
	         maxIndex = i;
	      }
		  }
	   return arr[maxIndex];
   }
}

class CaseInsensitiveCompare<T> implements Comparator<T>{
   public int compare(T lhs, T rhs){
       if(lhs instanceof String){
           String s = (String) lhs;


      return s.compareTo((String)rhs);}
       else
             if(lhs instanceof Integer){
                 Integer i = (Integer) lhs;
 

                 return i.compareTo((Integer)rhs);
       }
         return 0;  
   }
}

Open in new window



Output - either "zubra" or 8 dependning on which lines you comment out
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36583946
This is another variant which also works and takes advantage of the fact
that standard (provided by Java standard library) interface Comparable<T> defines method int compareTo(T o)

Still when you call the method for execution - generic type should be resolved

import java.util.Comparator;

class CaseInsensitiveCompare<AnyType extends Comparable<AnyType>> implements Comparator<AnyType>
{
   public int compare(AnyType lhs, AnyType rhs){
    
       
      return lhs.compareTo(rhs);
   }
}

class TestProgram
{
   public static void main(String [] args){
     String [] arr = {"zebra","alligator","crocodile"};
      System.out.println(findMax(arr, new CaseInsensitiveCompare<String>()));

      //  Integer [] arr = {new Integer(3), new Integer(2), new Integer(5)};
      //  System.out.println(findMax(arr, new CaseInsensitiveCompare<Integer>()));




	}

    public static <AnyType extends Comparable<AnyType>> AnyType findMax(AnyType [] arr, CaseInsensitiveCompare <AnyType> cmp)
    {
       int maxIndex = 0;

	   for(int i = 1; i < arr.length; i++){
	      if(cmp.compare(arr[i], arr[maxIndex]) > 0){
	         maxIndex = i;
	      }
		  }
	   return arr[maxIndex];
   }
}

Open in new window

0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 10

Expert Comment

by:gordon_vt02
ID: 36586821
Your original program should work as designed.  Your Comparator is designed to work purely with Strings, so its completely legal to use compareToIgnoreCase().  Your main method is passing a String Array into the findMax() method, which should pick up String for the type T.

I just compiled your original code and it is returning what it should: "zebra"
0
 
LVL 10

Expert Comment

by:gordon_vt02
ID: 36586860
A better solution, that will work with any size array might be something like below.  Keep in mind though that this will modify the ordering of the initial array, so you might want to copy it first if ordering is important.
import java.util.Arrays;

public static <T> T findMax(T[] array, Comparator<T> cmp) {
    // no elements, return null
    if (array == null || array.length == 0)
        return null;

    // only one element, return it
    if (array.length == 1)
        return array[0];

    // copy array to prevent modification of original
    T[] copy = Arrays.copyOf(array, array.length);
    // sort array according to comparator
    Arrays.sort(copy, cmp);
    // max element is last element in array
    return copy[copy.length-1];
}

Open in new window

0
 
LVL 10

Expert Comment

by:gordon_vt02
ID: 36586866
Ignore my comment about modifying the original array -- I added the Arrays.copyOf() method to the code to prevent that modification.
0
 

Author Comment

by:shampouya
ID: 36590927
Ok, I would like to take line 11 and line 17 of my code below and translate it into simple English word by word. Can you tell me if this is correct?

11.  public static <T> T findMax(T [] arr, Comparator<T> cmp){

public: everything in this class has access to this method
static: this method can't be used through an object
<T>: allow the generic type T to exist and be used in this method
T: this method will return the generic type T
findMax: this is the name of the method
T [ ] arr: allow an array of generic type T to be passed as the first argument
Comparator<T> cmp: allow any class that implements Comparable T to be passed as the 2nd argument

17. class CaseInsensitiveCompare<T extends Comparable<T>> implements Comparator<T>{

class CaseInsensitiveCompare: this is the name of this generic class
<T extends Comparable<T>>: allow the the generic type T to be used in this class and allow it to inherit the properties of the Comparable class
implements Comparator<T>: allow the class to use the compare method of the Comparator interface after it implements the method in its own way
import java.util.Comparator;

public class FunctionObject {
    public static void main(String[] args) {
      String [] arr = {"zebra", "alligator"};
      Integer [] newArr = {new Integer(3), new Integer(9)};
      System.out.println(findMax(arr, new CaseInsensitiveCompare()));
      System.out.println(findMax(newArr, new CaseInsensitiveCompare()));
    }

    public static <T> T findMax(T [] arr, Comparator<T> cmp){
        if(cmp.compare(arr[1], arr[0]) > 0)
            return arr[1];
        return arr[0];}
}

class CaseInsensitiveCompare<T extends Comparable<T>> implements Comparator<T>{
   public int compare(T input1, T input2){
      return input1.compareTo(input2);
}
}

Open in new window

0
 
LVL 47

Expert Comment

by:for_yan
ID: 36590968
These are the lines which need some (soemtimes minor) changes to mymind
-------------
public - means it can be accessed from OUTSIDE of the class

static - means that this method is specific not to the instance of the class, but rather to the class itself, and can be accessed through classname

 Comparator<T> cmp: allow any class that implements ComparATOR T to be passed as the 2nd argument

<T extends Comparable<T>>: allow the the generic type T to be used in this class and allow it to inherit the properties of the Comparable T
 class

implements Comparator<T>: allow the class to use the compare method of the Comparator T interface after it implements the method in its own way
-------------------

and of course this contents of the method with indexes zero and one is incorrect and
confusing
      if(cmp.compare(arr[1], arr[0]) > 0)
            return arr[1];
        return arr[0];}

Open in new window


I replaced it in the code above
0
 

Author Comment

by:shampouya
ID: 36590997
I don't think you made any changes to this, did you?

 if(cmp.compare(arr[1], arr[0]) > 0)
            return arr[1];
        return arr[0];}
0
 
LVL 47

Expert Comment

by:for_yan
ID: 36591013

Of course I returned to general number
- not zero and one - I had long arrays - how would it otherwise work,
see:
ID:36583857
ID:36583946
0
 

Author Comment

by:shampouya
ID: 36591045
What's wrong with the way I did it? I just wanted to make a simple array that held two elements and allowed my program to compare two strings. Is that wrong?
0
 
LVL 47

Accepted Solution

by:
for_yan earned 500 total points
ID: 36591051
It is not wrong for two elemnts, but in order to test it more extensively I added more elements,
so I needed to return to previous code which was for any number of chracters.
All that is not relevant for te story obout types - it is true.
0
 

Author Closing Comment

by:shampouya
ID: 36591065
Thanks
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

After being asked a question last year, I went into one of my moods where I did some research and code just for the fun and learning of it all.  Subsequently, from this journey, I put together this article on "Range Searching Using Visual Basic.NET …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
Viewers will learn about the different types of variables in Java and how to declare them. Decide the type of variable desired: Put the keyword corresponding to the type of variable in front of the variable name: Use the equal sign to assign a v…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

27 Experts available now in Live!

Get 1:1 Help Now