Utilicé Spring Boot para desarrollar un proyecto de shell utilizado para enviar correos electrónicos, por ejemplo
sendmail -from foo@bar.com -password foobar -subject "hello world" -to aaa@bbb.com
Si faltan los argumentos from
y password
, utilizo un remitente y una contraseña predeterminados, por ejemplo, [email protected]
y 123456
.
Entonces, si el usuario pasa el from
argumento, también debe pasar el password
argumento y viceversa. Es decir, ambos son no nulos o ambos son nulos.
¿Cómo verifico esto con elegancia?
Ahora mi camino es
if ((from != null && password == null) || (from == null && password != null)) {
throw new RuntimeException("from and password either both exist or both not exist");
}
From
dirección de correo electrónico no siempre es el nombre de autenticación SMTP.Respuestas:
Hay una manera de usar el operador
^
( XOR ):La
if
condición será verdadera si solo una variable es nula.Pero creo que generalmente es mejor usar dos
if
condiciones con diferentes mensajes de excepción. No puede definir qué salió mal con una sola condición.Es más legible y mucho más fácil de entender, y solo requiere un poco más de tipeo.
fuente
!=
dos bools?!=
. Alucinante. Y esa es una gran cantidad de votos a favor en el comentario. Y, para agregar calidad a este comentario, sí, también creo que es mejor dar un mensaje de error diferente para un caso de error diferente, ya que el usuario sabrá mejor cómo corregir el error.if
cláusulas: el mensaje en la excepción lo documenta muy bien (edité la pregunta, pero no aparecerá hasta que sea aceptada)Bueno, parece que estás tratando de verificar si la condición de "nulidad" de los dos es la misma o no. Podrías usar:
O hacerlo más explícito con variables auxiliares:
fuente
^
hace. :-)^
dice "Hola, mis operandos son booleanos" de una manera que!=
no. (Aunque desafortunadamente este efecto se ve disminuido por la necesidad de verificar "mis operandos pueden ser numéricos, y podría no ser un operador relacional en este momento", lo que, según creo, es una desventaja). Su estatus de héroe no disminuyó, a pesar de estar en desacuerdo conmigo :-)from
ypassword
ambos deben ser nulos o ambos no deben ser nulos". Tal vez solo somos yo y mi inexperiencia, pero prefiero la solución más legible como en la respuesta de @ stig-hemmer, incluso si cuesta otras 3 líneas de código. Supongo que no entiendo de inmediatobool != bool
, no es intuitivo.^
operador es un operador bit a bit; en realidad no implica que sus operandos sean booleanos. El operador booleano xor esxor
.Personalmente, prefiero legible a elegante.
fuente
IllegalArgumentException
lugar de unaRuntimeException
Ponga esa funcionalidad en un método de 2 argumentos con la firma:
Esto ahorra espacio en el método real que le interesa y lo hace más legible. No hay nada de malo con nombres de métodos ligeramente verbosos y no hay nada de malo con métodos muy cortos.
fuente
((from == null) != (password == null))
que es muy fácil de entender también. Hay algo mal con los métodos no útiles.Se utilizaría
Objects.isNull(Object)
una solución Java 8 , suponiendo una importación estática:Para Java <8 (o si no le gusta usar
Objects.isNull()
), puede escribir fácilmente su propioisNull()
método.fuente
from == null != password == null
lo mantiene todo en el mismo marco de la pila, pero usandoObjects.isNull(Object)
empujones innecesarios y saca dos cuadros. Objects.isNull (Object) está ahí porque 'Este método existe para ser utilizado como Predicate' (es decir, en flujos).Objects.isNull()
- usted puede escribir el suyo si lo prefiere - pero en lo que respecta a la legibilidad, creo que usarisNull()
es mejor. Por otra parte necesita paréntesis adicionales para hacer la sencilla compilación expresión:from == null != (password == null)
.(val == null)
es tanto la facilidad proporcionada con el propósito de comparar con nulo, me resulta difícil superar dos invocaciones de métodos grandes y gordos que me miran a la cara, incluso si el método es bastante funcional, en línea y bien ... nombrada. Aunque solo soy yo. Recientemente he decidido que soy un poco extraño.Aquí hay una solución general para cualquier número de cheques nulos
Usos
fuente
Dado que desea hacer algo especial (usar valores predeterminados) cuando faltan el remitente y la contraseña, primero debe manejar eso.
Después de eso, debe tener un remitente y una contraseña para enviar un correo electrónico; lanzar una excepción si falta alguno.
Un beneficio adicional es que, si alguno de sus valores predeterminados es nulo, también se detectará.
Dicho esto, en general creo que el uso de XOR debería ser permisible cuando ese es el operador que necesita. Que es una parte de la lengua, no sólo un truco que funciona debido a un arcano compilador de errores.
Una vez tuve un orker que descubrió que el operador ternario era demasiado confuso para usar ...
fuente
Me gustaría sugerir otra alternativa que es cómo escribiría realmente este fragmento de código:
Para mí, esta parece ser la forma más natural de expresar esta condición, lo que hace que sea fácil de entender para alguien que tenga que leerla en el futuro. También le permite enviar mensajes de diagnóstico más útiles y tratar la contraseña innecesaria como menos grave y facilita la modificación, lo que es bastante probable para tal condición. Es decir, puede descubrir que dar una contraseña como argumento de línea de comando no es la mejor idea y puede permitir leer la contraseña desde la entrada estándar opcionalmente si falta el argumento. O es posible que desee ignorar silenciosamente el argumento de contraseña superfluo. Cambios como estos no requieren que reescribas todo el asunto.
Además de eso, ejecuta solo el número mínimo de comparaciones, por lo que no es más caro que las alternativas más "elegantes" . Aunque el rendimiento es un problema muy poco probable aquí porque comenzar un nuevo proceso ya es mucho más costoso que una verificación nula adicional.
fuente
Creo que una forma correcta de manejar esto es considerar tres situaciones: se proporcionan 'desde' y 'contraseña', ninguna de las dos, se proporciona una combinación de ambas.
Parece que la pregunta original quiere romper el flujo si es una entrada incorrecta, pero luego tendrán que repetir algo de la lógica más adelante. Quizás una buena declaración de lanzamiento podría ser:
fuente
Aquí hay una manera relativamente directa que no involucra ningún Xor og largo ifs. Sin embargo, requiere que sea un poco más detallado, pero por el lado positivo, puede usar las Excepciones personalizadas que sugerí para obtener un mensaje de error más significativo.
fuente
Nadie parece haber mencionado el operador ternario :
Funciona bien para verificar esta condición particular, pero no generaliza más allá de dos variables.
fuente
^
,!=
con dos bools o dosif
sa == null ? (b == null? "both null" : "a null while b is not") : (b ==null? "b null while a is not")
Como veo sus intenciones, no es necesario verificar siempre ambas nulidades exclusivas sino verificar si
password
es nulo si y solo sifrom
no lo es. Puede ignorar elpassword
argumento dado y usar su propio valor predeterminado sifrom
es nulo.Escrito en pseudo debe ser así:
fuente
password
sin suministrarfrom
, es posible que tenga la intención de anular la contraseña, pero mantener la cuenta predeterminada. Si el usuario hace eso, es una instrucción no válida y se les debe informar. El programa no debe continuar como si la entrada fuera válida, y seguir adelante e intentar usar la cuenta predeterminada con una contraseña que el usuario no especificó. Lo juro por programas como ese.Me sorprende que nadie haya mencionado la solución simple de crear
from
ypassword
campos de una clase y pasar una referencia a una instancia de esa clase:aquí
from
podría ser nulo o no nulo y si no es nulo, ambos campos tienen valores no nulos.Una ventaja de este enfoque es que el error de hacer que un campo pero no el otro campo sea nulo se activa donde se obtiene inicialmente la cuenta, no cuando se ejecuta el código que usa la cuenta. Para cuando se ejecuta el código que usa la cuenta, es imposible que los datos no sean válidos.
Otra ventaja de este enfoque es más legible ya que proporciona más información semántica. Además, es probable que requiera el nombre y la contraseña juntos en otros lugares, por lo que el costo de definir una clase adicional se amortiza en varios usos.
fuente
new Account(null, null)
que arrojará un NPE a pesar de que la cuenta con nombre nulo y contraseña sigue siendo válida.null
lugar de unAccount
. No pasaríasnull
alAccount
constructor.