Dexters
Dexters

Reputation: 2495

JAVA api validation/Exception handling

How to handle error conditions when writing a Java API/Utility

This is my Implementation for my API interface

public void bin2zip(InputStream[] is,OuputStream os, String[] names)
{
   //if number of streams and number of names do not match do something 
}

What I am trying to do is handling a case when the length of the is != length of name.

How do i handle this. I dont want my API to do some work until ArrayOutOfBound exception to be thrown. I want to catch this early.

One solution is something like this:

if it does not match I throw

if(is.length==names.length)
            throws new Exception("ParemeterValidationException: The inputstream array and name array length should match");
if(containsInvalidFileName(names))
            throws new Exception("ParemeterValidationException: The names array length should contain valid filenames");

Also, can this be done compile time using DataDependency (I can make ValidationClass for the API and make sure the developer get hold of this object to pass on to this conversion API) or the runtime exception is the best way?

I believe doing a ValidationClass will make API use complicated

I did go through some materials (if anyone interested), but need some directions.

  1. http://lcsd05.cs.tamu.edu/slides/keynote.pdf
  2. Java: checked vs unchecked exception explanation
  3. http://docs.oracle.com/javase/tutorial/collections/interoperability/api-design.html

Upvotes: 3

Views: 530

Answers (2)

Elemental
Elemental

Reputation: 7476

I think your solution of comparing the array lengths is perfectly appropriate. I think in this case you should throw an IllegalArgumentException; this exception is defined in the standard and used by most standard functions doing this kind of checking.

Many standard libraries use this kind of interface it is easily understood.

That said I think you should prefer an interface that simply doesn't facilitate such misuse such as that suggested by @Eric - the library everybody likes to use is the one that works first time every time because it's too simple to mess up.

Upvotes: 0

Eric Stein
Eric Stein

Reputation: 13672

Wherever possible, don't let end users screw it up.

public final class Bin2Zipper {
    private final List<InputStream> inputStreams = ...;
    private final List<String> names = ...;    

    public BinZipper() {
    }

    public void add(final InputStream is, final String name) {
        this.inputStreams.add(is);
        this.names.add(name);
    }

    public void bin2zip(final OutputStream os) {
        // ...
    }
}

A fluent interface might even be better. Then your code would look like:

Bin2Zipper.add(is1, name1).add(is2, name2).add(is3, name3).toZip(os);

public final class Bin2Zipper {

    private final List<InputStream> inputStreams = ...;
    private final List<String> names = ...;

    private Bin2Zipper(final InputStream is, final String name) {
         this.inputStreams.add(is);
         this.names.add(name);
    }

    public static Bin2Zipper add(final InputStream is, final String name) {
         return new Bin2Zipper(is, name);
    }

    public Bin2Zipper add(final InputStream is, final String name) {
         this.inputStreams.add(is);
         this.names.add(name);
         return this;
    }

    public void zip(final OutputStream os) {
        ...
    }
}

Where these fall down is when the client starts off with the two arrays. In that case, it can be annoying for them to have to loop over all the entries themselves. I think it's still worth it. If you don't, then you'll have to compare the sizes of the inputs right away. You almost certainly want to throw an unchecked exception, probably an IllegalArgumentException like Vince said.

Upvotes: 3

Related Questions