Spot the mistake

Saturday, November 17, 2007 at 01:02PM
Posted by Registered CommenterParag

Can you spot the mistake in this code?

// BROKEN - throws NoSuchElementException!
for (Iterator i = suits.iterator(); i.hasNext(); )
for (Iterator j = ranks.iterator(); j.hasNext(); )
sortedDeck.add(new Card(i.next(), j.next()));
If not, check this article on the Java for...each loop. 

 

Never invoke a public method from another public method

Saturday, October 20, 2007 at 10:04PM
Posted by Registered CommenterParag

In the previous post we saw how subclassing from a class not designed for inheritance, can be dangerous. Using composition instead of inheritance would have solved the problem. But what was the crux of the problem? Could such a trap have been avoided? Could AbstractCollection have been implemented so that such a situation would not have arisen in the first place?

The real problem was the class AbstractCollection which was not designed properly for inheritance. It is a non-final class with a public method addAll(Collection c) which invokes another non-final public method add(Object o).

How should AbstractCollection have implemented add(Object o) and addAll(Collection c) to prevent such a problem?

I do not know if this problem has been fixed in OpenJDK. They may have not been able to do so to maintain backwards compatibility. You can check out the sources from their website.

In the next post we will discuss an idiom for preventing such a situation. 

Discuss this post in the learning forum.

A Java example showing the dangers of implementation inheritance

Tuesday, October 16, 2007 at 11:30AM
Posted by Registered CommenterParag

I ended my previous post with a paragraph from Josh Bloch's book, Effective Java. In his book, Josh explains why inheriting classes from a different package (especially inheriting from a class that may not be designed and documented for inheritance) can be dangerous. Below you will find Josh's example (from Effective Java) that explains the concept. Many many thanks to Josh Bloch for graciously giving me permission to reproduce the example here :-)

The class InstrumentedHashSet is a subclass of HashSet, that maintains a count of the number of objects added. It overrides the add(Object o) and addAll(Collection c) methods from HashSet to maintain a count of objects added to it. These methods increment the count and then delegate responsibility for adding the element to HashSet. The number of objects added can be obtained from the method getAddCount().

This seems like a reasonable way to count objects added to the Set. Unfortunately it's not. But first let's have a look at the code of InstrumentedHashSet.

 InstrumentedHashSet.JPG

 

Below is a test case for the addAll(Collection c) method of InstrumentedHashSet. By the way, this test was written by me, so if there is anything wrong with it, it's entirely my fault :-)

 

InstrumentedHashSetTest.JPG 

 

Now let us run the unit test.

InstrumentedHashSetTestReport.JPG 

