Java Immutable Struct

There's something I sometimes do myself, which I've recently noticed someone else doing. That's not yet the RuleOfThree, but it's a start. Anyone else do this?

When I have a small ValueObject whose scope is not large (typically a private inner class), one that in C++ I would have perhaps used a struct for, I sometimes find it convenient to write code like this:

 class ScheduledEvent
 {
     final Event event;
     final long time;
     ScheduledEvent(Event event, long time)
     {
         this.event = event;    
         this.time = time;
     }
 }

Notice that the fields are not private, and yet they are read-only through being final. The lack of getters means that I can't secretly change the implementation. That hasn't been a problem with these trivial classes so far.

This kind of class almost always comes up when I want to make a Collection of pairs of things (e.g. Events and times above), rather than maintaining a pair of synchronized Collections. -- DavidPrice

I've been doing exactly this for the last couple of years. -- CurtisBartley

In a language with an advanced typesystem, this would be much better. For example, in CamlLanguage? you have type scheduled_event = ScheduledEvent of event * long, and in LispLanguage or even in SAC you have similar things.


I fail to see the utility of this kind of class. Whenever I see a DumbDataObject, I wonder how many places the code would be cleaner if behaviour was moved into the dumb data object, smartenin it up a bit. A similar problem occurs with enumerated types when people litter the code with conditionals based on which enumerated type they have, instead of factoring those conditionals into the enumerated type. -- JeffBay


I also have used this kind of technique, save the naming style.

Watch out for all your object allocations, and reference retention: prevent memory leaks, ensure stated contracts are upheld, and things like that -- non-static inner types in Java retain a reference to their enclosing type, using memory, but local and inner types can also bring reference implications that can immediately become orthogonal. If this is safely encapsulated into an appropriate context then it shouldn't be anything but perfectly fine to define a type like this.

I have also pushed these things out of the implementation: If you find you're using it for an operational effect, consider defining a method, taking the two arguments, that encapsulates the behavior: or look into the continuations that may be part of Java version 7. Be sure it shouldn't be refactored into another location. Also, with some thoughtful observation it might be able to be dissipated into refined implementation design.

Just be sure you still document the class: When a new programmer reads your code it should have an API like any other!

I'd say the concurrent utilities in Java show an implementation of a lot of things classified as this type of thing. It contains a number of classes you can use as low-level "nuts" and "bolts" for your implementation and replace what otherwise might be many uses of ad-hock local and inner types. Is this a "nut" or a "bolt"? But the API is not infinite, so we must always have a use for this type of thing, no? -- StevenCoco


EditText of this page (last edited November 15, 2006) or FindPage with title or text search