Little things I wish for in Java
Language Changes
A good percentage of lines in Java programs look like this:
SomeLongClassName foo = new SomeLongClassName(args);This could be a static, instance, or local variable. Of course, sometimes the two class names are different. For example:
SomeInterfaceName bar = new SomeInterfaceImplementation(args);But the former case is so prevalent and so frustrating to type, that I propose a shortcut syntax. I rejected the C++ syntax because one design goal of the JLS is to have a visible 'new' keyword wherever objects are created.
SomeLongClassName foo = new(args);should be equivalent to
SomeLongClassName foo = new SomeLongClassName(args);Automatic dispose syntax.
C++ requires special syntax to enable automatic disposal on scope exit. For instance, the following code:
void foo() {does not release the resource when the scope exits. Instead, you have to use a different syntax:
Bar * const p = new Bar();
doSomething();
}
void foo() {Now the resource is disposed when the scope exits. The same is true in Java. If you code:
Bar p();
doSomething();
}
void foo() {then nothing is disposed when the function exits - exactly like in C++. If however, you write:
final Bar p = new Bar();
doSomething();
}
void foo() {then the Bar is guarranteed to be disposed - exactly like in C++.
final Bar p = new Bar();
try { doSomething(); }
finally { p.dispose(); }
}
So what's the beef? The functionality is exactly the same. I wish that the syntax for the automatic disposal case in Java were simpler - something closer to C++ syntax. In particular, I want the syntax for automatic disposal to be *shorter* than the syntax for manual disposal - not longer. What I want is some "syntactic sugar".
- Create a new interface, java.lang.Disposable:
package java.lang;
public interface Disposable {
void dispose();
} - For any local final reference to a class that implements 'Disposable',
dispose is automatically called in a finally block. For instance, given:
class MyFiler implements Disposable {
then the following:
MyFiler(String name) { ... }
public void dispose() { closeAll(); }
...
}void foobar() {
would effectively generate this:
// notice I'm using the initialization shortcut described above
final MyFiler filer = new("blah..blah");
doSomething();
// shortcut syntax not requried for 'Disposable' feature
final MyFiler filer2 = new MyFiler("barsoap");
doSomethingElse();
}void foobar() {
final MyFiler filer = new MyFiler("blah..blah");
try {
doSomething();
final MyFiler filer2 = new MyFiler("barsoap");
try {
doSomethingElse();
}
finally { filer2.dispose(); }
}
finally { filer.dispose(); }
} - For every Disposable class, the compiler automatically generates calls to
dispose() for final reference fields first and then the base class whenever
they are 'Disposable'. For example, this class:
class Soap implements Disposable {
Would generate code equivalent to:
private final MyFiler filer = new("bar");
public void dispose() { }
}
class Shampoo extends Soap {
private final MyFiler filer2 = new("liquid");
}class Soap implements Disposable {
private final MyFiler filer = new MyFiler("bar");
public void dispose() {
filer.dispose();
}
}
class Shampoo extends Soap {
private final MyFiler filer2 = new MyFiler("liquid");
public void dispose() {
filer2.dispose();
super.dispose();
}
}
- By making a shorter syntax do automatic disposal, clients are more likely
to cleanup properly. Most programmers don't bother calling Image.flush() or
Graphics.dispose() until their GUI crashes enough to annoy them.
Even if dispose() is called while a reference is retained somewhere, this does not corrupt memory (unlike C++). This feature is just syntactic sugar for a common use of try..finally.
- Activating this feature with the 'Disposable' tagging interface prevents changing the meaning of existing code. Even without auto-disposal, tagging a class with 'Disposable' makes it crystal clear that the object needs to disposed. Furthermore, it provides a standard name for the dispose function. Currently, it could be 'close()' or 'dispose()' or 'flush()' or 'destroy()' or ... :-(
- Even without compiler support, you could follow the convention proposed. By using a tagging interface such as 'Disposable', an automatic tool can check whether the convention is properly followed from either source or .class files.
- In the meantime, while no standardized 'Disposable' interface or
auto-disposal or initilization shortcut is available, I recommend the
following practice:
Every class with external (non memory) cleanup required should implement a standard (for your company) interface (say, Disposable). Every Disposable class must provide a 'finalize()' method (separately from the dispose() method). It should check whether the instance was properly disposed, and write a log record which will be seen by a programmer whenever finalize() has to do the dispose(). This way, programmers using your class will be encouraged to use the proper try..finally syntax where needed to avoid the annoying error messages.
JVM Changes
Although the language provides for initializing primitive arrays, the current implementation is a joke. A blank array is allocated, then each element is individually set to its value. The workaround is to load a resource file to initialize large primitive arrays.
Without changing the JVM, it would be an improvement if the compiler would create this resource file for you and generate code to load it.
API Changes
In JDK 1.1 there was a public API for user defined encodings. Furthermore, certain kinds of programs can be made 4 or more times faster by keeping an instance of a Converter loaded instead of passing the encoding name as a String. This feature was taken away in JDK1.1.3! Sun promised to give it back in an improved form - but it still isn't there in Java 2. Our database driver needs to access byte encoded fields, and the performance is unusable without using the sun.io package as per the original JDK1.1 spec. The only other alternative is to roll our own converter classes - which seems silly.
Java Notes
by Stuart D. Gathman
Last updated Jan 16, 2007
I have moved the most popular items to the top of the menu.
Class Packager for Java
If you want to deliver an application or applet with all the classes and resources it needs - and only the classes and resources it needs, then you need ZipLock.java. The Java Cannery is a similar utility with a different feature set. Here are the doc comments for ZipLock:This is a utility class for examining a list of class names for all of their dependencies.When you create a JAR file with all the classes needed for your application, the JAR file is self-contained. It can be run by putting the JAR first in the CLASSPATH and running the main class. It will not break if later version of supporting class libraries introduce incompatibilities. This is similar to the effect of statically linking an executable in a modern dynamically linked OS.ZipLock will read each class file and search the internal structures for all references to outside classes and resources. The checks are recursive, so all classes will be examined. A list of dependencies will be returned.
None of the java.* classes will be examined. Additional system packages may be excluded with
setExcludes()
.In addition to classes, we look for other resources loaded via
Class.getResource()
orClass.getResourceAsStream()
. If a class calls these methods, then every String constant in the class is checked to see if a file by that name exists on the CLASSPATH in the same directory as the class - in other words wheregetResource
would find it. This heuristic only works if your resource names appear as String constants - which seems to be the case in my practice so far.We can optionally write all the classes and resources found to a zip or jar, or the list of files can be retrieved with
getDependencies()
.@author Stuart D. Gathman Copyright (C) 1998 Business Management Systems, Inc.
Original version Copyright (c) 1998 Karl Moss. All Rights Reserved.
The Object-Oriented jargon for such a self-contained application is a "Sealed System". The original name of this class, "RollCall" just didn't convey this concept. "Sealer" was too boring. We considered "Saran", but "ZipLock" seems more airtight and suggests the underlying ZIP format of JAR files as well!
Keep javac "hot" and ready to roll
A good portion of the time taken by the Sun javac compiler to compile your java code is spent in "startup". The JVM must load and initialize hundreds of classes and resolve references. I have created a simple "compile server" which listens for requests on a socket and invokes the compiler repeatedly. This saves about 10sec for each compile after the first on our 66Mhz AIX system. Here is the source: If the reduced startup time for Submit.java is still too much, you can use C++ to submit the requests: javac.cc, socket.cc, socket.h.A ZIP file with all of the above.
A Formerly Embarrassing Benchmark for AIX Java
This benchmark runs in 6.5 seconds on a 233Mhz Pentium II with MS J++. On a 300Mhz 604 with JDK1.1.4 GA, it takes 16.844 seconds (with JIT). The JIT makes little difference. There is no swapping. Profiling reveals that memory allocation is the bottleneck.IBM has since released JDK1.1.6 for AIX which cuts the time for this benchmark by more than half by using a per Thread cache for memory allocation and using direct memory references instead of handles. This makes AIX competitive performance-wise with the Microsoft VM - and it's not intentionally incompatible either!
code,
soya.att,soya.exs data files
Web page of benchmark author.
Fast Fourier Transform
I have always been fascinated by this algorithm. Here is a Java version adapted from 'C'. It adapts well and there is nothing kludgey here.Here is where I got the C code: Jo Desmet, Jo's Web Page
Obtaining JDK1.1.4GA for AIX
IBM no longer has this release on their web site. Several people have asked for it since it is the version they have tested against and need to install at their customers - but they have lost the AIX install image!You must contact IBM and ask for this release. I am not allowed to redistribute our copy - an IBM lawyer told me so. Very pleasantly and politely, I might add. It is probably easier to retest your applications against the latest release - which is 1.1.6 the last I checked. If this is a problem - then don't lose your install images. Besides, GA1.1.6 for AIX is much faster than GA1.1.4.
You need to register with IBM to gain access to their free developer area.
Elliptic Curve Cryptography
I have translated some public domain C source for Elliptic Curves to Java. I have further changes planned (like interfacing with java.security and making the ECPoint class immutable), but this might save you some work. New - the ECCrypt class has a stupid bug fixed, has some tests, and sign/verify now work. The EC.jar file includes the Lava rocks classes needed to run the test program.GNU Diff for Java
I have translated the GNU Diff algorithm to a Java class. The Diff class computes the differences between two Object arrays as a list of changes. This is very general purpose. Any of the options to GNU diff can be efficiently implemented as variations on how Object.equals() is implemented and how the change list is printed.DiffPrint now sports a setOutput() method. The DiffPrint.Base class and derivatives should really be renamed out of the empty package.
NOTE - unified and context printing do not combine nearby changes. Perhaps this feature was added since diff-1.15, or perhaps it is a bug. I (or someone) will need to get the latest diff source and add that feature.
Many people have asked me to change the license to LGPL. My port is based on GNU Diff, which is GPL. Until someone convinces me otherwise, I don't believe that I have the right to change the license. I have corresponded with the copyright holders of GNU Diff, and they are unwilling to change the license. Their position is that the GPL helps force companies to GPL more code in order to use existing GPL code.
The GPL restrictions do not apply to purely dynamically loaded code (otherwise, you would be unable to run GNU diff on a proprietary OS). When I get some time, I (or anyone who beats me to it) will create a plugin API so that applications can compile against an LGPL interface, and load the GPL implementation at runtime. This will also make comparing the performance of diff algorithms very convenient. While all Java classes are dynamically loaded at runtime, directly referenced classes are also used at compile time, and thus might be considered in violation of the GPL.
TODO
Publish the revised interface that simplifies doing things with elements that are the same (as opposed to the usual requirement of dealing with just those that are different).A TimeZone Implementation with Historical Changes and Leapseconds
I have translated the Unix "tz" package (formerly known as "localtime") to a Java class. In addition to reading/etc/zoneinfo
files and providing unix like functions
such as localtime()
and mktime()
, it extends
java.util.TimeZone
providing GregorianCalendar with TimeZones
that handle historical changes and leapseconds.
The tz code and zoneinfo files are included with modern Unix systems such as BSD and Linux.
Version 1.11 makes ZoneInfo Serializable.
Version 1.10 uses a better default timezone for zones with erratic changes.
Version 1.8 uses 64 bits for the unix timestamp - which unix systems are going to have to do by 2038 anyway, closes the Zoneinfo file when it is done, and removes the call to Lava Rocks.
TODO
Zic zoneinfo compiler. Have the compiler detect rational cycles, and extend the zoneinfo file to have a "go back N transitions" feature as suggested by Paul Eggert.JAR File Invoker for JDK 1.1
In Java 2, Jar files are directly invokable with the -jar option. For instance:$ java -jar myapp.jar arg1 arg2will look at the MANIFEST attributes for the jar to find the main class, and invoke it. Here is a simple invoker written in Java to provide the same feature with JDK 1.1. It is used like this:
$ java jar myapp.jar arg1 arg2