Oops :-( we expected a count of 3, but looks like InstrumentedHashSet is reporting 6. Now, how did that happen???

Look again at InstrumentedHashSet. The method addAll(Collection c) calls super.addAll(c) after incrementing the count. This ends up invoking a method implemented in AbstractCollection in the JDK (ver 1.6). It has implemented addAll(Collection c) to iterate through the given Collection and invoke add(Object o) for every element in the Collection. Since we have overriden add(Object o), it is our implementation that get's called. The count is added for every element of the Collection in addAll(Collection c) as well as in add(Object o), resulting in the count increasing by 2 for every object. That's the reason we got a count of 6 instead of 3.

So to summarize. Be very careful when you subclass a class that is not in your control. It might be safer to use composition that inheritance in such situations. It is also equally important to remember that if you create a non-final class with public methods, please design it carefuly to ensure that it does not break a subclass that may extend from it. If there are any caveats, be sure to document them clearly.

Inheritance and composition

Saturday, September 29, 2007 at 11:29PM
Posted by Registered CommenterParag


  • Inheritance is used for
    • Code resuse
    • To support polymorphism
  • Disadvantages of inheritance
    • Difficult to change the interaface of the subclass
    • Superclass is always instantiated
    • Can get complex and unmanageable
  • Composition is used for code reuse
  • Disadvantages of composition
    • We cannot use polymorphism
    • We cannot extend the system by adding subclasses
    • May have a slight performance overhead
  • Usage
    • Inheritance: IS- A
    • Composition: HAS - A

Example 1

public class Car {

    private Engine engine;

    public void start() {}

    public void stop() {}



public class SUV extends Car{

    public void start() {} //overrides the start method from Car
 

    public void fourByFourMode() {}

}



Example 2:

public void someMethod() {
    Car c = new SUV();
    c.start();
}



Example 3:

public class Car {

    private Engine engine;

    public void start() {
      engine.start();
        //maybe do something more
    }

    public void stop() {}

}
Java2html

 

I will end this post with the first paragraph from Item 17, of Joshua Bloch's excellent book, Effective Java. In the book this paragraph is followed by a code example that explains this very well, however, I am not sure if I can include the example under fair use Crying..

Inheritance is a powerful way to achieve code reuse, but it is not always the best tool for
the job. Used inappropriately, it leads to fragile software. It is safe to use inheritance within
a package, where the subclass and the superclass implementation are under the control of the
same programmers. It is also safe to use inheritance when extending classes specifically
designed and documented for extension (Item 15). Inheriting from ordinary concrete classes
across package boundaries, however, is dangerous. As a reminder, this book uses the word
“inheritance” to mean implementation inheritance (when one class extends another).
The problems discussed in this item do not apply to interface inheritance (when a class
implements an interface or where one interface extends another).

Can you think of a situation where subclassing an existing class can break the semantics of your code, because of a certain undocumented feature of the superclass? Let me give you a hint. Assume a collection class has 2 methods

add(Object o)  - to add the specified object to the collection

addAll(Collection c) - to add each element of the specified Collection to this collection.

Now assume that addAll(Collection c) internally invokes add(Object o) for every object in the collection.

Can you think of a situation that will result in a bug, if we subclass this class and override the above methods to add a functionality that keeps track of how many elements have been added to the collection?

Resources:

  1. Compostion vs. Inheritance
  2. Composition and interfaces

High cohesion

Friday, September 21, 2007 at 11:59PM
Posted by Registered CommenterParag


[Time: 4 mins]

  • Stuff that goes together, stays together
  • Easy to discover relevant code
  • Levels of cohesion
    • packages
    • classes
    • methods 
 
So in very simple words, cohesion is keeping related stuff together so we can find what we want without too much difficulty. 
 

 

Example 1
public class Student {
    //cohesive methods
    public void registerForCourse() {}
    public void deregisterFromCourse() {}
    viewTranscripts() {}
    //methods below are not in synch with the responsibilities of the Student class
    //hence cohesion is broken
    submit grades() {}
    submitCourseSchedule() {}
 
Java2html

Resources:
 

Loose coupling

Friday, September 21, 2007 at 06:37PM
Posted by Registered CommenterParag


[Time: 4:32 mins]

Loose (or low) coupling means (in a generic sense) that an entity can interact with another entity without being concerned with the internal implementation, and through a stable interface. Low coupling is implemented by using principles of information hiding. When two entities are loosely coupled, internal changes in one of them do not affect the other. The calling method is coupled to the called method and not it's implementation. Since we have already discussed encapsulation and information hiding in detail, I will not repeat it here.

  • Loose coupling is achieved with information hiding
  • And by programming to the interface rather than the implementation

 

Example 1: Tightly coupled system 

public void aMethod() { 

    ArrayList myList = new ArrayList();

    doSomethingWithList(list)



private void doSomethingWithList(ArrayList list) {



Example 2: Loosely coupled system 

public void aMethod() { 

    List
myList = new ArrayList();

    doSomethingWithList(list)



private void doSomethingWithList(List list) {


Java2html
 
  • Loose coupling contains the scope of change when an implementation is modified 


Don't repeat yourself

Saturday, September 15, 2007 at 10:02PM
Posted by Registered CommenterParag

 

The code says everything once and only once, which is the essence of good design. -- Martin Fowler


[Time: 4:44 mins]

 

  • Repititive code makes maintainance more difficult
    • There are more places to change
    • We may forget to change some of them
    • Increases probability of bugs
  • Types of repitition
    • In methods in a class
    • Accross the entire software 

Example 1: DRY violated
public class Account {
  public void transferFunds(double amt, Account dest) {
    //transfer funds
    //generate email... create connection
    //create message
    //dispatch email
  }

  public void delete() {
    //delete account
    //generate email... create connection
    //create message
    //dispatch email
  }
}
Java2html
Example 2: DRY honoured
public class Account {
  public void transferFunds(double amt, Account dest) {
    //transfer funds
    dispatchEmail(...);
  }

  public void delete() {
    //delete account
    dispatchEmail(...);
  }

  public dispatchEmail() {
    //generate email... create connection
    //create message
    //dispatch email
  }
}
Java2html

Resources:

  1. http://www.artima.com/intv/dry.html
  2. Don't repeat yourself
  3. Once and only once
  4. Code harvesting

 


 

Keep it simple

Wednesday, September 12, 2007 at 09:49PM
Posted by Registered CommenterParag


[Time: 5:37 mins]

One should not increase, beyond what is necassary, the number of entities required to explain anything - Occams Razor

  • KISS helps keep software manageable
  • The UNIX kernel is an example of a functionally complex software implemented in simple design
  • Intentional complexity
    • Enthusiasm to use design patterns
    • Enthusiasm to make a system uber flexible
    • Feature bloat
  • Unintentional complexity
    • Maintainance quick fixes
    • Laziness in refactoring

 

 

Page | 1 | 2 | 3 | 4 | 5 | Next 8 Entries