Miscellaneous Java problems and their solutions.

These items below are listed pretty much in the order that they were troubling my java development efforts. It's said that smart people can learn from their own errors, but a genius can learn from the mistakes of others. Here's you chance to exercise your genius and learn from my errors.

When I have encountered and solved a java puzzle, I write up the problem and its solution here. May this list save you a bit of time, I've got quite a few hours in figuring out how to do these things!

To ameliorate the disorderliness of the entries, use your browser's find function to search for whatever's bothering you.


Compiling java code.

   I have found that it's nice to have all of your classes in a single directory
during development.  Once you deliver to a customer, you of course should
package everything nicely into a jar file, but while you're putting things
together, it's nice to take advantage of Java's ability to put everything into a
single directory:

    javac -d /my/class/directory/ myJavaSource.java

   The above command places the myJavaSource.class file into the
/my/class/directory/ directory.  All you then need to do is have
/my/class/directory/ in your CLASSPATH environmental variable, and java will
have no trouble finding it.

   As an aside, most current Java IDEs will handle these details for you, and if
you're stuck with nothing better than a Windows system to work on, you should
take advantage of the IDE.  Unix, however, is its own IDE, and most IDE
functions are contained within its many commands.


To position an initial window in Swing:

   JFrame frame = new JFrame("SwingApplication");
   frame.setBounds(100,100,200,200);
   // This places the window at 100,100 on the screen, and makes it
   // 200x200 pixels in size.

The setPreferredSize method seems to have no effect.


To display an integer as hex:

   int exponent;
   String exp;
   exp = Integer.toHexString(exponent).toUpperCase();
   System.out.println("The exponent is " + exp); 


To capture keyboard input:

    // The following snippet reads a byte (single keystroke) from the keyboard:
    import java.io.*;
    class myClass 
    {
       public int myMethod() throws IOException 
       {
          java.io.BufferedReader in = 
          new java.io.BufferedReader(new InputStreamReader(System.in));
          String s = in.readLine();
       }
    }


Where is servlet.jar?
Your java server pages (JSPs) and servlets will not work without J2EE's servlet.jar and jsp.jar. When you download the latest versions of J2EE (sun now calls it Java EE), these jars are nowhere to be found.

Sun has renamed them to servlet-api.jar and jsp-api.jar. I use the ones in my Tomcat distribution, which are in
   /usr/local/tomcat/common/lib/servlet-api.jar and
   /usr/local/tomcat/common/lib/jsp-api.jar
on my server.


When running a project, all references to executables must contain the fully qualifed project URL, e.g.:


        java myProject.Class

   Non project java code can be run as:
        java Class

   If you have a class called myClass in a package called myPackage, after you've compiled it with
        javac MyClass.java

   you'd invoke it with:
        java myPackage/MyClass


Debugging an applet

   To debug an applet, run it under appletviewer, not a browser. Any run
   time errors will be reported by appletviewer, whereas the browser is
   generally silent.


Configuring JFrame

   When configuring a JFrame, many properties must be set by using:
       f = new JFrame();
       f.getContentPane().setLayout(new GridBagLayout());
       f.getContentPane().setBackground(Color.BLUE);

    not
       f.setLayout(new GridBagLayout());
       f.setBackground(Color.BLUE);


Importing jar files

   When using classes from a jar file, first do a jar -tf jarFile.jar,
   and ascertain the path in each of the classes that you need to use.
   This, and not the jar file itself, is the import statement used at the
   beginning of your .java file to use the class.


Invisible components

   If a component (e.g. JLabel) does not show up when properly added to a
   frame or panel, call the setOpaque method and set it to true:
   myLabel.setOpaque(true);


Null pointer to a Graphics object:

   Before you can get the Graphics object of a component, it must be installed
   into the panel where it will live, and that panel must be set visible, or
   the Graphics object will be null.


Setting up a $CLASSPATH:

   Each directory specified must end in a slash.
      /myJava/classes won't work, while /myJava/classes/ will.
   Jar files must be spelled out explicitly.
      /myJava/classes/ won't pick up the jar files in the directory.
   You must use:
      /myJava/classes/myJarFile.jar.
   Jar files are not followed by a slash.


