| Articles in this issue :
|
SCJP Tip Line - hashCodes Uncovered
The SCJP Tip Line hashCodes Uncovered by Corey McGlone
In this edition of the JavaRanch Journal SCJP Tipline, author Corey McGlone investigates hashCodes, expanding on an April blog entry.
What is a hashCode?
First of all, what the heck are hashcodes for? Well, oddly enough, they're used heavily in Hashtables. Hashtables, along with the other classes that extend the Map interface, are discussed in this Journal article For the purposes of this article, I'm going to assume you know what a Hashtable is and how useful it can be. Needless to say, Hashtables can help you keep a large number of objects organized and allow you to access them very quickly. Of course, to do so, a Hashtable relies on the power of the hashCode method.
In essence, when you invoke the get(Object o) method of a Hashtable, the Hashtable will use the hashCode method of the object you passed to it in order to access an object (or list of objects). As long as the hashCode method is working properly, everything works just fine. If it doesn't, however, you can have some rather serious problems.
So, what makes a valid hashCode? Well, here's what is said about hashCodes in the API Specification for Object:
The general contract of hashCode is:
- Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
- If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
- It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
Study: A Proper hashCode
Let's start by looking at a good program. In this case, we've defined a new object, MyObject, which defines its own equals and hashCode methods. In general, it is good practice to define your own hashCode method any time you override equals (more about this later). Here it is:
import java.util.Hashtable;
import java.util.Date;
public class MyObject
{
int a;
public MyObject(int val)
{
a = val;
}
public boolean equals(Object o)
{
boolean isEqual = false;
if ( o instanceof MyObject )
{
if ( ((MyObject)o).a == a )
{
isEqual = true;
}
}
return isEqual;
}
public int hashCode()
{
return a;
}
public static void main(String[] args)
{
Hashtable h = new Hashtable();
MyObject[] keys =
{
new MyObject(11),
new MyObject(12),
new MyObject(13),
new MyObject(14),
new MyObject(15),
new MyObject(16),
new MyObject(17),
new MyObject(18),
new MyObject(19),
new MyObject(110)
};
for ( int i = 0; i < 10; i++ )
{
h.put(keys[i], Integer.toString(i+1));
}
long startTime = new Date().getTime();
for ( int i = 0; i < 10; i++ )
{
System.out.println(h.get(keys[i]));
}
long endTime = new Date().getTime();
System.out.println("Elapsed Time: " + (endTime - startTime) + " ms");
}
} |
Executing the above code leaves you with this output:
1
2
3
4
5
6
7
8
9
10
Elapsed Time: 0 ms |
As you can see, we easily retrieved the objects we had originally put into the Hashtable and it took practically no time at all. How does our hashCode method do? Does it pass all 3 of the criteria laid out earlier? Let's look at each of the criteria one at a a time.
1. Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
Does our hashCode meet that criteria? Does our hashCode continually return the same value (assuming that our variable, a, hasn't changed)? Certainly, it does - it returns the value of a. Okay, next criteria.
2. If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
How about this one? Does our hashCode method still work here? Sure, it does. If two object have the same value for a, they will be equal (by the equals method). In such a situation, they would also return the same hashCode value. Our hashCode method works here. Okay, on to the final criteria.
3. It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
Well, this isn't really a requirement at all - it's more of a suggestion, if anything. It is best if the hashCodes for unequal objects are different, but it's not required. We'll look at this a little more in a few minutes.
So, there you have it - we've successfully overridden the hashCode method. So, how do you know when you should do such a thing? Well, in general, it's considered good practice to override hashCode any time you override equals. The reason for this is due to the default behavior of the equals and hashCode methods.
When Should you Override hashCode()?
In Java, the default equals method (as defined in Object) compares the two objects to see if they are, in fact, the same object. That implementation does not take into account any data that might be contained by the object. For example, had we not overridden the equals method in our class, MyObject, we'd see that the following code:
MyObject obj1 = new MyObject(1);
MyObject obj2 = new MyObject(1);
System.out.println(obj1.equals(obj2)); |
...would produce the output "false." The reason for this is that, even though the two objects contain the same data, they are different objects - two separate objects on the heap. Fortunately, we overrode the equals method and, given the MyObject class as defined originally, we'd get the output "true" from this example. However, what about the hashCode?
Well, the default hashCode method works in a similar fashion to the default equals method. It converts the internal address of the object into an int and uses that as the hashCode. Well, that won't work so well here. We just defined a way in which two distinct objects (which will, necessarily, have distinct memory addresses) to be considered "equal." The default hashCode implementation, however, will return different hashCodes for the two objects. That violates the second rule defined above - any objects that are considered equal (by their equals method) must generate the same hashCode value. Therefore, whenever you override the equals method, you should also override the hashCode method.
Study: Faulty hashCodes
What happens if we override the hashCode method poorly? Let's violate one of the rules, shall we? Let's change our hashCode method to look like this:
public int hashCode()
{
return (int)(Math.random() * 5);
} |
This one actually violates a couple rules. Not only does it not guarantee that two objects that are equal have the same hashCode, it doesn't even guarantee that the same object will keep the same hashCode from one invocation to the next. Any idea what havoc this might wreak on a poor, unsuspecting Hashtable? If I execute the main method again, as I did before, I get this output:
null
2
null
4
null
6
null
null
null
null
Elapsed Time: 0 ms |
Eek! Look at all of the objects I'm missing! Without a properly functioning hashCode function, our Hashtable can't do its job. Objects are being put into the Hashtable but we can't properly get at them because our hashCode is random. This is certainly not the way to go. If you were to run this, you might even get different output than I got!
Even if the hashCode that is returned is always the same for a given object, we must ensure that the hashCodes that are returned for two objects that are equal are identical (Rule #2). Let's modify our MyObject class so that we hold true to Rule #1 but not to Rule #2. Below is the modified parts of our class:
public class MyObject
{
int a;
int b;
public MyObject(int val1, int val2)
{
a = val1;
b = val2;
}
...
public int hashCode()
{
return a - b;
}
...
public static void main(String[] args)
{
....
MyObject[] keys =
{
new MyObject(11, 0),
new MyObject(11, 1),
new MyObject(11, 2),
new MyObject(11, 3),
new MyObject(11, 5),
new MyObject(11, 5),
new MyObject(11, 6),
new MyObject(11, 7),
new MyObject(11, 8),
new MyObject(11, 9)
};
...
}
} |
Executing this code gives us some more disturbing results, although they may not appear that way at first. Here's my output:
1
2
3
4
5
6
7
8
9
10
Elapsed Time: 0 ms |
So what's wrong with that, you ask? Well, what should the put method do? If you first put an object into a Hashtable using a specific key and then put a new value into the Hashtable using a key that is equal to that one, the original value should be replaced with this new one. That's not what's happening here. Instead, our Hashtable is treating our keys as if they're all unequal. Eek! This is the same result you could expect if you were to override equals without overriding hashCode. Here's the output we should get, assuming we have a good hashCode method:
10
10
10
10
10
10
10
10
10
10
Elapsed Time: 0 ms |
Inefficient hashCodes
Okay, one more thing to go over. What happens if we have a valid hashCode, but the values aren't very distinct. In this case, I'm going to hold to requirements 1 and 2, but I'm going to ignore requirement 3 entirely. Let's modify MyObject.hashCode() and our main method to look like this:
public int hashCode()
{
return 0;
}
public static void main(String[] args)
{
Hashtable h = new Hashtable();
MyObject[] keys = new MyObject[10000];
for ( int i = 0; i < 10000; i++ )
{
keys[i] = new MyObject(i);
}
for ( int i = 0; i < 10000; i++ )
{
h.put(keys[i], Integer.toString(i+1));
}
long startTime = new Date().getTime();
for ( int i = 0; i < 10000; i++ )
{
h.get(keys[i]);
}
long endTime = new Date().getTime();
System.out.println("Elapsed Time: " + (endTime - startTime) + " ms");
} |
Note that this is a valid hashCode method. It always returns the same value for a given object, assuming that nothing used in the equals method changes (not that it cares anything about that). It also returns the same value for two objects that are "equal." What it doesn't do is return a different value for objects that are not equal. It always returns the same value. This is a valid hashCode but, as this example will show, an inefficient one. Executing this 5 times using this new hashCode method, I get this output:
Elapsed Time: 7016
Elapsed Time: 7125
Elapsed Time: 7297
Elapsed Time: 7047
Elapsed Time: 7218 |
That gives me an average time of 7140.6 - roughly 7 seconds. By executing my original hashCode method and execute the same main method, I got this output:
Elapsed Time: 16
Elapsed Time: 16
Elapsed Time: 16
Elapsed Time: 15
Elapsed Time: 16 |
That's an average of about 16 millseconds - a far cry from the 7 seconds we saw earlier! We're seeing a dramatic increase in the amount of time required to retrieve objects from our Hashtable using the poor hashCode method. The reason for this is that, with every key object having the same hashCode, our Hashtable has no choice but to index every value under the same hashCode. In such a case, we've got everything in one long list and our Hashtable does us no good at all - we might as well have stored the objects in an ArrayList.
Summary
Hopefully you see the importance of creating a valid hashCode for any objects you're using. Whenever creating your own hashCode method, it's important to remember the 3 rules. I've listed them here in a summarized format; refer to the API Spec for full details.
- The hashCode method must always return the same value (assuming the object has not changed) from one invocation to the next.
- The hashCode for multiple "equal" objects must be identical.
- The hashCodes for multiple "unequal" objects should be different, but it is not required.
With that knowledge, you should have a firm grasp on how to override hashCodes and make the most out of the Hashtable (and other Map classes) in Java. Remember to tune in to The SCJP Tipline for more updates.
Discuss this article in The Big Moose Saloon!
Return to Top
|
LegoTM meets JavaTM : RoboJDE vs. LeJOS
by Jessica Sant
Introduction
I recently took a Robot Building Lab as
part of my Master's degree program. The class was a mix of graduate and
undergraduate Computer Science students. The majority of the course was taught
using the HandyBoard controller programmed
with a C derivative called IC4. Being the
Java geek that I am, I was thrilled when my professor mentioned there was a Java
product out there that you could use to program the HandyBoard. Enter RoboJDE. All the graduate students had an
additional requirement to program an RCX
robot using leJOS. This article
is based on my experience of the two platforms. This is by no means a definitive
comparison of the two platforms.
Every language has its purpose,
and this may have not been the ideal application of Java due to the extremely
limited memory on the platforms (~12k for the JVM, program, and the execution
space), but trying to code java small was a very interesting (albeit sometimes
frustrating) exercise. Plus, I always get a kick out of writing a program that
"does something cool". And getting a robot to do stuff like following a flash
light, avoiding obstacles it encounters, and determining where it is along a
wall based on what it sees with its sonar definitely qualify as "cool".
HighlightsRoboJDE and leJOS both have strong aspects to their platform.
Some highlights include: leJOS's built in RotationNavigator
that performs both forward and inverse kinematics (basically knowing where it
is on a 1' x 1' grid and the ability to go to a particular point on that
grid); and RoboJDE's sensor
interaction that better encapsulates the behavior of different sensors.
Because both platforms are Java-based it is possible to create
stand-alone programs in order to test the needed functionality off-line and
without the use of the actual robot. Each of these aspects proved quite helpful
in the respective labs.
Each platform has their issues... the main
problem that sticks out for leJOS is its lack of Garbage
Collection. The extremely limited memory is hard enough to deal with, and
not having the ability to free the memory after its been allocated makes the
situation more challenging for significant programs. RoboJDE has a very
efficient built-in garbage collector. The main issue with RoboJDE is that its
only available on the Windows platform, leJOS is available on both Windows and
Linux.
Hardware comparison
I/O
ports The Lego Mindstorm RCX board has a limited number of input and
output ports (three each). However the ability to overlap sensors allows the
programmer to use more sensors than there are ports available. Overlapping
sensors has the side effect that the readings from the sensors can be received
but it is often impossible to differentiate between which overlapped sensor is
sending the signal.
The HandyBoard had seven analog input ports, seven
digital input ports and two digital input / output ports. The limited number of
digital I/O ports became a problem during the 2nd half of the course because we
needed to use two encoders (used with kinematics
to determine where the robot is) and a sonar sensor. Each of these sensors
required the use of an individual digital input/output port. The HandyBoard does
not have the ability to overlap sensors, and so we were forced to use only one
encoder along with the sonar sensor. *Note: as a
work around we could have written native code to allow one of the encoders to
run on a pure input port, but this proved too difficult given the time
constraints and my pathetic understanding of the Motorola M68HC11 assembly
language.
LCD The RCX board has a severely limited
display. It allows only a total of 5 characters to be shown on the board whereas
the HandyBoard can display a total of 32 characters (2 lines, 16 characters in
length). The ability for the HandyBoard to display a more significant output
significantly aids in the process of debugging.
Robot
Interface The Handyboard interfaces with the PC through the serial port,
which connects to a standard phone line, which connects to the robot. So, if
you'd like to get debug information sent back to the PC during the robot's run,
it must remain "tethered" via the phone cord.
The RCX on the other hand
uses a USB tower to send signals via IR (I believe the tower can also be
connected to the PC via a serial port, but we didn't have the appropriate
hardware in our kits). Whether it was due to the IR speed or the RCX loading
software's speed, the RCX took a significantly longer amount of time to download
programs to the robot than the HandyBoard software. The nice advantage about the
built-in IR capabilities of the RCX robots is that it doesn't need to be
tethered in order to send debug information back to the PC.
Software comparisonThe Tools RoboJDE is a commercial product
that compiles code for the Handyboard. It has a more elegant user interface and
cleaner out-of-the-box experience than the UI used with leJOS. RoboJDE runs only
on windows, but the installation is much cleaner, requiring only the execution
of a simple setup executable. The UI itself produces a significant amount of
statistics about the user's program during compilation (program size, number of
static variables, number of classes used, etc) and execution (free bytes
available, free blocks available, % CPU used, % memory used). This information
proved quite useful while coding and debugging the HandyBoard.
leJOS is
an open-source product and thus has several available interfaces that can be
used to compile and download programs. Bricxcc required several products to
be installed as well as multiple environment variables to be set, and I was
unable to configure it successfully. Instead, I used RCXDownload, which requires only
that the JDK and the USB Tower driver be installed. It provides none of the
helpful statistics provided by RoboJDE; it is simply a way to compile and
download the leJOS programs.
The API Both RoboJDE and leJOS
are Java-based platforms, but they differ in the amount of the standard Java API
they implement and how they interact with the Robot.
- java.lang
leJOS implements more of the java.lang package
than implemented by RoboJDE. However the only significant piece of
functionality I found missing from RoboJDE was java.lang.Math.random(), a
simple random number generator. In order to simulate a random number generator
in RoboJDE when we needed to randomly choose from three different actions
(turn left, turn right, go straight) we performed a modulus operation on the
current system time. This method worked for our purposes, but one should note
that it is only effective if the call itself is made at random intervals.
- java.util
One significant piece of the standard Java API
that is implemented by leJOS and is missing from RoboJDE is the java.util
package. The Collection classes are the most useful parts of the java.util
package for the purposes of programming a robot. These data types are quite
useful when developing significant programs such as trying to find the optimal
path through a set of obstacles based on the sonar input. Because RoboJDE does
not implement any of these data types, simple arrays must be used to hold the
necessary data. Robot
Interaction One of the significant comparisons that need to be made
between RoboJDE and leJOS is how easily the two interact with and control the
robot.
RoboJDE provides specialized classes to handle a select set of
sensors. These classes encapsulate all the functionality of the particular
sensor. For example, the conversion of a sonar reading into a distance (see Figure
1) is handled by the RangeFinder class. If necessary, this class can also be
extended to support different brands of Range Finders other than the
DevantechSRF04.
Instead of providing specialized classes that handle
different sensors, leJOS provides a generic Sensor class which, when initialized
with different "Type and Modes", will behave differently. These types can range
anywhere from TOUCH to TEMP or LIGHT.
I find that RoboJDE's method of
interacting with sensors is more intuitive and easier to implement than the one
used by leJOS.
Figure 1: Example of leJOS
and RoboJDE code to interact with sonar |
leJOS |
//initialize the sonar
Sensor.S2.setTypeAndMode (3, 0x80);
Sensor.S2.activate();
//read the raw value of the sonar
float value = Sensor.S2.readValue();
//manually convert sonar reading to distance in centimeters
float distance = (float)(12f+.53*a*2.54); | |
|
RoboJDE |
//initialize the sonar
RangeFinder sonar = new DevantechSRF04(...);
float distance = 0.0f;
//send out a ping and read the value within 100 milliseconds
sonar.ping();
long timeout = System.currentTimeMillis() + 100;
do {
//RoboJDE automatically converts sensor reading to distance
result = sonar.getDistanceCentimeters();
} while ((result < 0.0f) && (System.currentTimeMillis() < timeout)); | | Both
RoboJDE and leJOS have a similar method of interacting with the Motors (see Figure
2). With both API's, you set the power levels of the motors their
directions.
Two very useful features that leJOS possesses that are
lacking in RoboJDE are the methods Motor.X.isMoving() and Motor.X.flt(). These methods tell the program if the
motor is currently being moved, and tells the motor to stop applying power to
the motor, respectively. The .flt() command is
different than stop in that it removes power, rather than bringing the motor to
an abrupt stop.
Figure 2: Example of
controlling motors in RoboJDE vs leJOS |
leJOS |
//Performs a left turn by moving the left motor (A) slowly
Motor.A.setPower(1);
Motor.A.forward();
//moving the right motor (C) quickly
Motor.C.setPower(7);
Motor.C.forward();
//pausing
Thread.sleep (1000);
//stopping both motors
Motor.A.stop();
Motor.C.stop(); | |
|
RoboJDE |
//initializes the motors
Motor leftMotor = HandyBoard.getMotor(0);
Motor rightMotor = HandyBoard.getMotor(1);
//performs the turn by moving the left motor slowly
leftMotor.setPower( Motor.FORWARD );
//moving the right motor quickly
rightMotor.setPower( Motor.FORWARD/10 );
//pausing
Thread.sleep(1000);
//stopping both motors
leftMotor.setPower( Motor.STOP );
rightMotor.setPower( Motor.STOP ); | |
Kinematics LeJOS makes kinematics almost a
trivial task. LeJOS provides a class called RotationNavigator that uses two
encoders to calculate the distance the robot has traveled, and in what
direction. The RotationNavigator performs the desired move by using commands
such as RotationNavigator.gotoPoint() (inverse
kinematics). It also can calculate where the robot is currently located by using
commands such as RotationNavigator.getX() and
.getY() (hence forward kinematics).
When
using RoboJDE, all of the functionality provided by a class such as
RotationNavigator needed to be designed and coded. Granted, having to code this
myself gave me a renewed appreciation for high school geometry as well as a
better understanding of how the kinematics calculations were actually performed.
Bump detection Due to the limited number of input ports
available on the RCX, the two bump sensors were stacked on a single input port
and it was not possible to determine if the bump occurred on the left or right
side of the robot. So, when avoiding a bump the robot always attempted to avoid
the obstacle by turning to the right. This caused a problem sometimes because
the robot would take several tries to completely avoid an obstacle, which would
in turn cause the robot to hit the obstacle more, and possibly collect more
error in the calculation of its position.
Figure 3: RoboJDE vs leJOS
in detecting a bump. |
leJOS |
Sensor.S2.setTypeAndMode (SensorConstants.SENSOR_TYPE_TOUCH,
SensorConstants.SENSOR_MODE_BOOL);
if( Sensor.S2.readBooleanValue() ) {
// avoids obstacle
} | |
|
RoboJDE |
DigitalInput leftBumper = HandyBoard.getDigitalInput(15);
DigitalInput leftBumper = HandyBoard.getDigitalInput(13);
if( leftBumper.isSet() && rightBumper.isSet() ) {
//center hit avoid obstacle
}
else if( leftBumper.isSet() && !rightBumper.isSet() ) {
// left hit avoid obstacle
}
else if( !leftBumper.isSet() && rightBumper.isSet() ) {
// right hit, avoid obstacle
} | |
Debugging Debugging
the robot's program for logical errors is a much easier task in the HandyBoard
due in large part to the RoboJDE UI as well as the large LCD on the HandyBoard.
Error messages, variable values and other helpful debugging statements can
easily be sent to the host machine (and simultaneously displayed on the LCD) by
simply calling System.out.println(). As mentioned before, the RoboJDE interface
that tracks the amount of memory and CPU used as well as program size etc is
incredibly helpful when debugging.
This type of helpful debugging is
much more involved with the Mindstorm. There is no simple way to print to the
host, and the limited size of the LCD prevents much useful information from
being displayed. We found that "debugging" is often reduced to adding different
sounds to be played at various points in the program and trying to interpret
these sounds to mean that the program has successfully reached a particular area
in the code. *In all fairness to the RCX and leJOS, because it has
an IR connection to the PC, you can send message through the IR in order to
debug problems -- but I didn't realize this at the time I was programming
it.
Garbage Collection One
significant advantage that RoboJDE has over leJOS is its automatic Garbage
Collection. When an object or variable is no longer used it is removed and the
memory is freed in order to be used by other variables. In leJOS the programmer
must be diligent and not produce more objects than necessary because there is no
way to reclaim memory once it is used. The lack of a Garbage Collector is a huge
detriment due to the extremely small amount of memory on the RCX.
RoboJDE is also very efficient when it compiles your program. Any
methods or classes not used will not be compiled and built into byte code for
the HandyBoard. This also aids in significantly reducing the size of your
program.
Other Stuff One significant advantage that leJOS has
over RoboJDE is that it has a Persistent memory area that can be used to store
calibration values from one program execution to the next. This functionality
would have proven useful during the first half of the course when we were
constantly calibrating and recalibrating the light and reflection sensors. If we
could have calibrated the robot once and stored these values in a Persistent
memory area, we could have saved time from one run to the next.
Simulating the Robot Due to Java's object
oriented nature, it was easy to encapsulate much of the functionality of the
labs as individual classes that were not dependent on the Robot code itself.
This quality became very useful when writing and testing some of the major
pieces of the labs.
For example, in one of the final labs a map of the
world needed to be built and stored on the HandyBoard based on the Sensor
inputs. We were able to hard-code a simulated set of sonar readings into a main
class. These values were then manipulated and stored so that they could later be
used to find an optimal path to the goal. The ability to do all of this off-line
with the use of real debugging utilities such as those built into IntelliJ IDEA
significantly reduced the number of logical errors present in the program once
it was actually used by the Handyboard.
What I thinkIn the end, I found that using and debugging RoboJDE was
easier than leJOS. The UI provided by RoboJDE made it easier to identify memory
problems as well as logical errors, and as I mentioned before, I found the API a
bit more intuitive to use as well.
All that being said, for the average
robot geek (and particularly for the recreational robot geek), money is almost
always an issue. LeJOS is a free open source product, and the Mindstorm itself
costs about $200. The
HandyBoard costs about $300, and RoboJDE is
about $100 (there is a free Lite
version available as well). So, for the casual geek, RoboJDE may not be the most
cost-efficient path, but I believe for the academic arena, its certainly a
strong choice.
Links
Discuss this article in The Big Moose Saloon!
Return to Top
|
Whizlabs SCMAD Exam Simulator (CX-310-110) Review
by Valentin Crettaz
When some big corporation's educational services announces the release of a new certification exam, you can be certain that the Whizlabs team won't be that far away. After many successful simulator releases in 2003 and before (SCBCD, SCJP 1.4, etc), Whizlabs now wants to make you MAD (that is, a Mobile Application Developer ) by complementing their product suite with another exam simulator for Sun's new certification exam targeted at the Micro Edition of the Java 2 Platform (J2ME). Whizlabs' simulators essentially pursue the following goals:
- to provide a huge question bank in order to best train the exam taker, and
- to closely mimic real exam conditions.
Basically, the user interface hasn't change much compared to what I have experienced with other simulators from Whizlabs' product line. While some display bugs have been eliminated, a few ones are still on the edge eargerly waiting to be terminated. Furthermore, when looking back at Lasse Koskela's review of their SCJP 1.4 simulator last December, it appears that Whizlabs has done much of its homework:
- I haven't experienced any problems during the installation process, and
- the code is well indented (even though monospace font is still not used for displaying code snippets.)
Moreover, I have to admit that I have specially liked the way Drag-n-Drop questions have been implemented. They are even better than in the real exam since after you have answered a question you can reopen the Drag-n-Drop box without having to answer the question again. This is, in my opinion, one of the big limitations in Sun's certification exam software. Actually, as most of you, every time I take a Sun certification exam, I have to write down my answer to a Drag-n-Drop question before closing the dialog box, which is a little annoying.
Regarding the content itself, you will find a total of 490 questions evenly distributed across 5 mock exams (68 questions each) and 1 quiz (150 questions). You can even create your own mock exams with the built-in test customizer that allows you to select any questions in the bank to help you focus on a specific area of your choice. Besides, all questions come with very exhaustive explanations and links to sections of the relevant specifications. Once you finish an exam you are offered the opportunity to review some answers you were unsure about or to directly go to the exam report and see if you have passed or failed. On the reports you will find a good deal of very comprehensive information. For each question, you will be able to see the objective to which the question relates, the level of difficulty, the type of the question (i.e., multiple choice, DnD, fill-in, etc) and whether you answered it correctly or not. Wait, that's not all!! The help menu will direct you to a complete user guide and some help content on how to use the tool itself. As always, Whizlabs has also bundled a Tips'N'Trick cheat sheet and quick revision notes for you to read just before taking the exam. On the downside, it's just unfortunate that you can't print out these helpful notes from the tool and take them with you to the test center to do some last minute brush up... Maybe, they'll consider adding that to future versions of their tools. Who knows...
A cool new feature has been added to the simulator: If you ever have a doubt about a question or an explanation or if you want to report some problem you experienced, you can do it by clicking on the "Discuss it" button and you will be forwarded to a dedicated SCMAD forum on Whizlabs website. Once you have logged in, you will just have to write your message. Of course, a live Internet connection is required in order to take advantage of this feature.
Finally, I think that this new exam simulator is well worth the money spent ($79.95 for new customers and $63.95 for existing ones) for the reasons enumerated below:
- The simulator is very efficient and is of great support for exam takers
- You get free upgrades for 6 months
- You get free technical support from the authors
- There are very few SCMAD mock exams out there yet (check out this link)
- And... (drum rolls) You'll get your money back if you don't pass the exam anyway
Don't hesitate to download the free trial edition to get a feeling of the exam simulator before buying it. I definitely recommend this outstanding resource to any respectful J2ME developer willing to tackle the SCMAD exam.
Resources
Whizlabs homepage
Whizlabs SCMAD exam simulator
SCMAD Certification Primer
Discuss this article in The Big Moose Saloon!
Return to Top
|
The Coffee House
An Agile Excursion
by Solveig Haugland
Looking back, nobody could agree what really made the project go bad. But
everyone agreed that Sid had gone nuts.
The JavaRanchers, in their hurry to get their code ready for the fall release
date, had gotten a little over-organized. It all seemed so innocent at first.
They made lists. Then spreadsheets. Then project plans, and then multiple
levels of organizational hierarchy, and four-dimensional schedules. Then
of course when the staff senior project manager told the senior staff project
manager and the lead senior project manager that it looked like the September
1st release wasn't going to happen, the senior lead project manager went
out and hired 42 more contract JavaRanchers to help move the project along.
Which is when the project, oddly enough, actually ground to a halt.
Sid and Zeke, who were lead senior staff developers on a couple of the project
modules, slunk into the Coffee House around 2 to avoid their daily 3-hour
status meeting.
"Give me a latte with a triple shot of strychnine, Brenda," Zeke groaned
as he bellied up to the bar. "I don't want to be in a world that has this
project in it."
"And a d-d-d-dodeca-espresso for me, Lacey," stammered Sid, jumping up and
down at approximately 120 reps per minute. "I got to keep alert! The Incan
Monkey God is going to come to me at midnight to tell me how to get this
project back on track! Yes, he is! Hey, isn't that Tony Randall? Pretty pretty
flowers!"
Lacey grinned. Brenda looked as if she wanted to look sympathetic but also
wanted to bust out laughing. "Ummm...so you guys are still on the stagnant
death march project from hell., eh?" Brenda asked as she poured out the latte,
sans strychnine. "Any new info today, Zeke; any progress?"
"Well, we got the users to tell us that the requirements they gave us last
month bear absolutely no resemblance to the software they want, but that's
OK since none of the developers actually knew those requirements existed.
Apparently two thirds of them have been working on a really cool offshoot
of wiki and the other third have been playing Quake. So now we have to re-gather
the requirements, and analyze them, and that usually takes about a year in
itself but we have a day and a half."
"Oh is that all!" Brenda started laughing but Zeke was too far gone to hear
her.
"Well, no. Sid here has gone into infinite loop caffeine intake and whenever
you ask him for a project update, he just keeps talkin' about how the Pope
and him have joined the Swiss luge team and they need to go luge shopping."
Lacey, who was as amused as Brenda but didn't relish human suffering quite
as much, said. "You know, Zeke, I think there's something that just might
help y'all, over the hill in that big ol' Salt Lake City. Did you know the
Agile Development conference is takin' place right there?"
"Agile! I've got an agile badger in my pants! Whoopeee!" That of course was
Sid, who by now had stripped naked (thus belying the pants remark) and was
doing some pretty remarkable cartwheels up the side of the Coffee House.
"Agile Development....isn't that a bunch of religious folks who worship a
guy named Kent Beck and have this heretical notion that ya don't need the
traditional 1500-page specification? I tell you, I think them folks is a
big tetched."
"Well, OK, that's not entirely wrong, but you know what else they do? They
tend to release software."
You could tell that Zeke was struggling. He was a Traditionalist and hated
the idea of taking on some pansy ass new fangled touchy feely methodology.
On the other hand, his bonus should he bring this project in on time was
a brand new John Deere combine with a titanium Mac 17-incher mounted on the
cupholder. He struggled. He shifted in his chair. He swatted Sid as Sid came
twirling down the near wall, and yelled for somebody to put some clothes
on that man. He looked close to a decision.
"Can a man get a decent whiskey in that town? In Salt Lake City?"
Lacey nodded. "Yes, but not on election day or in a month ending in an R."
Zeke said "I'll do it!" and that weird guy in the back of the coffee house
played the theme from The Magnificent Seven as Zeke threw Sid over his shoulder
and strode out the coffee house's swinging doors.
Zeke rode hard all the way to Salt Lake, with Sid strapped to the horse's
rump, inhaling some pretty nasty fumes which it turned out are a great antidote
to overcaffeination. They arrived just in time for the conference ice breaker,
where they strode around the room, eyeing the pretty ice-breaking belly dancers.
"Who is that guy in the weird hat with the wild look in his eyes?" asked
Sid, newly adjusted to the real world and just a little afraid of it.
"I imagine he's just the entertainment," Zeke assured him.
They looked around at the small but talkative developers around them. One
table was listening intently to a guy with a radio announcer's voice discussing
gap-toothed women. A tall man in frightening cowboy boots was describing
the pot-smoking rules in Amsterdam. Several men with really cute accents
who looked to be thoughtful workers were discussing soccer in a depressed
sort of way. "We're supposed to learn how to release software from these
folks ??? " Sid was skeptical. Zeke had a nasty feeling in the pit of his
stomach, but four drink tickets and their corresponding contents helped ease
the discomfort. They went to sleep that night in an uneasy state of mind.
The next four days, however, changed their minds, lives, and attitude toward
supposedly silly touchy feely development methodologies. Zeke learned much
to his chagrin that just because you write something down, well, that don't
make it true. Sid learned that extreme programming does not in fact mean
just staying up til it's done. They both learned that there are two kinds
of customers, liars and damned liars, and you have to watch them to find
out what their requirements are, not actually believe them when they say
they need shoulder-mounted faxes and milkshake machines for their field people.
They learned not to giggle and elbow each other when somebody said SCRUM
master, and to not confuse process with actually knowing what they were doing.
And they bought a bunch of technical books, as all people of honor do, and
stuffed them in their leather saddle bags along with some incredibly tasty
brownies from the afternoon snacks. They stuffed themselves at the end-of-conference
banquet, laughed uproariously at the truly amazingly exceptionally hilarious
top ten lists, donned their novelty sunglasses, stuffed the novelty plastic
clappers in their pants, and danced up a storm, especially to "YMCA".
The next day, flushed with new ideas, new books, and while they wouldn't
even admit it under torture, empowerment, Sid and Zeke made the return trip
to the JavaRanch, humming snatches of their Agile Development Song. They
met with the senior staff senior project manager, discussed the user requirements,
did some non-paralyzing analysis, threw a pile of dead fish out the window
of the meeting room, and in the end figured out that an application meeting
the customers' needs already existed and could be purchased at WalMart for
$49.99. Sid and Zeke exchanged high fives and went home, at last, for a well-deserved
whiskey.
This month's Coffee House Adventures were inspired by a trip to the 2nd Annual Agile Development
Conference in Salt Lake City. The conference was not only chock
full of great information and run by a conference team that knows the importance of chocolate, but
was just plain lots of fun. And as if that weren't enough, these agile development guys can dance up
a storm.
Solveig Haugland is an independent trainer
and author near Boulder, Colorado. Her businesses include GetOpenOffice.org for those switching
from Microsoft Office to OpenOffice.org (www.getopenoffice.org); Techwriter Stuff: The Single Source,
tshirts and posters for tech writers and those who love them; and of course
Dating
Design Patterns, the original reusable solutions to recurring problems.
Discuss this article in The Big Moose Saloon!
Return to Top
|
Meet the Authors - Kathy Sierra and Bert Bates
Meet the Author Solveig Haugland by Dirk Schreckmann
Not yet posted. Check back soon.
Return to Top
|
The Big Moose Saloon Question and Answer of the Month
Mosey on in and pull up a stool. The
JavaRanch Big Moose Saloon is the place to get your Java questions answered.
Our bartenders keep the peace, and folks are pretty friendly anyways, so don't
be shy!
Question: Use OOP to design database tables schema?
Over in the OO, Patterns, UML and Refactoring forum, Edward Chen opened a bottle of worms with this thread starter:
This question has haunted a while.
Usually, we firstly check the porject requirements and set up tables, and then do 1/2/3-NF normaliztion.
I don't like this way, because it is not Object-oriented way. So any body could share exprience how we use OOP to design complicate table schema/relationship?
Now, mosey on o'er, see what folks are saying and chime in with some thoughts of your own.
Join this discussion in The Big Moose Saloon!
Return to Top
|
Book Review of the Month
Other books reviewed in
June :
Discuss this book review in The Big Moose Saloon!
Return to Top
|
Following are the scheduled book promotions coming in July and August. Be sure to check our book promotions page often for changes and new promotions.
Return to Top
|
Managing Editor: Dirk Schreckmann
|