Optional with multiple exceptions

I have the following code snippet that I want to rewrite using optionals

public User signup(UserDTO userDTO) throws Exception {
    User user = modelMapper.map(userDTO, User.class);
    
    if (userRepo.findByEmail(user.getEmail()).isPresent()) {
        throw new EmailAlreadyUsedException();
    }
    
    if (userRepo.findByUsername(user.getUsername()).isPresent()) {
        throw new UsernameAlreadyUsedException();
    }
    
    user.setId(UUID.randomUUID().toString());
    // set other stuff like encoded password
    userRepo.save(user);
}

With optionals, I could come up with following.

public User signup(UserDTO userDTO) throws Exception {
    return Optional.of(userDTO)
            .map(u -> modelMapper.map(u, User.class))
            .map(user -> {
                user.setId(UUID.randomUUID().toString());
                // set other stuff like encoded password

                // check email and username if they exist

                // save
                userRepo.save(user);
                return user;
            }).orElseThrow(Exception::new);
}

I am stuck at the part that I cannot throw specific exception depending on username and email. I can return null if one of them already exist in db and it will cause orElseThrow to work but with same Exception type. I want two seperate exception for two different case. How can I handle this?

Answer

I prefer the Optional usage which is more Functional.

The thing is that CheckedException's were not designed to work with functional style on Java. The method .map of Optional receives a Function which does not throws a Exception. Just convert your exceptions to RuntimeException's and will work as expected.

…BUT be careful with the instantiating throwables (especially with the param writableStackTrace, configure at false and should be fine), take a look at: The hidden performance costs of instantiating Throwables .

If you are interested in Functional Programming approach in Java, take a look at Vavr too, very nice library and support CheckedException's on Option.