0

I have the following problem: In a servlet I need to handle different inputs (in the following Lists) from an already implemented supplier (just the interface is known). This handling only makes sense, if the Lists have the same size (which almost surely is the case, unless the supplier-function messed up), hence I wanted to use assert on the sizes (else it will throw and Index out of Bound Exception or something similar much later, which would be hard to debug for later developers). The problem here is, my program will run on a server without the -ea argument. My question is: Is it still possible to assert the proper way:

try{
    List listA = supplier.getListA();
    List listB = supplier.getListB();
    assert listA.size()==listB.size();

    List listC = supplier.getListC();
    assert listA.size()==listC.size();
}
catch(AssertionError error){
   //error handling
}

or am I thrown back to Exceptions:

try{
    List listA = supplier.getListA();
    List listB = supplier.getListB();
    if(listA.size()!=listB.size())
        throw new RuntimeException();

    List listC = supplier.getListC();
    if(listA.size()!=listC.size())
        throw new RuntimeException();
}
catch(RuntimeException exception){
   //error handling
}

For the readability the former way is strongly preferred, but wouldn't surely work on the server.

3
  • 1
    I don't find the latter that unreadable but if you like you could do something like JUnit does: provide a class with static methods to get calls like Assert.sameSize(listA, listB) or Assert.equals(listA.size(), listB.size()). Commented Mar 15, 2016 at 14:41
  • What do exceptions buy you that a simple if statement doesn't? It isn't propagating outside of your method, so what's the point? You might as well simply catch the IndexOutOfBounds exception and be done with it. Commented Mar 15, 2016 at 14:54
  • @TMN The problem is, the IndexOutOfBounds exception occurs much later and the root wouldn't be visible (hence proper error handling). The exceptions/errors are saved in a log to be handled at a proper place, an if-statement would result in something like logger.put(new RuntimeException, "description"); Commented Mar 15, 2016 at 14:57

2 Answers 2

2

There are languages designed differently, but in Java, using exceptions for flow control is a brilliant way of shooting yourself in the foot.

Why don't you just make an if statement and check the condition?

List listA = supplier.getListA();
List listB = supplier.getListB();
List listC = supplier.getListC();
if(listA.size()==listB.size() && listA.size()==listC.size()) {
    //happy path :)
} else {
    //sad path :(
}
Sign up to request clarification or add additional context in comments.

3 Comments

The reason is, when the assertion fails, this is pretty close to an exception (the program will fail/throw exceptions at later places/yield unpredictable results). Hence I want to be it, what it is, a severe error (with the proper information). Don't worry, I am not using it for flow-control but for bug hunting, which may occur from foreign software.
I've recently inherited a small project that was written by ex-C++ "coders" that apparently think goto is the new black... Anyway, you can still handle/log the error in the sad path scenario
Since there is a longer flow which should get broken down as soon as one of the supplied values are wrong, the error-throwing solution from Thomas (thought Assert.assertTrue would behave as assert...) seems to be better style in my case. In general I would agree with you, but in this case, this seems to be the better solution. Fun fact: the short termed solution was with several if(...){ /*same error handling over again*/ return;} EDIT: You should better change the if and else to avoid large nested constructs.
1

I'll expand on my comment:

You could either use an external library that contains an Assert class or roll your own, e.g. like this:

class AssertionException extends Exception {
  //content goes here
}

class Assert {
  public void sameSize( Collection<?> a, Collection<?> b ) {
    //TODO: handle null as well
    if( a.size() != b.size() ) {
      throw new AssertionException("some message"); 
    }
  }
}

Then your code becomes:

try{
  List listA = supplier.getListA();
  List listB = supplier.getListB();
  Assert.sameSize( listA, listB );

  List listC = supplier.getListC();
  Assert.sameSize( listA, listC );
 }
catch(AssertionException ex){
  //error handling
}

It's basically the same as language level asserts (errors and exceptions are both throwables anyways, but errors are more often used to express fatal conditions which wouldn't be the case here).

I'll want to reiterate what CptBartender said though: errors and exceptions are a means to express unexpected behavior, i.e. whether to use them or not depends on what your error handling code would do and whether the error condition should occur during normal execution or not.

1 Comment

Thanks for the answer, this works (I am using the Assert-class from JUnit now). And just to give your mind peace: it really is just a way to handle unexpected behavior. The supplier should always return proper values, but I prefer checking it at the right spot, instead of having a long bug hunt in a few years, when the supplier changes or breaks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.