Setting up multidimensional arrays of objects:

    It's not enough to declare and size the array:

        Item[][] myItems = new Item[5][5];

    You must initialize them, too:

      for (int i = 0; i < 5; i++)
      {
         for (int j = 0; j < 5; j++)
         {
            myItems[i][j] = new Item();
         }
      }


Using objects instantiated in try/catch blocks outside of the block.

    Declare the object outside of the try/catch, and set it to "null" (set Strings to""). The
    instantiated object can then be used outside of the try/catch block.


Regular expressions in java

   When escaping meta characters in java, you need 2 (count'em: two)
   backslashes before the meta character for the pattern compilier to
   correctly recognise the character, e.g.:  to find a question mark:

      Pattern p = Pattern.compile("\\?");


A FileInputStream anomaly.

   The read(byte[] b, int off, int len) method is a bit of a misnomer.  As
   written, one would expect it to read len bytes into byte array b starting
   at byte off in the file you're reading.
    This is not the case.
   What really occurs is that len bytes are read into array b at location off
   in the byte array, not the file.  Use RandomAccessFile instead.


Bit busting in Java.

   Java's lack of unsigned integers makes bit busting in the language a real
   pain.  Here's how you read in floating point numbers, say from the output
   of a C program, and translate them into Java floats:

   byte note[] = new byte[sizeOfBuffer];
   int tc;
   ...

   for (i = 0; i < 4; i++)
   {
       if (note[i] < 0)
       {
           byte b = (byte) ((int) note[i] & 127);
           tc += b << (i * 8);
           tc |= (1 << ((i * 8) + 7));
       } 
       else { tc += note[i] << (i * 8); }
   }
   float a = Float.intBitsToFloat(tc);


Accessing variables in main, anonymous classes, etc.


   Main and most anonymous classes will not access variables outside of their
   boundaries. 

   This is one royal pain until you learn the trick, which is all too often
   obfscutated as it is so apparent to those in the know that they forget
   to mention it.  

   Use accessor methods.  To get the value of variable bozo, your class has
   an accessor method for bozo:

       public int getBozo() { return bozo; }

   This can be called by your internal classes to get the variable. 

   BTW this technique is the reason that all Java beans require accessors
   for all variables that might ever be used by a calling method.


Hashtables must have Objects as their keys and values. Primitives, like int and double, won't work.

:-(

Jars


   To list the contents of a jar file: jar tf jelly.jar

   To extract the contents of a jar file: jar tx jelly.jar


A cross-platform line end token.

The end-of-line marker is 10 in unix, 13/10 in windows, and 13 in the world of mac. How do you get text to reflect this in Java?

         String end = System.getProperty("line.seperator");

Use this string instead of the usual "\n", and the JRE will figure out which line end to use on the platform the code is running on.


A bit busting bug.

   Using java's bitwise functions produces erratic results:

      return (buffer[i + 1] << 8) | buffer[i];

   Using its arithemetic functions produces the correct results:

      return (buffer[i + 1] * 256) + buffer[i];

   If you're doing a lot of bit busting, you should really be using C, perhaps
with native methods to interface it to a larger java procedure.  Java just
doesn't do this very well.


Drawing to a specific component

    To draw in a component, build a drawComponent (Graphics g) method in a
    class which extends the component's class. This can be the only method
    in this class, but it allows Java's drawing routine to identify which
    component to paint.


Getting the graphics environment, for later drawing.

A graphics object, such as a JFrame or JPanel needs to be made visible *before*
you try and access it.  This code:

      g = jpnl.getGraphics();

      f.pack();
      f.setLocation(50,50);
      f.setSize(winSize, (winSize + (winSize / 8)));
      f.setVisible(true);

Will result in g being a null pointer.  Instead, put the getGraphics call after
setting visible to true:

      f.pack();
      f.setLocation(50,50);
      f.setSize(winSize, (winSize + (winSize / 8)));
      f.setVisible(true);

      g = jpnl.getGraphics();

Note.  Setting the size of a component must also be done *AFTER* the component
has been rendered visible,  just like the getGraphics command.

Here jpnl is a JPanel within a JFrame f, and G, of course, is a Graphics
environment object.


A collection anomaly

So far, this one has only been verified on ListArrays, but I suspect that it
might be just as nasty for the other collections that allow you to have several
identical members.

MyObject mo = new MyObject();
ListArray la = new ListArray();
...

for (int i = 0; i < numItems; i++) {
   ...
   la.add(mo);
}

The above code won't work as expected.  Everytime you add your object, mo,
every item in you list, la, is set to the last item you added.  You need to add
another line:


for (int i = 0; i < numItems; i++) {
   ...
   la.add(mo);
   mo = new MyObject();
}

This fixes the problem, as mo is assigned a new address and Java's hidden
pointer that references your objects in ListArray is changed, allowing your
multiple entries to be the ones you expect, instead of the last one added.


Displaying graphics in an application at startup.

This one was subtle, and more than one Java Guru went down in flames trying to solve it, and I spent more than a year, off and on, before I found a solution.

The following code snippet attempts to set up a Java window, but all it produces is a blank frame.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Blank {

   JPanel p;
   public Blank() {
      JFrame f = new JFrame("BlankFrame");
      Dimension d = new Dimension(200, 200);
      p = new JPanel();
      p.setOpaque(true);
      f.getContentPane().add(p); 
      f.setLocation(50,50);
      f.setSize(d);
      f.setVisible(true);
   }

   /* This is never even called.*/
   public void paintComponent(Graphics g) {
      g.setColor(Color.white);
      g.fillRect(0, 0, 200, 200);
      g.setColor(Color.black);
      g.drawLine(0, 0, 190, 170);
      g.drawLine(0, 170, 190, 0);
      System.out.println("Lines drawn.");
   }

   public static void main(String s[]) {
      Blank b = new Blank();
   }
}

What is needed is a class that extends JPanel (or whatever component you want the use) which has the

   public paintComponent(Graphics g)

method overidden. The new paintComponent does your drawing for you. The default, in JComponent, just blanks the panel. Because class Blank does not have the paintComponent method in it's ancestry, (it's a simple object), this is not called, but the paintComponent for JPanel is, blanking the frame. Here's the same code, "refactored" a bit to display the graphics:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Plot {

   public Plot() {
      JFrame f = new JFrame("GraphicsDemo");
      Dimension d = new Dimension(200, 200);
      Pad p = new Pad();
      f.getContentPane().add(p);

      f.setLocation(50,50);
      f.setSize(d);
      f.setVisible(true);
   }

   public static void main(String s[]) {
      Plot q = new Plot();
   }
}

