Saturday, July 19, 2008

Use the java.util.Comparator and java.lang.Comparable interfaces to affect the sorting of lists and arrays. SCJP 6.0 Mock Exam & Objectives

Section 6: Collections / Generics

* Given a design scenario, determine which collection classes and/or interfaces should be used to properly implement that design, including the use of the Comparable interface.

* Use capabilities in the java.util package to write code to manipulate a list by sorting, performing a binary search, or converting the list to an array. Use capabilities in the java.util package to write code to manipulate an array by sorting, performing a binary search, or converting the array to a list. Use the java.util.Comparator and java.lang.Comparable interfaces to affect the sorting of lists and arrays. Furthermore, recognize the effect of the "natural ordering" of primitive wrapper classes and java.lang.String on sorting.

-SCJP Exam Objectives


Which of the following interfaces provides a natural comparison method for implementing types?

a) java.util.Comparable
b) java.util.Comparator
c) java.lang.Comparable
d) java.lang.Comparator

Option c), java.lang.Comparable, is correct.

According to the Java 6 API JavaDoc, "The java.lang.Comparable interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method."

The Comparator interface is located in the java.util package. The comparator interface is used to impose ordering on a collection of objects that is different from the natural ordering you might obtain from java.lang.Comparable interface.

Which two abstract methods are defined by the Comparator interface?

a) boolean compare(T o1, T o2)
b) boolean equals(Object obj)
c) boolean compareTo(T o)
d) int compare(T o1, T o2)
e) int equals(Object obj)
f) int compareTo(T o)

Options b) and d) are correct for this answer.

The java.util.Comparator interface defines an equals method that returns a boolean value, and a compare method that returns an int value.

The java.lang.Comparable interface is the one that defines the compareTo method that returns an int value.

For both the compare and the compareTo methods of the Comparator and Comparable interfaces return an int value. A negative value indicates that the first argument passed to the method is, when being ordered in a list, less than the second argument passed. A zero value indicates that the two types passed in as arguments are equal to each other, and the positive value indicates that the first value passed into the method is, when being ordered, greater than the second argument passed into the method.

It is interesting to note that the Comparator interface defines a .equals method. Why is this interesting? Well, becuase it seems redundant, as you can't create an object in Java that doesn't already inherit a fully functional equals method from its parent class. Of course, the makers of Java 6 were fully aware of this. But the mention of the .equals method wasn't an oversight, but instead, was an attempt to emphasize the following poing:

"
Note that it is always safe not to override Object.equals(Object). However, overriding this method may, in some cases, improve performance by allowing programs to determine that two distinct comparators impose the same order. " -JavaDoc equals Comparator Interface

When two objects are being compared through the pertinent method of the Comparator interface, a negative return value idicates:

a) a processing error in performing the comparison
b) the first argument is greater than the second
c) the second argument is greater than the first
d) the two arguments are equal when being compared

Option c) is the correct answer.

The compareTo method takes two objects as parameters. If the first object is less than the second parameter, then a negative result is returned. This is the same as saying the second argument is greater than the first, as is stated by option c) in the answer.

When the opposite is true, a positive result is returned, and when the two objects passed to the Comparator's compareTo method are equal, a zero value is returned.


Which method is defined by the Comparable interface?

a) boolean compare(T o1, T o2)
b) boolean compareTo(T o1, T o2)
c) int compareTo(T o1, T o2)
d) int compareTo(T o)
e) int equals(Object obj)
f) boolean equals(Object obj)


Option d) is the correct anwer.

The java.lang.Comparable interface defines only one method that needs to be implemented, compareTo(T o), making option d) correct.

This method must be implemented in order for collection classes to be able to sort a collection of these object types according to a natural, logical ordering.

The Comparator interface defines the abstract int compare and boolean equals methods.

#########################################################

What would be the result of an attempt to run and compile the following code?


import java.util.*;
public class BeyondCompare {
public static void main (String args[]) throws Exception {
List players = new Vector(3);

players.add(new Player(01, 99, "Wayne"));
players.add(new Player(03, 07, "Tim"));
players.add(new Player(02, 88, "Mario"));

for (Player p : players) System.out.print( p.name() + " ");

}

}


