All entries for February 2006

February 06, 2006

Java Pet Peeves #3:Lack of use of the final keyword

Seeing as how I am on a roll ;)

The use of the final keyword is so important within Java; I fully believe that the function of the code should be readable without comments, even if the reason for the code needs commenting (this will be explained in another Pet Peeve ;)), and appropriate use of the "final" keyword is another way of documenting your code. The side effect of allowing the JDK to help you, is of course a bonus :) :)

Objects; how are they passed?

The "final" keyword in java doesn't mean (as some think) "do not change the state of this object", it means "do not change the variable containing the reference to this object". This is a subtle, but extremely important distinction. Generally speaking, objects can be passed in one of two ways, by value, or by reference. By value means a copy of the object is passed, leaving the original intact. By reference means a pointer to the same object is passed. Java manages to combine the two by passing a copy of the reference. For example:


  public class ClassA {
    public void doSomething(List myList) {
    }

    public static void main(String args[]) {
      List myList = new ArrayList();
      doSomething(l);
    }
  }

When doSomething() is called with a reference to myList the JDK will provide a copy of the reference to myList. This means that the doSomething method can manipulate myList, but it cannot reassign the reference to myList:


  public class ClassA {
    public void doSomething(List myList) {
      myList = new ArrayList();
      myList.add("hi");
      System.out.println("doSomething contains " + myList.size() + " elements");
    }

    public static void main(String args[]) {
      List myList = new ArrayList();
      doSomething(l);
      System.out.println("MyList still points to the same list as before, with " + myList.size() + " elements");
    }
  }

will result in the following statements:


doSomething contains 1 elements
MyList still points to the same list as before, with 0 elements

This is because the myList variable that doSomething method is modifying is a copy of the myList variable in the main method. Hence; Java passed objects by a copy of the reference!

The two copies of myList reference the same bit of memory though, so:


  public class ClassA {
    public void doSomething(List myList) {
      myList.add("hi");
      System.out.println("doSomething contains " + myList.size() + " elements");
    }

    public static void main(String args[]) {
      List myList = new ArrayList();
      doSomething(l);
      System.out.println("MyList still points to the same list as before, with " + myList.size() + " elements");
    }
  }

will result in the following statements:


doSomething contains 1 elements
MyList still points to the same list as before, with 1 elements

So if you wanted to prevent access to myList, how would you do it? In short; you can't. Making the method parameter final prevents you modifying the the reference, not the object the reference is to:


  public class ClassA {
    public void doSomething(final List myList) {      
      myList.add("hi");  // I can still modify myList
      myList = new ArrayList(); // won't compile.  Cannot change where myList points to
    }

    public static void main(String args[]) {
      List myList = new ArrayList();
      doSomething(l);
      System.out.println("MyList still points to the same list as before, with " + myList.size() + " elements");
    }
  }

Final; so what does it do?

What does making a method or a class final do? It prevents you extending the class:


public class ClassCanBeExtended {
  public void methodWhichCanBeExtended() {
  }

  public final void methodCannotBeExtended() {
  }
}

public final class ClassCannotBeExtended {
}

results the following scenarios:


public class ExtendingClass extends ClassCanBeExtended { // fine.
  public void methodWhichCanBeExtended() { // fine
  }

  public final void methodCannotBeExtended() {  // fails because the super class is final.
  }
}

public class WontCompileClass extends ClassCannotBeExtended {  // won't compile.
}

Making a static, member, method or local variable final (as discussed) prevents you assigning more than one copy to it.

So why use it?

The reason you would use the final depends upon where you would use it:

[classes, methods]
Use it to prevent others from changing the behaviour of your code.

[member variables]
Use it to indicate that the class requires access to a collaborator and the class cannot handle changing that collaborator once it has been instantiated:


public class ClassWithCollaborator {
  private final Collaborator collaborator;
  public ClassWithCollaborator(Collaborator myCollaborator) {
    super();
    this.collaborator = myCollaborator;
  }
 
