2008-09-17 18 views
13

¿Generalmente asume que toString() en cualquier objeto dado tiene un costo bajo (es decir, para el registro)? Hago. ¿Es esa suposición válida? Si tiene un costo elevado, ¿debería cambiarse normalmente? ¿Cuáles son las razones válidas para hacer un método toString() con un alto costo? La única vez que me preocupan los costos de String es cuando sé que está en algún tipo de colección con muchos miembros. De: http://jamesjava.blogspot.com/2007/08/tostring-cost.html¿Es seguro asumir generalmente que toString() tiene un costo bajo?

Actualización: Otra forma de decirlo es: ¿Generalmente considera el costo de llamar a String en cualquier clase antes de llamarlo?

+1

En uno de sus comentarios, dice "generalmente + seguro <100% seguro". Bueno, generalmente no es seguro usar esa interpretación. – RoadWarrior

Respuesta

19

La biblioteca estándar de Java parece haber sido escrita con la intención de mantener el costo de las llamadas aString muy bajo.Por ejemplo, las matrices y colecciones Java tienen métodos toString que no iteran sobre sus contenidos; para obtener una buena representación de cadena de estos objetos, debe usar Arrays.toString o Collections.toString del paquete java.util.

Del mismo modo, incluso los objetos con costosos métodos iguales tienen llamadas toString de bajo costo. Por ejemplo, la clase java.net.URL tiene un método igual que hace uso de una conexión a Internet para determinar si dos URL son realmente iguales, pero todavía tiene un método simple y de tiempo constante toString.

Así que sí, las llamadas de bajo costo a String son la norma, y ​​a menos que use algún paquete extraño de terceros que rompa con la convención, no debe preocuparse porque esto tome mucho tiempo.

Por supuesto, no deberías preocuparte por el rendimiento hasta que te encuentres en una situación en la que el programa demora demasiado, e incluso entonces deberías utilizar un generador de perfiles para saber qué es lo que lleva más tiempo en lugar de preocuparte por esto tipo de cosas antes de tiempo.

+0

AbstractCollection itera sobre sus elementos con un iterador, ya que no se reemplaza por la eficiencia incluso en clases como ArrayList. No he comprobado Java 6, pero en Java 1.5, sigue usando StringBuffer en lugar de StringBuilder. Definitivamente no optimizado para la eficiencia. – erickson

1

Dado que generalmente solo llamo aString() sobre los métodos y las clases que he escrito y sobreescribo el método base, generalmente sé cuál es el costo por adelantado. La única vez que uso toString() es el manejo de errores o la depuración cuando la velocidad no es de la misma importancia.

5

¿Generalmente asume que toString() en cualquier objeto dado tiene un costo bajo? Hago.

¿Por qué harías eso? Perfil su código si tiene problemas de rendimiento; le ahorrará mucho tiempo trabajando con suposiciones incorrectas.

37

No, no lo es. Como ToString() puede ser sobrecargado por cualquier persona, puede hacer lo que quiera. Es una suposición razonable que ToString() DEBE tener un costo bajo, pero si ToString() accede a las propiedades que hacen "carga diferida" de datos, incluso puede golpear una base de datos dentro de su ToString().

+0

Tenga en cuenta la palabra "en general" en mi pregunta. Estoy preguntando si deberíamos suponer que el 90% del tiempo toString es de bajo costo. ¿Siempre observa la implementación de theString para determinar el costo solo porque existe la posibilidad de que sea costoso? –

+1

@Juegos: "Generalmente"! = "Normalmente". – codekaizen

+0

Yo diría que el problema es con el código de sobrecarga y debe ser refactorizado. –

0

Posiblemente el costo más grande con el encadenamiento toString() ingenuo es agregar todas esas cadenas. Si desea generar cadenas de gran tamaño, debe utilizar una representación subyacente que admita un anexo eficiente. Si sabe que el apéndice es eficiente, entonces toString() probablemente tenga un costo relativamente bajo.

Por ejemplo, en Java, StringBuilder preasignará un espacio de modo que una cierta cantidad de cadenas anexas tome tiempo lineal. Se reasignará cuando te quedes sin espacio.

En general, si desea anexar secuencias de cosas y, por alguna razón, no desea hacer algo similar, puede usar difference lists. Estos soportan el tiempo lineal que se agrega al girar la secuencia que se agrega a la composición de la función.

0

toString() se utiliza para representar un objeto como una cadena. Por lo tanto, si necesita código de ejecución lenta para crear una representación de un objeto, debe ser muy cuidadoso y tiene una muy buena razón para hacerlo. La depuración sería la única en la que puedo pensar que es aceptable una ejecución lenta en String.

9

La mejor manera de averiguarlo es perfilar su código. Sin embargo, en lugar de preocuparse de que una función en particular tenga una sobrecarga, es (generalmente) mejor preocuparse por la corrección de su aplicación y luego hacer perfiles de rendimiento en ella (pero tenga cuidado con el uso en el mundo real y la configuración de la prueba puede diferir radicalmente) Como resultado, los programadores generalmente adivinan incorrectamente lo que es realmente lento en su aplicación y a menudo pasan mucho tiempo optimizando cosas que no necesitan optimización (eliminando ese triple ciclo anidado que solo consume 0.01% del tiempo de su aplicación es probablemente un desperdicio).