class Player extends Object implements Comparator {

int id, number; String name;

Player(int id, int number, String name) {
this.id = id; this.number=number;
}

public int compareTo(Player p) {
return this.id - p.id;
}

public int compare(Player p1, Player p2) {
return p2.number - p1.number;
}

}

a) The code would not compile
b) The code would compile but not run
c) The code would print out Wayne Mario Tim
d) The code would print out Tim Mario Wayne
e) The code would print out Mario Tim Wayne

Option a) is correct.

The variable name is using method notation, and as a result, the compiler will attempt to link to a method called name() in the Player class, which does not exist. As a result, the code will not compile.

p.name() should be p.name

#################################################

What would be the result of running and compiling the following code?

import java.util.*;
public class BeyondCompare {
public static void main (String args[]) throws Exception {

List players = new Vector(3);

players.add(new Player(01, 99, "Wayne"));
players.add(new Player(03, 07, "Tim"));
players.add(new Player(02, 88, "Mario"));

for (Player p : players) System.out.print( p.name + " ");

}

}


class Player extends Object implements Comparable, Comparator {

int id, number; String name;

Player(int id, int number, String name) {
this.id = id; this.number=number; this.name=name;
}

public int compareTo(Player p) {
return this.id - p.id;
}

public int compare(Player p1, Player p2) {
return p2.number - p1.number;
}

}

a) The code would not compile
b) The code would compile but not run
c) The code would print out Tim Mario Wayne
d) The code would print out Wayne Mario Tim
e) The code would print out Mario Tim Wayne
f) The code would print out Wayne Tim Mario

Option f) is correct.

While the Player class implements the Comparable interface, and provides a compareTo method that would sort on the id of the player, the fact is, the List or Vector was never actually sorted, and as such, no sorting was performed, so the elements placed into the vector will be sorted in the exact same order in which elements were added, which produces an output of Wayne Tim Mario

####################################################


What line of code, placed immediately before the enhanced for:each loop, would generate the output of Wayne Tim Mario?

import java.util.*;
public class BeyondCompare {
public static void main (String args[]) throws Exception {
List players = new Vector(3);

players.add(new Player(01, 99, "Wayne"));
players.add(new Player(03, 07, "Tim"));
players.add(new Player(02, 88, "Mario"));


/* Place Code Here */

for (Player p : players) System.out.print( p.name + " ");

}

}


class Player extends Object implements Comparable, Comparator {

int id, number; String name;

Player(int id, int number, String name) {
this.id = id; this.number=number; this.name=name;
}

public int compareTo(Player p) {
return p.id - this.id;
}

public int compare(Player p1, Player p2) {
return p2.number - p1.number;
}

}


a) players.sort();
b) Arrays.sort(players);
c) Vector.sort(players);
d) Collections.sort(players);

Option d) is correct.

The player class does not define or inherit any sort method, so this options is just plain wrong.

The java.util.Arrays class does define a sort method, but it requires an array as a parameter, not a Vector or a List, as we have in this example.

"Arrays:
static void
sort(Object[] a)
Sorts the specified array of objects into ascending order, according to the natural ordering
of its elements."
- sort method of java.util.Arrays class

Vector does not have a static sort method, so option c) is incorrect.

The Collections class does indeed have a sort method, and when passed any class that implements the List interface, it will sort those classes according to their "natural order." For a class such as the Player class, or any class that implements the Comparable interface, the natural order is determined by the ordering results of the compareTo method.

With the Player class, the compareTo method orders players according to their jersey number, from lowest to highest, making the output Tim Mario Wayne, whose jersey numbers are 7, 88 and 99 respectively.



What would be the result of attempting to compile and run the following code?

import java.util.*;
public class BeyondCompare {
public static void main (String args[]) throws Exception {
List players = new Vector(3);

players.add(new Player(01, 99, "Wayne"));
players.add(new Player(03, 07, "Tim"));
players.add(new Player(02, 88, "Mario"));


Collections.sort(players);

for (Player p : players) System.out.print( p.name + " ");

}

}


class Player extends Object implements Comparator {

int id, number; String name;

Player(int id, int number, String name) {
this.id = id; this.number=number; this.name=name;
}

public int compareTo(Player p) {
return p.id - this.id;
}

public int compare(Player p1, Player p2) {
return p2.number - p1.number;
}

}