  public void setCollaborator(final Collaborator a) {
    this.collaborator = a; // won't compile!
  }
}

[method or local parameters]
Use this if you want to prevent name space clashes:


public void doSomething(final List myList) {
  myList = new ArrayList();  // won't compile!
  final List anotherList = new ArrayList();
  anotherList = new ArrayList(); // won't compile either.

}

So; if you are still reading ;) Please think carefully about:

a) Can your class handle changing the reference to something once it has been initialised? If not, make the initialisation final.
b) Are you trying to prevent access to an object passed into a method? If so, don't use final because it won't do what you think :)

HTH someone ;)


Java Pet Peeves #2:Useless assignments

Boy; am I moaning today :)

So my second pet peeve is unnecessary assignments within Java.

Essentially; all member variables will be assigned to a default value (Object=null, int=0, boolean=false), whilst all local variables will have no initialisation.

Thus, the following two classes will be equivalent:


public class ClassThatUnderstandsHowJavaWorks {
  private Object o;
  private boolean b;
  private int i;
}

public class ClassThatDoesntUnderstandHowJavaWorks {
  private Object o = null;
  private boolean b = false;
  private int i = 0;
}

I have heard the argument that the second form is more explicit. I don't but this because it means every time you write a member variable you need to write extra crud. Every time! It would be far better to educate people once and write neat code, than write bad code over and over.

The other aspect of initialisation is allowing the compiler to help you. For example, if you have a variable which should always be initialised within an if clause, how many people would write:


  String message = null;
  if (someCondition) {
    message = "a message";
  } else (someOtherCondition) {
    message = "some other message";
  }

This code will compile, and work; but will allow the situation for message to be null (if neither condition is used). If the assumption is that one of the two conditions will always be true, the compiler cannot help you.

Remove the initial initialisation and the code won't compile:


  String message;
  if (someCondition) {
    message = "a message";
  } else (someOtherCondition) {
    message = "some other message";
  }

because the compiler will catch the fact that there is a route through your code that will leave message in an uninitialised state. Forcing you to rethink your if condition.


Java Pet Peeves #1:Pointless Constructors

So I was looking through some code (the author shall remain nameless :)) and spotted a shed load of my number #1 pet peeve; useless constructors:


public class Something {
  public void aMethod() {
    …
  }
}

In the above circumstance there is absolutely no point (as far as the JRE is concerned) to put a default constructor. The following will result in exactly the same byte code (I imagine; I cannot verify this :)):


public class Something {
  public Something() {
    super();
  }

  public void aMethod() {
    …
  }
}

or even worse:


public class Something {
  public class Something() {
  }

  public void aMethod() {
    …
  }
}

Why, oh why must people do it?

Admittedly; stupidly Eclipse provides a default constructor (with the super() call) by default, but that is no excuse.

It is quite simple; if you have no constructors, the JDK will provide a default constructor which contains a call to super() for you. You must provide a constructor if either you do not wish to have a default constructor, or the super class does not include one.

For example, if you have a class which requires a number of collaborators to work, then you should create a constructor which takes in those collaborators. Because you have provided a constructor, the JDK won't put a default one in for you, so:

public class Something {
  public Something(final String s) {
  }
  public void aMethod() {
    …
  }
}

can be instantiated with:


  new Something("ssss");  // good
  new Something();  // bad

The JDK cannot create a default constructor if the super class doesn't itself contain a default constructor:


public class BaseClass {
}

public class ExtendedClass extends BaseClass {
  // no need to put a constructor
}

public class BaseClass {
  public BaseClass() {
    // stupid, but used for illustrative purposes.
  }
}

public class ExtendedClass extends BaseClass {
  // still no need to put a constructor
}

however:


public class BaseClass {
  public BaseClass(final String s) {
  }
}