Afortunadamente, hay muchos open source profilers for Java.

1

Mi respuesta pragmática sería: sí, siempre asumes que una llamada a toString() es barata, a menos que hagas una gran cantidad de ellas. Por un lado, es extremadamente improbable que un método toString() sea costoso y, por otro lado, es extremadamente improbable que tenga problemas si no es así. Por lo general, no me preocupo por problemas como estos, porque hay demasiados y no obtendrás ningún código si lo haces;).

Si se encuentra con problemas de rendimiento, todo está abierto, incluido el rendimiento de toString() y debería, como sugiere Shog9, simplemente perfilar el código. El Java Puzzlers muestra que incluso Sun escribió algunos constructores bastante desagradables y métodos de String() en sus JDK.

0

Mi pensamiento es:

Sí en objetos estándar-biblioteca

n sobre los objetos no estándar a menos que tenga el código fuente en frente de usted y puede comprobarlo.

0

Siempre anularé toString para poner en cualquier cosa que crea que necesitaré para solucionar problemas. Normalmente el desarrollador debe usarlo llamando al método toString o llamando a otra clase (println, logging, etc.).

3

El título de su pregunta utiliza las palabras contradictorias "seguro" y "en general". Entonces, aunque en los comentarios parezca que está enfatizando el caso general, para el cual la respuesta probablemente sea "sí, generalmente no es un problema", muchas personas ven "seguro" y por lo tanto responden "No, porque hay una riesgo de rendimiento arbitrariamente bajo, "o" No, porque si desea estar 'seguro' con una pregunta de rendimiento, debe perfil. "

+0

generalmente + seguro <100% seguro –

0

Hay una respuesta fácil a esta, que escuché por primera vez en una discusión sobre la reflexión: "si tiene que preguntar, no puede pagarlo".

Básicamente, si necesita ToString() de objetos grandes en el funcionamiento cotidiano de su programa, entonces su programa está loco. Incluso si necesita ToString() un entero para cualquier momento crítico, su programa está loco, porque obviamente está usando una cadena donde un entero haría.

ToString() para los mensajes de registro está automáticamente bien, porque el registro ya es costoso. Si su programa es demasiado lento, baje el nivel de registro. En realidad, no importa lo lento que sea generar realmente los mensajes de depuración, siempre que pueda elegir no generarlos.(Nota: su infraestructura de registro debe llamar a ToString() en sí, y solo cuando se supone que se va a imprimir el mensaje de registro. No lo haga ToString() manualmente en el camino en la infraestructura de registro, o pagará el precio incluso si el nivel de registro es bajo y no lo imprimirá después de todo. Consulte http://www.colijn.ca/~caffeine/?m=200708#16 para obtener más información al respecto.)

0

Dado que pone "en general" en su pregunta, diría que sí. Para la mayoría de los objetos, no habrá una costosa sobrecarga de ToString. Definitivamente puede haber, pero generalmente no habrá.

1

Creo que la pregunta tiene un defecto. Ni siquiera asumiría que toString() imprimirá una pieza útil de datos. Entonces, si comienzas con esa suposición, sabes que debes verificarla antes de llamarla y puedes evaluar su 'costo' caso por caso.

+0

Absolutamente correcto. ToString en un tipo de referencia simplemente devuelve el nombre del tipo, y el principio KISS dice que no debe ser anulado en la gran mayoría de los casos. – Joe

+0

toString en general, al menos incluye el nombre de clase y que a menudo es algo útil. –

0

En general, considero toString() low cost cuando lo uso en objetos simples, como un entero o una estructura muy simple. Sin embargo, cuando se aplica a objetos complejos, toString() es un poco de disparate. Hay dos razones para esto. En primer lugar, los objetos complejos tienden a contener otros objetos, por lo que una sola llamada a toString() puede formar una cascada en muchas llamadas a toString() en otros objetos, además del principio de concatenación de todos esos resultados. En segundo lugar, no existe un "estándar" para convertir objetos complejos en cadenas. Una llamada a toString() puede generar una sola línea de valores separados por comas; otra una forma mucho más verbosa. Solo al verificarlo usted mismo puede saberlo.

Así que mi regla es toString() en objetos simples generalmente es segura, pero en objetos complejos es sospechoso hasta que se compruebe.

0

Evitaría usar toString() en objetos que no sean los tipos básicos. toString() puede no mostrar nada útil. Puede iterar sobre todas las variables miembro e imprimirlas. Puede cargar algo que aún no está cargado. Dependiendo de lo que planeas hacer con esa cadena, deberías considerar no construirla.

Por lo general, hay algunas razones por las que utiliza toString(): el inicio de sesión/depuración es probablemente el más común para objetos aleatorios; la visualización es común para ciertos objetos (como números). Para el registro que haría algo así como

if(logger.isDebugEnabled()) { 
    logger.debug("The zig didn't take off. Response: {0}", response.getAsXML().toString()); 
} 

Esto hace dos cosas: 1. Evita la construcción de la cadena y 2. Además previene la cadena innecesaria si no se registra el mensaje.

0

En general, no reviso todas las implementaciones. Sin embargo, si veo una dependencia en los recursos comunes de Apache, las alarmas suenan y miro la implementación más de cerca para asegurarme de que no estén usando ToStringBuilder u otras atrocidades.

Cuestiones relacionadas