2009-05-13 20 views
12

¿Por qué String.indexOf no utiliza la excepción sino que devuelve -1 cuando no se encuentra la subcadena?¿Por qué String.indexOf no utiliza la excepción pero devuelve -1 cuando no se encuentra la subcadena?

El propósito de esta pregunta es: cuando comenzamos la excepción personalizada.

Creo que evitar la necesidad de devolver el código de error especial es la ruta correcta de diseño.

¿Cuál es su opinión?

+0

Como puede ver en las respuestas, nadie piensa que debería ser una excepción. Pregúntate a ti mismo, si devuelve Integer en lugar de int, esperarías que devuelva null o lanzar una excepción. Dado que es una primitiva, null no está disponible como un tipo de retorno, por lo que se usa -1 en su lugar. – Robin

+0

si devuelve un objeto Integer. nulo es posible. consulte MSFT.net 2.0, int? es una buena solución – ariso

Respuesta

24

Como regla general, si el propósito de un método es verificar algo, entonces la falta de ese algo no debería ser una excepción. Si el método supone que algo es cierto, entonces la ausencia de ese algo sería una excepción. Por lo tanto, "File.exists()" no arroja una excepción FileNotFoundException, pero sí "File.open()".

+0

Creo que Paul tiene la respuesta correcta. porque file.exists() no arroja excepciones. – ariso

18

excepciones son para casos excepcionales, cuando una cadena no contiene una letra, eso no es excepcional, a menos que lo esté utilizando para casos extremos. Si eso es lo que estás haciendo, siempre puedes elegir lanzar tu propia excepción.

+3

+1 para "excepciones son para casos excepcionales". Uno podría preguntarse, "¿por qué File.exists() no lanza un FileNotFoundException en lugar de devolver false"? Concepto similar; usted llama a ambos métodos sabiendo que es bastante probable que la condición sea negativa. – Rob

+0

Quizás se considere bastante normal que un archivo no exista, de lo contrario, ¿por qué tener un método para probarlo en lugar de simplemente asumir que el archivo que usted solicita estará allí? –

3

Es mucho más fácil lidiar con un -1 que atrapar una excepción.

3

también porque las excepciones son caros en términos de rendimiento

1

creo que uno tiene que lanzar una excepción cuando algo inesperado sucede. Dicho esto, una subcadena no encontrada en una Cadena no es tan inesperada, puede suceder, es un resultado razonable.

Estoy de acuerdo con que uno debe tratar de evitar la devolución de códigos de error, pero en este caso solo tenemos dos opciones, cadena encontrada o cadena no encontrada.

15

Lo último que supe de eso fue ...

'Usted lanza una excepción cuando su método de no es capaz de hacer lo que promete ' - Jeff Richter CVC 2ª ed

  • IndexOf() te promete devolver el índice de la primera aparición de un char/string. Hubiera arrojado una excepción si no hubiera podido hacer su trabajo por alguna razón. Hizo su trabajo pero no encontró la cadena y por lo tanto devuelve -1 para transmitir el resultado no encontrado.
  • File.Open() arrojará una excepción FileNotException para una ruta de archivo no existente, ya que no puede hacer lo que promete ... es decir, abrir el archivo especificado.
+2

Agregue aquí los comentarios de Paul. Como regla general, si el propósito de un método es verificar algo, entonces la falta de ese algo no debería ser una excepción. Si el método supone que algo es cierto, entonces la ausencia de ese algo sería una excepción. Por lo tanto, "File.exists()" no arroja una excepción FileNotFoundException, pero sí "File.open()". – ariso

+1

+1 a Paul. De la cita anterior se desprende que cualquier posible resultado/valor de retorno en caso de que el método tenga éxito debe * no * estar en la forma de una excepción. El método solo debería arrojar una excepción para indicar que no pudo cumplir con su deber/razón de ser. – Gishu

+0

La falla está del lado de la Cadena (porque no tiene la Cadena que busca), no en el lado del método. –

3

Además de los argumentos en contra de las excepciones en general, agregaría que -1 puede ser un resultado útil de indexOf y lastIndexOf, no solo de un valor especial. Por ejemplo, para analizar el nombre de archivo de una cadena que pueden o no contener una ruta:

String filename = arg.substring(arg.lastIndexOf('/') + 1); 

Si bien tal vez un ejemplo artificial, esto sería un poco más engorroso con excepciones.

+1

De hecho, lo consideraría un truco. Es hermoso, pero aún así, no está claro si el desarrollador vendrá después de que lo entiendas. Al menos use un comentario ... – sleske

+0

@Sleske ¿Un truco? Un valor de retorno útil no es un truco. ¿Un comentario? ¿Qué le gustaría añadir que no está ya establecido en el JavaDoc de estas funciones (simples)? – eljenso

+3

@eljenso - Estoy de acuerdo en que 'hack' podría ser un poco fuerte. Pero mirar el código NO hace que las intenciones sean claras. Otro programador podría ver muy fácilmente esto y pensar que el autor "olvidó" el caso no '/'. Inteligente y fácil de mantener no siempre van de la mano. – kenj0418