public class ExtendedClass extends BaseClass {
  // absolutely must put a constructor in, even if it is a no-args constructor
  public ExtendedClass() {
    super("some value");
  }
}

So please; when you create the next class, ask yourself whether it requires any collaborators, if it does, provide a single constructor with those collaborators (which should be marked final BTW :)). If it doesn't, don't provide any constructors; let the JDK do it's job.

And if you must provide a constructor; make sure you call super(...) :)

Please, for my sanity :)


February 03, 2006

Interesting little problem upgrading to Spring 2.0M2 :)

Details here:

link

Essentially I upgraded my project from Spring 1.2.4 to Spring 2.0M2. Despite the addition of org.springframework.web.servlet.View#getContentType(); the upgrade appeared to be very smooth. The extensive unit tests passed, and all appeared to be well…..until I deployed it :)


14:50:36,676 ERROR [ContextLoader] Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'siteBuilderDAO' defined in ServletContext
resource [/WEB-INF/persistence-context.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessio
nFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFact
ory' defined in ServletContext resource [/WEB-INF/persistence-context.xml]: Cannot create inner bean 'uk.ac.warwick.sbr.hibernate.
ClassFilteringLoadEventListener#159f498' while setting bean property 'eventListeners' with key [post-load]; nested exception is or
g.springframework.beans.factory.BeanCreationException: Error creating bean with name 'uk.ac.warwick.sbr.hibernate.ClassFilteringLo
adEventListener#159f498' defined in ServletContext resource [/WEB-INF/persistence-context.xml]: Instantiation of bean failed; nest
ed exception is java.lang.IllegalStateException: BeanWrapper does not hold a bean instance
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext
resource [/WEB-INF/persistence-context.xml]: Cannot create inner bean 'uk.ac.warwick.sbr.hibernate.ClassFilteringLoadEventListener
#159f498' while setting bean property 'eventListeners' with key [post-load]; nested exception is org.springframework.beans.factory
.BeanCreationException: Error creating bean with name 'uk.ac.warwick.sbr.hibernate.ClassFilteringLoadEventListener#159f498' define
d in ServletContext resource [/WEB-INF/persistence-context.xml]: Instantiation of bean failed; nested exception is java.lang.Illeg
alStateException: BeanWrapper does not hold a bean instance
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'uk.ac.warwick.sbr.hibernate.ClassFiltering
LoadEventListener#159f498' defined in ServletContext resource [/WEB-INF/persistence-context.xml]: Instantiation of bean failed; ne
sted exception is java.lang.IllegalStateException: BeanWrapper does not hold a bean instance
java.lang.IllegalStateException: BeanWrapper does not hold a bean instance
        at org.springframework.util.Assert.state(Assert.java:341)
        at org.springframework.beans.BeanWrapperImpl.getPropertyDescriptorInternal(BeanWrapperImpl.java:274)
        at org.springframework.beans.BeanWrapperImpl.getPropertyType(BeanWrapperImpl.java:323)
        at org.springframework.beans.PropertyEditorRegistrySupport.findCustomEditor(PropertyEditorRegistrySupport.java:233)
        at org.springframework.beans.PropertyTypeConverter.doTypeConversionIfNecessary(PropertyTypeConverter.java:100)
        at org.springframework.beans.PropertyTypeConverter.doTypeConversionIfNecessary(PropertyTypeConverter.java:73)
        at org.springframework.beans.PropertyTypeConverter.convertToTypedMap(PropertyTypeConverter.java:277)
        at org.springframework.beans.PropertyTypeConverter.doTypeConversionIfNecessary(PropertyTypeConverter.java:131)
        at org.springframework.beans.BeanWrapperImpl.doTypeConversionIfNecessary(BeanWrapperImpl.java:853)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doTypeConversionIfNecessary(AbstractBeanFactory.java:672)

        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:370)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:126)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapabl
