Java semantics - Is there a way to write this better?

Note: This is simply a workaround for your quite monstrous method. As mentioned in the comments, your endpoint tries to do too much. It would be much better to create many different endpoints which all only need the required parameters. Makes it a lot easier to understand than just to see 10+ if-else statements


You could create a data-class containing all the possible parameters:

public class UserRequest {
    private String lastName;
    private String firstName;

    // more fields, constructors, getters, setters etc.
}

Then have an interface looking something like this:

public interface UserRequestResolver {
    User resolve(UserRequest request);
}

This interface can then be implemented to depend on a given param, if it exists. Return a found User or simply null.

Next step is, create a List<UserRequestResolver> resolvers, and add the different implementations, with Java8+ you can use lambdas:

resolvers.add(r -> r.getParam1() != null ? getUserByParam1(r.getParam1()) : null);
resolvers.add(r -> {
    if(r.getFirstName() == null && r.getLastName()) return null;
    return getUserByName(r.getFirstName(), r.getLastName());
});
// etc.

Then when receiving a UserRequest you can simply iterate over resolvers and take the first return value which is not null:

for(UserRequestResolver resolver : resolvers) {
    User user = resolver.resolve(request);
    if(user != null) return user;
}
throw costumException;

If you're a fan of Streams, then you can replace the for-loop above with this:

return resolvers.stream()
    .map(resolver -> resolver.resolve(request))
    .filter(Objects::nonNull)
    .findFirst()
    .orElseThrow(() -> costumException);