2

Muchas buenas respuestas aquí. Este es un problema de diseño donde el pragmatismo ha prevalecido sobre las siguientes "reglas".En este caso, hay algunas "reglas" en conflicto:

  • evitar el uso de valores especiales como datos de retorno (no auto-documentado, requiere desarrollador para manejar el valor especial de una manera distinta de otro código)

vs

  • no lanzar excepciones durante la ejecución de la rutina de código, sólo cuando ocurre algo inesperado

Estoy de acuerdo con esta decisión de diseño. Sin embargo, si no lo hace, siempre puede escribir su propio código para verificar la existencia de una cadena antes de verificar su índice. No seas prisionero de tu idioma, dóblalo a tu voluntad. ¡Los idiomas están destinados a ser torturados!

6

returning -1 es casi tan horrible como lanzar una excepción. La forma correcta sería usar el tipo de opción si el lenguaje simplemente lo admite mejor. En una situación normal en la que hay resultados, envuelve el resultado en un objeto y lo devuelve. De lo contrario, devuelve un objeto que representa la situación "sin resultado".

En el sitio de la llamada, debe verificar cuál fue; no se puede simplemente usar el valor de retorno debido a su tipo súper, deben inspeccionarse mediante la coincidencia de patrones.

En la sintaxis de pseudo:

class Option[a] = Some[a] | None, 

donde a es el parámetro de tipo genérico, A veces representa un resultado con valor y Ninguno no resultado sin valor.

en caso de indexOf que tendría:

Option[Integer] indexOf(char c) = { 
    if(found) return Some(index) 
    else return None 
} 

y el uso que de esta manera:

result = "uncle".indexOf('c') 
result match { 
    Some(i) => System.out.println("index was: " + i); 
    None => System.out.println("no value"); 
} 

Si omite alguna de algunos o ninguno de igualar (interruptor que se generaliza un poco), compilador te daría una advertencia.

+0

Java no es Haskell. Y -1 puede ser un valor de retorno * útil * cuando se manipulan cadenas. Así que devolver -1 está lejos de ser horrible en Java, y desde luego no es tan horrible como lanzar una excepción. – eljenso

+1

La excepción no pasará desapercibida, pero es posible que la lógica de su programa se estropee silenciosamente cuando se trata de un número. Plus -1 no tiene ningún valor de legibilidad. Solo un valor arbitrario. – egaga

+0

Estoy de acuerdo. throw exception hará que el código sea más completo y no sea fácil de entender .... – ariso

0

Hasta que el autor de Java de string.indexOf nos cuenta la historia real ...

Supongamos que hemos tenido que diseñar desde cero, algunas restricciones de diseño obvias para este problema:

  1. indexOf deben devolver una valor numérico, de modo que cuando se encuentra una coincidencia, usted sabe dónde está
  2. , los índices válidos son siempre enteros
  3. Los índices de matriz (y cadena) están basados ​​en cero en Java
  4. Java es fuertemente tipado
  5. el entero tipos numéricos son firmados en Java

Dadas estas restricciones básicas, algunas de las posibles opciones para la devolución de la función escriba el sería número entero (lo ideal es de un tipo lo suficientemente grande como para representar la último índice en la cadena más grande posible), O ... Object (y quizás devuelva nulo para indicar que no se encontró).Pero en la práctica, devolver Object no sería ni eficiente ni fácil de usar, debido a la necesidad de verificar su validez y descartar antes del uso para el caso encontrado, ¡así que no es realmente una opción viable!

Así que vamos con un número entero. ¿Deseamos lanzar una excepción si no se encuentra? Lanzar excepciones tiene múltiples problemas propios: crear objetos de excepción y saltar a manejadores de excepciones puede ser bastante ineficiente, y escribir bloques try/catch alrededor de las llamadas indexOf tampoco es divertido.

Digamos que lo hemos reducido: tiene que devolver un tipo entero (con signo) y no arrojar una excepción. Ahora, ¿qué valor entero debería volver a representar no encontrado?

Para permitir la búsqueda en cadenas lo más grandes posible, debemos reservar todos los enteros positivos para su uso con el fin de encontrarlos correctamente. Por el contrario, ninguno de los números negativos es necesario para representar un índice "encontrado", por lo que todos están potencialmente disponibles para su uso como códigos de retorno que representan "no encontrado".

Si pudiéramos haber elegido cualquier número negativo, representar no encontrado, o simplemente decir "todos los valores negativos de retorno significan no encontrarlo", haría el trabajo ... ¿Pero sería el mejor diseño?

¿Cuáles son algunas razones para usar -1 en lugar de otros números negativos? Mis razones favoritas son simplemente '-1, es fácil de recordar para todos, y puedes hacer pruebas de igualdad exactas sobre él'. (En lugar de verse obligado a usar las desigualdades y pensar en problemas uno por uno, como si desea menos que o menos que o igual, y con qué valor comparar, cero o uno negativo)

I también a veces admiro la razón de Chris de que (parafraseando) 'funciona muy bien con substring(foundIndex + 1)'.

Cuestiones relacionadas