Friday, October 8, 2010

Java Workshop

About three weeks ago, I floated the idea of a Java Workshop to my CS222 class, and enough liked the idea for me to pursue it. Last Tuesday, I gave a two-hour evening workshop on the fundamentals of Java. Here is a synopsis of the major points we covered. The point of this post is primarily to refresh the ideas among those who attended, but others may still be interested to see what I consider as the Java fundamentals. It may be worth noting that this was explicitly about the language and environment of Java, not best practices or even software development.


  • "Java" refers to a language, an API, and a VM. It's good to be aware of this overloading of the word so that you can see how the whole system fits together, especially with the proliferation of languages that run on the JVM.
  • Java has primitive types and reference types. Primitive types are just boxes that hold values, but reference types are for objects, the fundamental building blocks of OO systems.
  • All of the primitive types have similarly-named reference types. For example, there's int and there's Integer. The difference between these reveals an important insight into object-oriented software design. Whereas an int variable is just a box that holds a value, an Integer instance is a representation of the idea of a number. Consider the following code.
    int x = 5;
    Integer y = 5;
    
    Here, x is just a box that holds an integer, and so we can say x=7, and that means we're putting a different value in the box. On the other hand, y is five. We cannot say y.setValue(7) any more than we can assert that 5=7 in mathematics.
  • It's good to recognize that y=5 is not free: it's using autoboxing to convert an int primitive into an instance of Integer. While it's true that premature optimization is the root of all evil, you shouldn't write code that creates unnecessary objects either.
  • It is critical that a Java developer builds a functionally-correct mental model of
    classes, objects, static, methods, and fields. A blog post is not the right way to help you, dear reader, to identify the problems in your own mental model. The good news is that my services are for hire. ;)
  • There are four access control modifiers that you should know so that you can read code: public, private, protected, and package-protected (which has no keyword). However, you should really only ever use public and private, so you just saved half your allocated brainspace on this topic.
  • To understand classes, abstract classes, and interfaces, I used an example like the following.
    public interface InningListener() {
      public void strikeOut();
      public void walk();
      public void balk();
      public void beaned();
      public void hit();
    }
    
    public abstract class AbstractInningListener implements InningListener {
      public void strikeOut() {}
      public void walk() {}
      public void balk() {}
      public void beaned() {}
      public void hit() {}
    }
    
    public class Inning {
      private final List<InningListener> listeners = new ArrayList<InningListener>();
      private int strikes = 0;
      public void addInningListener(InningListener listener) {
        listeners.add(listener);
      }
      public void strike() {
        strikes++;
        if (strikes==3) {
          fireStrikeOutEvent();
          strikes=0;
        }
      }
      private void fireStrikeOutEvent() {
        for (InningListener listener : listeners) {
          listener.strikeOut();
        }
      }
    }
    
    public class Demo {
      public static void main(String[] args) {
        Inning inning = new Inning();
        inning.addInningListener(new AbstractInningListener() {
          public void strikeOut(){
            System.out.println("Strike out!");
          }
        });
        for (int i=0; i<3; i++)
          inning.strike();
      }
    }
    
    A few highlights of this example:
    • This is an example of the Observer design pattern.
    • The abstract class provides default empty implementations of the methods in the interface so that implementors—like the one in Demo—can provide implementations of only those methods that they care about. This keeps the code from getting cluttered up with no-op implementations.
    • This pattern can be found throughout java.awt.event. I tend to do something a little more idiosyncratic involving inner interfaces and inner classes, but that's for another day.

  • If you're doing I/O, it's good to know that the InputStream/OutputStream family of classes is for byte-level I/O, Reader/Writer family is for character-encoded content, and the nio libraries are for blazing fast access to hardware buffers, and so can be ignored until you need it. To me, the critical classes to know are BufferedReader and PrintWriter. BufferedReader has the amazingly-useful readLine method, allowing line-by-line access to a stream, and a PrintWriter behaves exactly like System.out.



  • The classloader trick will load a resource from the classpath whether you are running in Eclipse, from a command-line, from an executable jar, in a servlet, or on Java WebStart:
    Thread.currentThread().getContextClassLoader().getResourceAsStream("whatever.png");
    



  • Here's a slapdash tour of the collections API:
    • List<T> defines a sequence. There are two useful implementations,
      LinkedList<T> and ArrayList<T>, which come with the usual caveats implied by their names.
    • Set<T> defines a set, in the discrete mathematics sense.
      The two common implementations are TreeSet<T> and HashSet<T>, but you should use the latter because you're always providing a useful hashCode method in all of your Java classes—or else you're doing it wrong.
    • Map<K,V> defines a dictionary, an associative array, a lookup table—choose your favorite mental model. Again, we have TreeMap<K,V> and HashMap<K,V>, and you should use the latter and override hashCode in all of your classes.
    • Finally, use guava.



I think that's everything we covered, except for some of the more specific questions. I hope this post is helpful to someone looking for a birds-eye view of Java. As I mentioned at the workshop, when I started using Java in 1998, there was not much to learn and there was basically one place to go to get started. Now, I imagine that novices can be easily overwhelmed by the immensity of just the standard libraries. By the way, the good news here is that the best place to go for an introduction to Java—as long as you aleady know something about programming— is still The Java Tutorials.

No comments:

Post a Comment