a) The code would not compile
b) The code would compile but not run
c) The code would print out Tim Mario Wayne
d) The code would print out Wayne Mario Tim
e) The code would print out Mario Tim Wayne
f) The code would print out Wayne Tim Mario

Option a) is correct.

In this case, the Player class is not implementing the Comparable interface, so when the compiler sees the call to Collections.sort(players), it realizes that the Vector of players cannot have its various elements compared, and as such, the compiler chokes and a compiled class file cannot be generated.

Note that the Player class does contain the compareTo method, as required by the Comparable interface. However, if the class does not explicitly state that it implements the Comparable interface, it cannot be used by any methods that require an instance of type Comparable, as is the case with the Collections and Arrays sort methods.



What would be the result of attempting to compile and run the following code?

import java.util.*;
public class BeyondCompare {
public static void main (String args[]) throws Exception {
List players = new Vector(3);

players.add(new Player(01, 99, "Wayne"));
players.add(new Player(03, 07, "Tim"));
players.add(new Player(02, 88, "Mario"));


Collections.sort(players, new Player());

for (Player p : players) System.out.print( p.name + " ");

}

}


class Player extends Object implements Comparator {

int id, number; String name;


Player(int id, int number, String name) {
this.id = id; this.number=number; this.name=name;
}

public int compareTo(Player p) {
return p.id - this.id;
}

public int compare(Player p1, Player p2) {
return p2.number - p1.number;
}

}


a) The code would not compile
b) The code would compile but not run
c) The code would print out Tim Mario Wayne
d) The code would print out Wayne Mario Tim
e) The code would print out Mario Tim Wayne
f) The code would print out Wayne Tim Mario

Option a) is correct.

This is clearly a bit of misdirection, getting you to concentrate on the comparison aspect of this code, but tat is not what's wrong with the code. The line of code Collections.sort(players, new Player()); fails to compile due to the fact that the default constructor of the Player class is not available. Every class that extends Object has an implicit, default, constructor. But, if a non-defualt exists in a class, as it does in the Player class, the default constructor is no longer implicitly available. So, the call to new Player() causes a compile error.

Exam Objectives
Section 1: Declarations, Initialization and Scoping

Given a set of classes and superclasses, develop constructors for one or more of the classes. Given a class declaration, determine if a default constructor will be created, and if so, determine the behavior of that constructor. Given a nested or non-nested class listing, write code to instantiate the class. - SCJP Exam Objectives


Which line of code, placed immediately before the enhanced for:each loop in the main method, would generate the output of Wayne Mario Tim?

import java.util.*;
public class BeyondCompare {
public static void main (String args[]) throws Exception {
List players = new Vector(3);

players.add(new Player(01, 99, "Wayne"));
players.add(new Player(03, 07, "Tim"));
players.add(new Player(02, 88, "Mario"));


/* Place Code Here */

for (Player p : players) System.out.print( p.name + " ");

}

}


class Player extends Object implements Comparable, Comparator {

int id, number; String name;


Player(int id, int number, String name) {
this.id = id; this.number=number; this.name=name;
}

public int compareTo(Player p) {
return p.id - this.id;
}

public int compare(Player p1, Player p2) {
return p2.number - p1.number;
}

}


a) Collections.sort(players, new Player());
b) Collections.sort(players);
c) Collections.sort(players, new Player(01, 01, 01));
d) Collections.sort(players, new Player(0, 0, null));

Option d) is correct.

Option a) will not compile, as the default constructor, Player(), is not available in the Player class.

Option b) will allow the code to compile, but the sorting will occur according to the natural ordering of the class, which is produced by ordering the elements of the list according to the compareTo method, which is required by any class implementing the Comparable interface. However, the Comparable interface would sort the list of Players according to their ids, generating output of Wayne Mario Tim.

Option c) would not compile, as there is no constructor for the Player class that takes three integer types as parameters.

Option d) will not only compile, but will also sort the Players according to their jersey numbers, generating an output of Tim Mario Wayne.

#########################################################

What code snippet, placed immediately before the enhanced for:each loop in the main method, would sort the Player names alphabetically?