eBeanFactory.java:542)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFact
ory.java:368)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBeanDefinition(BeanDefinitionValueRes
olver.java:151)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolv
er.java:97)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedMap(BeanDefinitionValueResolver.jav
a:235)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolv
er.java:118)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapabl
eBeanFactory.java:764)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFa
ctory.java:575)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFact
ory.java:405)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:238)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:148)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java
:186)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolv
er.java:106)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapabl
eBeanFactory.java:764)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFa
ctory.java:575)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFact
ory.java:405)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:238)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:148)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactor
y.java:253)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:331)
        at org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicat
ionContext.java:155)
        at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:240)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:178)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:49)

was thrown up. OK, I thought; lets look at the class in question (bear in mind this has all been working previously ;)):

The constructor looked like:


    public ClassFilteringLoadEventListener(final Map> theListeners) {
        }
    }

And it was being wired up:


  >bean class="uk.ac.warwick.sbr.hibernate.ClassFilteringLoadEventListener"<
            >constructor-arg index="0"<
              >map<
                >entry key="uk.ac.warwick.sbr.linksgenerator.SiteNavigationContentFetcher"<
                  >list<
                    >bean class="uk.ac.warwick.sbr.hibernate.AutoWiringLoadedObjectListener"/<
                  >/list<
                >/entry<
        >/map<
    >constructor-arg<
>/class<

Hmm, nothing strange there either (apart from me getting my < and > mixed up ;))

And then it occurred to me that Spring 2.0M2 understands generics :) Modifying the constructor argument to take a non typed Map fixed the problem.

Very subtle; took me most of the afternoon to catch this one ;)

JIRA is here: link

All this is redundant anyway because I found SWF (Spring Web Flow) PR5 uses a few classes which have been moved (PropertyEditorRegistrar etc.)


OK; I confess

Follow-up to The value of being explicit…. from Colin's blog

OK, OK: the original code actually used a Map instead of a Set.

For some reason I never used Set's; I would always use a Map and then Map.contains().

It is only in the last few years I started using a Set.

There, go and laugh now :)

I don't know; you just can get the senior staff nowadays :)

Come one; share the fun; what cringeworthy things do you do?


JDK5 Annotations; I love them, no, I hate them! (Actually I hate Eclipse) :)

So there is a fantastically useful annotation: @Override which when indicates that a particular method is overriding a method in the super class.

Why is this useful?

Assume today we are overriding the method called "methodA", tomorrow we get a new release of the library and the method in the parent class is no longer called "methodA", but renamed to "methodWithAMuchBetterName".

Your code is syntactically correct; it will compile, but it is not semantically correct. The no longer overridden method fails. No compiler errors to help you out; nothing.

You may argue that if you are overridding a method you almost certainly want to be calling super.sameMethod(); but that is just wrong. You do not have to , nothing in the million + 1 best practices suggest it, it is one of the more annoying anti-patterns. In particular; a lot of framework provide template method which do absolutely nothing for the sole purpose of you extending them; or they provide abstract methods for the same purpose.

Anyways; so JDK5 introduced an Annotation which told the compiler that the method is overridding a parent method. If the method in the super class is removed; your code won't compile.

Excellent. Lovely. As well as adding extra documentation to the source code; it has empowering side effects.

So sure; I love JDK annotations.

Now I implement an interface; create a method which implements the interface, stick an "@Override" on the method, and what happens? Eclipse moans that the method must override a superclass method.

ARRRGGHHH!!!!! It still compiles, but the source code looks like it is incorrect code.

Poo.


The value of being explicit….

So I had to explain some code I wrote a year or so ago to the colleague who was maintaing it and it looked something like this:


  public CollaboratorA doSomething() {
    final Set data = new HashSet();
    // .. populate the data
    return new CollaboratorA {
      boolean isThisTrueForSomeCriteria(final Object o) {
        return data.contains(o);
      }
    }
  }