/* The drawing has to occur in a separate class. */
class Pad extends JPanel {

   public Pad() {
      Dimension d = new Dimension(200, 200);
      setPreferredSize(d);
   }

   // Note this is called 3 times as the frame is set up.
   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      g.setColor(Color.black);
      g.drawLine(0, 0, 190, 170);
      g.drawLine(0, 170, 190, 0);
      System.out.println("Lines drawn."); //TEST
   }
}


Embedding an applet in an HTML page.
If you want your applet to appear as if it was part of an HTML page, utilize the fact that Applet (and JApplet) inherit from Panel. Instantiate the page in Panel, as opposed to placing it into a Frame (or JFrame). If you place it into the frame, the applet will come up in a separate window, which might not be what you wanted.


Finding the size of your screen.

By screen I mean the monitor/terminal you're running on.

   Dimension d = Toolkit.getDefaultToolkit().getScreenSize();


String pattern matching foolishness
The boolean String method matches("Your regular expression here")
ONLY returns true if the ENTIRE string is matched.
A real comedown from perl's superb regular expression engine.


Importing a package

   In specifying a package, the fully qualified class name must be used. This
   is the group of subdirectories off of a node of your $CLASSPATH.
   Having :. as the last node of the $CLASSPATH does not seem to help.


Constructors do not have return types.

   // This will confuse the compiler:
   class public myClass 
   {
       public void myClass
       {
           // Here we construct myClass.
       }
   }

   // This is correct:

   class public myClass 
   {
       myClass 
       {
           // Here we construct myClass.
       }
   } 


