Sunday, March 28, 2010
JAVA TIPS
1. Flush Streams
This might seem obvious, but it repeatedly kicks my butt. The problem usually appears with two programs on either side of a network socket having some kind of conversation. If you don't flush the output stream every time you say something, the data may not actually get written out to the socket, and the two programs will sit patiently, waiting forever for something to happen.
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.
2. Use Antialiasing
This is a sweet one. If you're doing any graphics at all in Java 2, you can make it look a lot nicer with a single line of code. Consider the following paint() method:
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
3. Subclass JComponent, not JPanel
If you're creating a new graphical component, subclass JComponent. It's the base class for all Swing components. JPanel, as a container, has some extra baggage for double buffering its children that you don't really want to deal with if you're building a new component.
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.
4. Use Collections
Java 2 includes a nice set of object buckets called the Collections API. This underappreciated API lives in the java.util package and provides interfaces, classes, and utilities for working with groups of objects. You're probably familiar with Vector and Hashtable. The Collections API provides a framework that encompasses Vector, Hashtable, and several new collection classes.
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.
5. Use Double Equals for Comparisons
This is a holdover from C. It made its way into C++, and then Java used a lot of C++ syntax. The bug goes like this: Somewhere, you accidentally type a single equals sign instead of a double one when examining a boolean value:
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.
6. Add Application Exit Logic
Swing frame windows (JFrames) automatically close themselves if you click on the close icon (the X in the corner). However, if the JFrame was the main window for your application, the application will not actually quit. After closing the window, users will need to hit Ctrl-C or whatever key sequence stops a running application on their particular platform. Worse, if the application was started with javaw, it will continue to run invisibly.
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); }
});
7. Java SDK and JRE Confusion
On Windows, you may actually have two Java environments in different places on your computer. The JDK (or SDK, whatever you want to call it) is usually installed in a directory like \jdk1.2.2. The JRE, including the Java Plug-in, is typically installed in a directory like \Program Files\JavaSoft\JRE\1.2.
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.
8. Fully Load Images Using ImageIcon
You can load GIF, JPEG, and (in SDK 1.3) PNG images using Toolkit's getImage() method:
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();
9. Use getResourceAsStream() For Portability
If you've got a serious application, you'll probably want to package it up in a JAR file someday for easy distribution. If your application loads image and sound resources from files, as it likely will, you may find all the resource-loading code breaks when you put your application in a JAR. To avoid this, there's a way of loading application resources that work with regular files and inside a JAR.
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.
10. Use the Main-class JAR Attribute
If you do package up an application in a JAR, there are two ways to run it. The first way is kind of clumsy--you have to add the JAR to your CLASSPATH and you have to know the name of the class to run. Suppose, for example, that I have an application called Shorts, packages in a JAR called Shorts.jar. To run it, I'd do something like this:
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.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment