3

Say we have a method changeUserName(Long id,String newName) which invokes the repository's findUser(Long id) to find the right user entity and then change its name.
Is it appropriate to thow an IllegalArgmentException when findUser returns null ?
Or should I instead throw a custom UserNotExistException (extends AppException extends RuntimeException) ?


UPDATE:

  • RuntimeException:
    @nachokk @JunedAhsan Actually I deliberately make all the exceptions unchecked , because I think this way makes client code clean , easy for debuging and more safe. As to those "unhandled" ones, I'll catch them all on the top of layers thus avoiding showing them on the UI.
    This is due to the fact that many clients catch checked exceptions and then just ignore it, and in some cases they don't know how to handle it. This is a hidden trouble.

  • Clarification:
    Sorry for my bad English. What I meant is if the changeUserName should throw an IllegalArgumentException, not the findUser method. And another question: how to differentiate illegal argument from business rule violation?

Nozama
  • 244
  • 4
  • 8

3 Answers3

2

You should use UserNotExistException. The name is very declarative of what is happening. In my opinion you should to avoid returning null but if you do you have to document it.

UPDATE

I was thinking and as @JunedAhsan suggest, UserNotExistException could be better a CheckedException (extends from Exception and not RuntimeException).

From this link: Unchecked Exceptions : Controversy

If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.

/**
* @return User found or throw UserNotExistException if is not found
*/
public User findUser(Long id) throws UserNotExistException{
    //some code
    User user = giveMeUserForSomePlace();
    if(user == null){
        throw new UserNotExistException();
    }  
    return user;   
}
nachokk
  • 14,363
  • 4
  • 24
  • 53
  • Not a problem, it didn't require much translation :) – robjohncox Aug 11 '13 at 04:15
  • Will this code compile without having a throws clause in method definition? – Juned Ahsan Aug 11 '13 at 04:18
  • @JunedAhsan he said that is `runtimeException`.. "UserNotExistException (extends AppException extends RuntimeException" – nachokk Aug 11 '13 at 04:21
  • Is there a need to extend RuntimeException in this scenario? – Juned Ahsan Aug 11 '13 at 04:23
  • @JunedAhsan i follow what he wrote but it's debatable if it has to be a checked exception or unchecked exception, i mean this is something that happen in runtime execution. – nachokk Aug 11 '13 at 04:26
  • thx guys! Sorry for my poor English :-( ... it might be ambiguous, but I meant if the `changeUserName` should throw an IllegalArgumentException. – Nozama Aug 11 '13 at 04:56
  • And @nachokk, is it ok to throw a more generic `ObjectNotExistException` instead of `UserNotExistException` from the `findUser` method ? How about the situation where I might wanna test if a user exists? Should I provide another `tryToFindUser` that returns null to avoid using try-catch'es everywhere? – Nozama Aug 11 '13 at 05:04
  • @Nozama yes you can throw `ObjectNotExistException` and in message put that user not exist, but i prefer subclassing exceptions to be more specifics, but i think if you subclass a lot is also bad. If you want want to provide if user exist you should make a `Boolean` method without throwing exception. – nachokk Aug 11 '13 at 05:19
  • @JunedAhsan i think you are right, it has to be checked but always it's depends of the context, i update answer :) – nachokk Aug 11 '13 at 05:29
  • 1
    @nachokk now you deseve an upvote :-) but please correct my name there it is not Ahsad .........aghhhhhhhhhh – Juned Ahsan Aug 11 '13 at 05:30
1

It depends on how you handle exceptions.

IllegalArgumentException is ok if you only display error report by using e.getMessage() and you don't care repetitive string appending code.

Here is some advantage I find by using custom exceptions:

1. Reduce reptetive code:

Let's say changeUserName is surely not the only case you'll load User, so this code snippet below will happen everytime you invoke repository.findUser(Long id)

if (user == null) {
    throw new IllegalArgumentException("No such user found with given id["+ userId +"]");
}

On the other hand, an ad-hoc exception is much more handy:

if (user == null) {
     throw new UserNotExistException(userId);
}

public class UserNotExistException extends RuntimeException {
     public UserNotExistException(Long id) {
         super("No such user found with given id["+ id +"]");
     }
}

2. You need more support from your exceptions:

Maybe you need to return status code or something like that. An custom exception hierachy may do some help:

see this answer for detail.

Community
  • 1
  • 1
Yugang Zhou
  • 7,123
  • 6
  • 32
  • 60
  • thx @Hippom. In my project, I designed `UserNotExistException` extending `AppException`, which means it is for `business rule violation`. It's different from `changeUserName(-123,"Xxx")` where '-123' is absolutely an illegalArgument. The problem is , how can I differenciate them? – Nozama Aug 11 '13 at 06:55
  • @Nozama Why would you differenciate them? I mean usaually neither of "normal user not exist" nor “a meanless -123” is unrecoverable. – Yugang Zhou Aug 11 '13 at 10:57
  • Yes they are both unrecoverable. But because -123 is more likely to be a program error (I might want it to be showing `500 Internal Error` page) , while `UserNotExist` may happen when somebody tries to access a `removed` user's profile in a multi-user environment, and I want to show him a `404 Not Found` or something making sense ... – Nozama Aug 11 '13 at 11:53
  • @Nozama hmm.. then I suggest throw IllegalArgumentException if there is no physical record in database and throw UserNotExistException if the user does exsit but broke some business rules. – Yugang Zhou Aug 11 '13 at 12:23
0

I would too suggest to use UserNotExistException but with a difference that instead of it being unchecked exception (by virtue of extending RuntimeException), make it checked exception (extending Exception if AppException is not doing this already).

This will make sure that caller of changeUserName handles UserNotExistException exception and make the code a bit robust.

Santosh
  • 17,667
  • 4
  • 54
  • 79