which is all perfectly valid; but not at all intuitive. In particular; what was the lifetime of Set data?

I then rewrote this and moved the inner class into it's explicit class:


  public CollaboratorA doSomething() {
    final Set data = new HashSet();
    // .. populate the data
    return new SetBackedCollaboratorA(data);
  }

  class SetBackedCollaboratorA implements CollaboratorA {
    private final Set data;

    SetBackedCollaboratorA(final Set theData) {
      this.data = theData;
    }

    boolean isThisTrueForSomeCriteria(final Object o) {
      return data.contains(o);
    }
  }

and this was found to be much easier to understand even though under the hood there is absolutely no difference. I am not entirely sure whether the byte code would even be any different, but the intuitiveness or readability was improved; so it was a win :)

To be clear; it was not the use an an inner class that was confusing; it was the fact that an inner class was referencing a variable defined in the method, outside of the method that created the inner class and the data.

Lesson for the day (because I keep needing to learn it again ;)); code that is functional is not as valuable as code that is intuitively functional.


Babies babies and more babies (well, only one ;))

So my wife and I am expecting my first child in the middle of May this year and we have been preparing the house for the grand arrival.

After redecorating and recarpeting the entire upstairs (which is not an easy job ; where do you put the contents of your entire upstairs???) we are now looking at purchasing the prerequisites for a sprog.

I have the following questions; how do manufacturers of baby stuff sleep at night; the prices are extortionate. Simply because most people would rather spend more "and be safe" then buy something cheaper; what a rip off. That being said; I am happy to spend the money because I want to be safe ;) :)

Anyways; the following questions:

– should I buy a travel system (which one) or stand alone car seats, buggies, carry cot etc. I anticipate having to purchase a new car seat in the next few years anyways.

– cot bed or just cot?

– where can I find a cot(bed), wardrobe, chest of drawers + baby changing thing that will comfortably fit in a 7ftx7ft room?

– what "essential" thing did you buy/wish you had bought/recommend I buy.

– recycleable nappies or conveient/chuck them away?

Both my wife and I are over 6ft and fairly strong, so weight of baby carrying things isn't so much an option, and we each have our own car with 5 doors, so dedicated baby seat will be fine. Anything we need to push should allow a large walking step though.

I will also be purchasing the following:

– sterilising thingy for the bottles (although we think breast is best, we still need them????)

– bottles (see above)

– millions and gazillions of nappies (see previous list)

– thousands of cloths that the baby will wear either once or twice with compulsory twiddly bits ;)

– video monitor (although which ones do not interface with the existing wireless network?)

anything else?

It is a very exciting time, and I cannot wait; but there is so much choice and it seems to me that buying the wrong thing would be a huge pain in the bum.

Ideas; comments; and don't even get me started on the names :)


February 02, 2006

Anyone know of a Composite proxy?

Any one know of such a beast:
link

I could write one, but why write your own when you can butcher others ….


February 01, 2006

JMock lies :)

So the excellent JMock library contains a constraint called ANYTHING which should, accept any object.

Unfortunately it doesnt. It falls if you provide an enum.

Minor point; but rather unintuitive ;)


February 2006

Mo Tu We Th Fr Sa Su
Jan |  Today  | Mar
      1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28               

Search this blog

Tags

Galleries

Most recent comments

  • Interesting… While I'm not completely convinced in such microbenchmarks, I'm pretty sure that 1ms … by Alexander Snaps on this entry
  • Hello. I bought the book yesterday. I was trying to find the source code for chapter 11 and chapter … by Suleman on this entry
  • http://woosight.net/account/login?username=demo by live mashup demo on this entry
  • Thanks mate ….. This blog was really helpful. by Maaz Hurzuk on this entry
  • Ty. Not directly helpful for my problem, but pointed me in the right direction. You will also get th… by Mike E. on this entry

Blog archive

Loading…
Not signed in
Sign in

Powered by BlogBuilder
© MMXX