Java packaging:

   Each file should have only ONE public class in it.

   The package name and directory name must be identical.

   All classes in a given package must be in that directory.

   All these classes have, as their first executable statement:
      package Package_Name;
   (Package_Name is the name of the package.)

   Write all of the classes, compile and test them before introducing the
   "package Package_Name;" statement at the top of each file. The compiler
   gets confused when non members try to access package members.

   Unless the Java program which accesses the methods in a package is
   a member of the package, you'll have to import it just as you would any
   other package:
      import Package_Name;

   If you have a package named:
      myJava.mySource
   that is kept in directory /home/myRoot/myJava/mySource, 
      and class myClass (original names, don't you think?)
   Your class path should have /home/myRoot/ in it, but /home/myRoot/myJava/
   or /home/myRoot/myJava/mySource/ will not find your class.  This can be
   quite puzzling, until you figure out Java's arcane way of directory
   specification.
   


Iterating over an ArrayList, and changing the contents of some of the list members
This should be easier and more general. If you know of a cleaner, more general way, please email it to me!

    import java.util.*;

    public class IterateOverCollection {

      ArrayList al;

      public IterateOverCollection() {
        al = new ArrayList();
        for (int i = 0; i < 10; i++) {
          Integer j = new Integer(i);
          al.add(j);
        }
      }

      void changeMembers() {
        Iterator  i = al.iterator();
        while (i.hasNext()) {
          Integer j = i.next();
          int k = j.intValue();
          int h = al.indexOf(j);
          k += 10;
          j = al.set(h, k);
        }
      }

      void printMembers() {
        Iterator  i = al.iterator();
        while (i.hasNext()) {
          Integer j = i.next();
          System.out.print(j.intValue() + " ");
        }
        System.out.print("\n");
      }

      public static void main(String[] args) {
         IterateOverCollection ioc = new  IterateOverCollection();
         ioc.printMembers();
         ioc.changeMembers();
         ioc.printMembers();
      }
    }


JTextArea (and other similar components)

Simply creating a JTextArea object and adding it to a panel or frame is not enough. You need to size the object as well for it to display:

    JTextArea ta = new JTextArea("Some Text");
    ta.setEditable(false);
    ta.setSize(800, 800); 


Regular expressions with capture.

Regular expressions in Java are a nice addition to the language. They are poorly documented (but so are everyone elses) and akward (compared to Perl) but they are, as I just said, a welcome addition. Examples, especially with capturing part of the expression, are hard to come by, so I include one here:

import java.util.regex.*;
public class RegexDemo {

  public static void main(String[] s) {

    Pattern p = Pattern.compile("\\w+(ing)");

    // Parse through the input strings.
    for (int i = 0; i < s.length; i++) {
      Matcher m = p.matcher(s[i]);

      if (m.find()) {
        System.out.println("The " + m.group(1) + " word " +
                            s[i] + " was found.");
      } else {
        System.out.println(s[i] + " does not have \"ing\" in it.");
      }
    }
  }
}
When you run it, you should get something like this:

java RegexDemo The Bling sing ding in the spring

The does not have "ing" in it.
The ing word Bling was found.
The ing word sing was found.
The ing word ding was found.
in does not have "ing" in it.
the does not have "ing" in it.
The ing word spring was found.


Iterating through an array of collection, new style.

This is so much nicer than having to set up an iterator or enumerator and calling hasNext and next until you're done...

  int[] numbers = { 1, 2, 3, 4, 5, 6, 7,  8, 9, 10 };
  for (int numeral : numbers) {
    System.out.print(numeral + " ");
  }
  System.out.println("");

Initizalition of components in a JFrame.

This is a weird one. In a window with a number of components such as JLabels, JButtons, etc, I initialized a class I built from a JPanel last. The class never displayed itself. When I instead, initialized it first, up it came. I seems that Java, once it has initialized on of its "built in" classes tends to ignore the others. I had set layout to null in both the JFrame and class derrived from JPanel.