| Sign In/My Account | View Cart |
Like any other language or platform, Java has its gotchas. Find out how to avoid subtle mistakes and cash in on the full power of the Java platform in Jonathan Knudsen's Top Ten Tips and Tricks. Compiled from years of hard knocks and hundreds of reader questions, this list covers everything from flushing streams to loading images and creating runnable JARs.
Typically, you can just call flush() after you write something important:
// OutputStream out;
// byte[] data
out.write(data);
out.flush();
If you're writing text data, you might use a PrintWriter for output. PrintWriter has a special constructor that lets you specify if the stream should be flushed after every newline:
PrintWriter out = new PrintWriter(rawOut, true);
A PrintWriter created in this way will automatically flush itself whenever you write a line of text.
public void paint(Graphics g) {
g.setColor(Color.green);
g.drawLine(20, 20, 40, 140);
g.setColor(Color.blue);
g.fillOval(50, 110, 120, 60);
g.setColor(Color.red);
g.setFont(new Font("Serif", Font.ITALIC, 36));
g.drawString("Cellini", 40, 80);
}
I haven't even used any 2D API features here--it's just plain old AWT graphics stuff. Adding antialiasing is easy. Just add this line to the very top of the paint() method:
((Graphics2D)g).setRenderingHint
(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
The difference is shown below. It's great stuff for free!
Aliased rendering (default)
Antialiased rendering
In the old AWT world, Canvas was the base class for new components. Swing doesn't have a JCanvas, so some people make the jump to JPanel as a base class. Use JComponent instead; it's a cleaner solution.
Also included are static utility methods in the Collections class for sorting collections, creating threadsafe versions of collections, and other common tasks. For a full story, see the coverage in Learning Java.
boolean b = false;
if (b = true) {
// Always gets executed.
}
Instead of performing a comparison, as you'd hoped, you're actually assigning true to the variable b. This assignment has an overall value of true, so the if always succeeds.
Some people suggest reversing the order of the comparison, so the literal value always comes first. This generates a compile-time error for if (true = b), so you'll figure out what's wrong and change it to if (true == b). Personally, I don't like how this looks, so I just muddle through the old fashioned way, making darn sure I always use a double equals when I need it.
There's an easy fix: shut down the application when the main window closes. It looks like this:
// JFrame f;
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) { System.exit(0); }
});
This becomes a problem whenever you are installing standard extension libraries or editing files like the java.security properties file. The problem I usually have goes something like this: I install a standard extension library, like the Communications API or the Java Cryptography Extension, in \jdk1.2.2\jre\lib\ext. I work on a program that uses the extension API, and it compiles fine. When I go to run it, it complains that the classes in the standard extension library are not found.
The problem is that I'm compiling using \jdk1.2.2\bin\javac.exe, but when I run the thing, it uses \winnt\java.exe, which is actually the JRE, which would expect to find the extension API in \Program Files\JavaSoft\JRE\1.2\jre\lib\ext.
To fix this, I usually remove or rename java.exe and javaw.exe in \winnt. Then when I run my program, it uses \jdk1.2.2\bin\java.exe which is the Java SDK where I installed the standard extension API.
Image i = Toolkit.getDefaultToolkit().getImage("tarsier.png");
However, Images use lazy data loading, so the data for the image won't start to be loaded until you try to display the image. You can use a MediaTracker to force the data to load, but it's a pain in the butt. An easier solution is to use one of ImageIcon's constructors, which does the dirty work of waiting for image data to load. Then you can just pull out the image and use it, confident in the knowledge that its data is fully loaded:
Image i = new javax.swing.ImageIcon("tarsier.png").getImage();
The straightforward, non-portable way of referencing a file looks something like this:
InputStream in = FileInputStream("images/tarsier.png");
When this code runs inside a JAR, it will still look for the file in the filesystem, rather than trying to find the image file inside the JAR. Instead, use code like this:
InputStream in = getClass().getResourceAsStream("images/tarsier.png");
This looks for images/tarsier.png relative to the location of the referenced class, and it works inside JAR files.
java -cp Shorts.jar Shorts
A much nicer solution is to use the Main-class attribute, which is a
way of embedding the name of the class to run inside the JAR. Then you
can just run the application (in Java 2, at least) like this:
java -jar Shorts.jar
How do you do it? Normally, you would create the JAR something like
this:
jar cvf Shorts.jar *.class
The trick to adding the Main-class attribute is defining an entirely separate file with the attribute definition. For instance, create the following one-line file and save it as extra.mf:
Main-class: Shorts
Now, to create the JAR, use this command line:
jar cvmf extra.mf Shorts.jar *.class
The m option reads information from the extra.mf file you just created and adds it to the manifest of the JAR you're creating. Now you can run the JAR using java -jar Shorts.jar.
O'Reilly & Associates recently released Learning Java.