a)
Collections.sort(players,
new Comparator() {
public int compare (Player p1, Player p2)
{ return p1.name.compareTo(p2.name) ;}
}
);

b)

Collections.sort(players, new String());

c)
Collections.sort(players,
new Comparator() {
public int compare (Player p1, Player p2)
{ return p1.name.compareTo(p2.name) ;}
}
);

d)
Collections.sort(
Collections.sort(players, new Player(0, 0, new String()));

Option c) is correct.

##################################################

What would be the result of attempting to compile and run the following code?

import java.util.*;

public class SCJPSorts {

public static void main (String args[]) {

int first = 5; char second = '8';
byte third = 2; short fourth = 3;

Object[] araise = {first, second, third, fourth};

for (int i=0;i lt; araise.length; i++)
System.out.print(araise[i] + " ");
}
}

a) The code would not compile
b) The code would compile but not run
c) The code would print out 0 1 2 3
d) The code would print out 3 2 1 0
e) The code would print out 2 3 5 8
f) The code would print out 8 5 3 2
g) The code would print out 5 8 2 3
h) The code would print out 3 2 8 5


Option a) is correct.

This code looks good, but the loop invokes the size() method of the array. The number of elements in an array is determined by the length property, not the size() method. Collection classes such as a List or a Vector support a call to size(), but an array does not, so this code will fail at the compilation stage.

If the length property of the array was used, the values would be printed out in the same order in which they were added to the array, which would be 5 8 2 3

#############################################################

What would be the result of attempting to compile and run the following code?

import java.util.*;

public class SCJPSorts {

public static void main (String args[]) {

int first = 5; char second = '8';
byte third = 2; short fourth = 3;

Object[] araise = {first, second, third, fourth};

Arrays.sort(araise);

for (int i=0;i<araise.length; i++)
System.out.print(araise[i] + " ");
}
}



a) The code would not compile
b) The code would compile but not run
c) The code would print out 0 1 2 3
d) The code would print out 3 2 1 0
e) The code would print out 2 3 5 8
f) The code would print out 8 5 3 2
g) The code would print out 5 8 2 3
h) The code would print out 3 2 8 5

Option b) is correct. This code will compile, but it will not run.

When objects are sorted using the Collections.sort() or the Arrays.sort() method call, elements in the collection are sorted in their natural order. However, all of the elements of the array must be comparable to one another. In this case, the second element, a Character, is not sortable against the first element, an Integer, and the following ClassCastException occurs:

Exception in thread "main" java.lang.ClassCastException: java.lang.Character can
not be cast to java.lang.Integer
at java.lang.Integer.compareTo(Integer.java:35)
at java.util.Arrays.mergeSort(Arrays.java:1144)
at java.util.Arrays.sort(Arrays.java:1079)
at SCJPSorts.main(SCJPSorts.java:14)



##########################################################

What would be the result of attempting to compile and run the following code?

import java.util.*;

public class SCJPSorts {

public static void main (String args[]) {

int first = 5; int second = 8;
int third = 2; int fourth = 3;

Object[] araise = {first, second, third, fourth};

Arrays.sort(araise);

for (int i=0;i@lt;araise.length; i++)
System.out.print(araise[i] + " ");
}
}

a) The code would not compile
b) The code would compile but not run
c) The code would print out 0 1 2 3
d) The code would print out 3 2 1 0
e) The code would print out 2 3 5 8
f) The code would print out 8 5 3 2
g) The code would print out 5 8 2 3
h) The code would print out 3 2 8 5


Option e) is correct.

When this code runs, the array is sorted using the call to the java.util.Arrays' sort method. This sorts the elements in the array in their natural order, which for Integer types would be from lowest to highest, producing an output of 2 3 5 8.

######################################################

Which of the following classes implement the Comparable interface?

a) String
b) Integer
c) Float
d) Character
e) java.util.Date
f) java.io.File
g) Object

Options a) b) c) d) e) and f) are correct.

The only class here that does not explicitly implement the Comparable interface is the java.lang.Object.

Remember though, just because classes implement the Comparable interface, doesn't mean those objects can necessarily be compated to oneanother. A Character and a File both implement the Comparable interface, but attempting to compare the two different types together would result in a ClassCastException.


No comments: