Проверьте два аргумента в Java, либо оба не null, либо оба null элегантно



я использовал spring boot для разработки проекта оболочки, используемого для отправки электронной почты, например



sendmail -from [email protected] -password  foobar -subject "hello world"  -to [email protected]


если from и password аргументы отсутствуют, я использую отправитель и пароль по умолчанию, например [email protected] и 123456.



так что если пользователь передает from аргумент они также должны передать password аргументом, и наоборот. То есть, либо оба являются ненулевыми, либо оба являются нулевыми.



как я могу проверить это элегантно?



теперь мой путь это



if ((from != null && password == null) || (from == null && password != null)) {
throw new RuntimeException("from and password either both exist or both not exist");
}
207   13  

13 ответов:

есть способ с помощью ^ (XOR) оператор:

if (from == null ^ password == null) {
    // Use RuntimeException if you need to
    throw new IllegalArgumentException("message");
}

The if условие будет true, если только одна переменная имеет значение null.

но я думаю, что обычно лучше использовать два if условия с различными сообщениями об исключениях. Вы не можете определить, что пошло не так через одно условие.

if ((from == null) && (password != null)) {
    throw new IllegalArgumentException("If from is null, password must be null");
}
if ((from != null) && (password == null)) {
    throw new IllegalArgumentException("If from is not null, password must not be null");
}

это более читабельно и гораздо легче понять, и это займет всего лишь немного дополнительного ввода.

Ну, похоже, вы пытаетесь проверить, является ли условие "nullity" из двух одинаковым или нет. Вы могли бы использовать:

if ((from == null) != (password == null))
{
    ...
}

или сделать его более четким с помощью вспомогательных переменных:

boolean gotFrom = from != null;
boolean gotPassword = password != null;
if (gotFrom != gotPassword)
{
    ...
}

лично я предпочитаю читаемый элегантный.

if (from != null && password == null) {
    throw new RuntimeException("-from given without -password");
}
if (from == null && password != null) {
    throw new RuntimeException("-password given without -from");
}

поместите эту функциональность в Метод 2 аргумента с подписью:

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

это экономит место в фактическом методе, который вас интересует, и делает его более читаемым. Нет ничего плохого в слегка подробных именах методов, и нет ничего плохого в очень коротких методах.

решение Java 8 будет использовать Objects.isNull(Object), предполагая, что статический импорт:

if (isNull(from) != isNull(password)) {
    throw ...;
}

для Java Objects.isNull()), вы можете легко написать свой собственный isNull() метод.

вот общее решение для любого количества нулевых проверок

public static int nulls(Object... objs)
{
    int n = 0;
    for(Object obj : objs) if(obj == null) n++;
    return n;
}

public static void main (String[] args) throws java.lang.Exception
{
    String a = null;
    String b = "";
    String c = "Test";

    System.out.println (" "+nulls(a,b,c));
}

использует

// equivalent to (a==null & !(b==null|c==null) | .. | c==null & !(a==null|b==null))
if (nulls(a,b,c) == 1) { .. }

// equivalent to (a==null | b==null | c==null)
if (nulls(a,b,c) >= 1) { .. }

// equivalent to (a!=null | b!=null | c!=null)
if (nulls(a,b,c) < 3) { .. }

// equivalent to (a==null & b==null & c==null)
if (nulls(a,b,c) == 3) { .. }

// equivalent to (a!=null & b!=null & c!=null)
if (nulls(a,b,c) == 0) { .. }

поскольку вы хотите сделать что-то особенное (использовать значения по умолчанию), когда и отправитель, и пароль отсутствуют, сначала обработайте это.
После этого у вас должен быть как отправитель, так и пароль для отправки электронной почты; бросьте исключение, если оно отсутствует.

// use defaults if neither is provided
if ((from == null) && (password == null)) {
    from = DEFAULT_SENDER;
    password = DEFAULT_PASSWORD;
}

// we should have a sender and a password now
if (from == null) {
    throw new MissingSenderException();
}
if (password == null) {
    throw new MissingPasswordException();
}

дополнительным преимуществом является то, что в настройках по умолчанию будет null, что будет обнаружена также.


сказав, что в общем Я думаю, что использование XOR должно быть допустимым, когда это тот оператор, который вам нужен. Это и часть языка, а не просто какой-то трюк, который работает из-за тайной ошибки компилятора.
Однажды у меня был коллега, который нашел тернарный оператор слишком запутанным, чтобы использовать...

Я хотел бы предложить другую альтернативу, которая заключается в том, как я бы на самом деле написал этот кусок кода:

if( from != null )
{
    if( password == null )
        error( "password required for " + from );
}
else
{
    if( password != null )
        warn( "the given password will not be used" );
}

кроме того, что он выполняет только минимальное количество сравнений, так что это не дороже, чем больше "Элегант" альтернативы. Несмотря на то производительность здесь очень маловероятна, потому что запуск нового процесса уже намного дороже, чем дополнительная нулевая проверка.

Я думаю, что правильный способ справиться с этим-рассмотреть три ситуации: оба " от " и "пароль" предоставляются, ни один из них не предоставляется, сочетание двух из них предоставляется.

if(from != null && password != null){
    //use the provided values
} else if(from == null && password == null){
    //both values are null use the default values
} else{
   //throw an exception because the input is not correct.
}

похоже, что исходный вопрос хочет нарушить поток, если он неверен, но тогда им придется повторить некоторые логические действия позже. Возможно, хорошим заявлением броска может быть:

throw new IllegalArgumentException("form of " + form + 
    " cannot be used with a "
    + (password==null?"null":"not null") +  
    " password. Either provide a value for both, or no value for both"
);

вот относительно прямой путь, который не включает в себя никаких Xor OG длительных ifs. Это, однако, требует от вас быть немного более подробным, но с другой стороны, вы можете использовать пользовательские исключения, которые я предложил, чтобы получить более значимое сообщение об ошибке.

private void validatePasswordExists(Parameters params) {
   if (!params.hasKey("password")){
      throw new PasswordMissingException("Password missing");
   }
}

private void validateFromExists(Parameters params) {
   if (!params.hasKey("from")){
      throw new FromEmailMissingException("From-email missing");
   }
}

private void validateParams(Parameters params) {

  if (params.hasKey("from") || params.hasKey("password")){
     validateFromExists(params);
     validatePasswordExists(params);
  }
}

Кажется, никто не упоминал тернарный оператор:

if (a==null? b!=null:b==null)

прекрасно работает для проверки этого конкретного условия, но не обобщает хорошо за две переменные.

как я вижу ваши намерения, нет необходимости всегда проверять оба исключительных нуля, но проверить, если password имеет значение null тогда и только тогда, когда from не null. Вы можете игнорировать данный password аргумент и использовать свой собственный по умолчанию, если from имеет значение null.

написано псевдо должно быть так:

if (from == null) { // form is null, ignore given password here
    // use your own defaults
} else if (password == null) { // form is given but password is not
    // throw exception
} else { // both arguments are given
    // use given arguments
}

Я удивлен, что никто не упомянул о простом решении сделать from и password поля класса и передачи ссылки на экземпляр этого класса:

class Account {
    final String name, password;
    Account(String name, String password) {
        this.name = Objects.requireNonNull(name, "name");
        this.password = Objects.requireNonNull(password, "password");
    }
}

// the code that requires an account
Account from;
// do stuff

здесь from может быть null или не null, и если это не null, оба поля имеют ненулевые значения.

одним из преимуществ этого подхода является то, что ошибка создания одного поля, но не другого поля null запускается там, где изначально получена учетная запись, а не когда код использует учетную запись работает. К моменту выполнения кода, использующего учетную запись, невозможно, чтобы данные были недействительными.

еще одно преимущество этого подхода является более читаемым, поскольку он предоставляет больше семантической информации. Кроме того, вполне вероятно, что вам потребуется имя и пароль вместе в других местах, поэтому стоимость определения дополнительного класса амортизируется в течение нескольких использований.

Comments

    Ничего не найдено.