Cómo escribir buen código Java
Cómo escribir un buen código Java
1. La elegancia tiene un precio.
Desde una perspectiva a corto plazo, encontrar una solución elegante a un problema puede parecer que te llevará más tiempo. Pero cuando finalmente funcione correctamente y pueda aplicarse fácilmente a nuevos casos sin pasar horas, días o meses de arduo trabajo, verá las recompensas del esfuerzo (incluso si nadie puede medir esto). Esto no sólo le proporciona un programa más fácil de desarrollar y depurar, sino que también es más fácil de entender y mantener. Eso es exactamente lo que vale en términos de dinero. Esto requiere algo de experiencia en la vida para comprenderlo, porque cuando intentas hacer que un fragmento de código de programa sea más elegante, no estás en un estado productivo. Pero resista a aquellos que le instan a darse prisa, porque hacerlo sólo le retrasará el paso.
2. Busca poder moverte primero y luego ser rápido.
Este principio sigue siendo válido incluso si ha determinado que cierta parte del código del programa es extremadamente importante y es un cuello de botella importante del sistema. Simplifique el diseño tanto como sea posible para que el sistema pueda actuar correctamente primero. Si la ejecución del programa no es lo suficientemente rápida, mida su rendimiento. Casi siempre descubrirá que lo que pensaba que era un "cuello de botella" no es en realidad el problema. Pase su tiempo al límite.
3. Recuerde el principio de "romper uno por uno".
Si el problema en el que estás trabajando es demasiado complejo, intenta imaginar cuáles serían los movimientos básicos para el problema y asume que esta pequeña pieza se encargará mágicamente de la parte más difícil. Esta "pequeña pieza" de algo es en realidad el objeto: usted escribe el código del programa que usa el objeto, luego inspecciona el objeto, envuelve las partes duras en otros objetos, y así sucesivamente.
4. Distinga entre desarrolladores de clases y usuarios de clases (programadores usuarios).
Los usuarios de la clase desempeñan el papel de "cliente" y no necesitan (ni conocen) la operación subyacente de la clase. Los desarrolladores de clases deben ser expertos en diseño de clases y escribir clases para que puedan ser utilizadas por tantos programadores novatos como sea posible y puedan ejecutarse de manera confiable en el programa. Una biblioteca de programas será fácil de usar sólo si es transparente.
5. Cuando escribas clases, intenta darles nombres claros y comprensibles y reduce los comentarios innecesarios.
La interfaz que proporcione a los programadores cliente debe seguir siendo conceptualmente simple. Para ello, haga un buen uso de la sobrecarga de funciones cuando sea adecuada para crear una interfaz intuitiva y fácil de usar.
6. Su análisis y diseño también deben mantener las clases en el sistema al mínimo, sus interfaces públicas al mínimo y las dependencias entre estas clases y otras clases (especialmente las clases base) al mínimo.
Si su diseño logra más que esto, pregúntese: ¿todo lo que contiene tiene valor durante la vida del programa? De lo contrario, mantenerlos le costará. Los miembros de los equipos de desarrollo tienden a no mantener nada que "no contribuya a la productividad"; este es un fenómeno que muchos métodos de diseño no pueden explicar.
7. Automatiza todo tanto como sea posible. Primero escriba el código del programa de prueba (antes de escribir la clase) y combínelo con la clase. Utilice makefile o herramientas similares para realizar acciones de prueba automáticamente.
De esta manera, siempre que se ejecute el programa de prueba, todos los cambios del programa se pueden verificar automáticamente y los errores se pueden descubrir de inmediato. Como conoce la seguridad de su arquitectura de prueba, estará más dispuesto a realizar cambios radicales cuando descubra nuevos requisitos. Recuerde, la mayor mejora en los lenguajes de programación proviene de las acciones de prueba integradas proporcionadas por la verificación de tipos, el manejo de excepciones y otros mecanismos. Pero estas funciones sólo pueden ayudarle a llegar hasta cierto punto. Al desarrollar un sistema robusto, usted mismo debe verificar las propiedades de sus clases o programas.
8. Antes de escribir una clase, escriba un código de prueba para verificar si su clase está completamente diseñada. Si no puede escribir código de prueba, no podrá saber cómo se verá su clase.
Escribir código de prueba a menudo puede revelar características o restricciones adicionales que no siempre surgen durante el análisis y el diseño. El código de prueba también se puede utilizar como programa de muestra para demostrar el uso de la clase.
9. Todos los problemas de diseño de software se pueden simplificar introduciendo una capa adicional de dirección conceptual indirecta. Este principio básico de la ingeniería de software es la base del concepto de abstracción, que es la propiedad principal de la programación orientada a objetos.
10. Las indicaciones deben ser significativas (de conformidad con la Directriz 9).
El significado aquí puede ser tan simple como "poner el código de la aplicación en una función única". Si el nivel de indirección (o abstracción, o encapsulación, etc.) que agrega no tiene sentido, probablemente sea tan malo como no tener el nivel apropiado de indirección.
11. Haga que la clase sea lo más pequeña posible y sin censura (atómica).
Dale a cada clase un propósito único y claro. Si sus clases o su sistema se vuelven demasiado complejos, corte las clases complejas en clases más simples. El indicador de juicio más obvio es el tamaño de la clase: si es grande, entonces la posibilidad de que haga demasiado trabajo probablemente sea alta y debería eliminarse. Las pistas sugeridas para rediseñar clases son:
1) Declaraciones de cambio complejas: considere usar polimorfismo.
2) Muchas funciones manejan cada una tipos de acciones muy diferentes: considere dividirlas en varias (clases) diferentes.
12. Tenga cuidado con las largas listas de argumentos.
Una secuencia de argumentos larga hará que la acción de llamada a la función sea difícil de escribir, leer y mantener. Debería intentar mover la función a una clase más apropiada e intentar utilizar objetos como argumentos.
13. No lo repitas una y otra vez.
Si un determinado código de programa aparece constantemente en muchas funciones de clase derivada, coloque el código del programa en una función de clase base y luego llámelo en la función de clase derivada. Hacerlo no solo puede ahorrar espacio en el código del programa, sino que también facilita la modificación del código del programa. A veces, encontrar este tipo de código de programa de acceso también puede agregar funciones prácticas a la interfaz.
14. Tenga cuidado con las declaraciones de cambio o las cadenas de cláusulas if-else.
Por lo general, esta situación representa la llamada "codificación de verificación de tipo". Es decir, qué fragmento de código de programa se ejecutará se decide en función de algún tipo de información (inicialmente, el tipo exacto puede no ser muy obvio). A menudo se puede utilizar la herencia y el polimorfismo para reemplazar este tipo de código de programa; las llamadas a métodos polimórficos (funciones polimórficas) realizan automáticamente esta verificación de tipos y proporcionan una extensibilidad más confiable y sencilla.
15. Desde una perspectiva de diseño, identifique las cosas que cambian y sepárelas de las que no cambian.
En otras palabras, encuentre los elementos en el sistema que usted puede cambiar y encapsúlelos en clases. Puede aprender mucho sobre este concepto en "Pensar en patrones con Java" (descarga gratuita en www.BruceEckel.Com).
16. No utilice subclases para ampliar la funcionalidad básica.
Si un elemento de la interfaz es extremadamente importante para la clase, debe colocarse en la clase base en lugar de agregarse hasta la derivación. Si agrega funciones al proceso de herencia, tal vez debería repensar todo el diseño.
17. Menos es más.
Comience desde la interfaz más pequeña de la clase e intente mantenerla lo más pequeña y simple posible mientras resuelve el problema. No piense de antemano en todas las formas posibles en que se puede utilizar su clase. Una vez que la clase se utilice realmente, sabrá naturalmente cómo ampliar la interfaz.
Sin embargo, una vez que se utiliza una clase, no se puede reducir su interfaz sin afectar el código del cliente. Si desea agregar más funciones, no hay problema: el código del cliente existente no se verá afectado, solo será necesario volver a compilarlo. Pero incluso si la nueva función reemplaza la función anterior, mantenga la interfaz existente. Si tiene que ampliar la interfaz de una función existente agregando más argumentos, escriba una función sobrecargada con los nuevos argumentos de esta manera no afectará a ningún cliente de la función existente;
18. Lee tus clases en voz alta y asegúrate de que tengan sentido.
Por favor, permita que la relación entre la clase base y la clase derivada sea "is-a" (es uno), y que la relación entre la clase y los objetos miembro sea "has-a" (tenga uno).
19. Cuando tenga dudas sobre la herencia o la composición, pregúntese si necesita actualizar a un tipo básico.
Si no, dé prioridad a la composición (es decir, utilice objetos miembro). Este enfoque puede eliminar "demasiados tipos básicos". Si utiliza la herencia, los usuarios pensarán que deberían poder realizar transmisiones hacia arriba.
20. Utilice miembros de datos para representar cambios en los valores y utilice métodos anulados para representar cambios en el comportamiento.
En otras palabras, si encuentra una clase con algunas variables de estado y sus funciones cambian diferentes comportamientos según los valores de estas variables, entonces probablemente debería rediseñarla y agregar subclases y anulaciones. Las diferencias de comportamiento se muestran en los métodos anulados.
21. Tenga cuidado con la sobrecarga.
Las funciones no deben elegir condicionalmente ejecutar una determinada pieza de código de programa en función de los valores de los argumentos. En este caso deberías escribir dos o más métodos sobrecargados
22. Utilice jerarquías de excepciones
Es mejor derivar clases específicas de la jerarquía de excepciones estándar de Java, de modo que la persona que detecta la excepción pueda detectar la excepción específica y luego detectar la excepción básica. Si agrega una nueva excepción derivada, el programa cliente original aún puede detectarla a través de su tipo subyacente.
23. A veces la simple agregación es suficiente.
El "sistema de confort de los pasajeros" en un avión consta de varios elementos separados: asientos, aire acondicionado, equipo de vídeo, etc. Muchas de estas cosas necesitarás en el avión. ¿Los declararías miembros privados y desarrollarías una interfaz completamente nueva? No, en este ejemplo, el elemento también forma parte de la interfaz pública, por lo que sigue siendo seguro. Por supuesto, la agregación simple no es una solución comúnmente utilizada, pero a veces lo es.
24. Intente pensar desde la perspectiva de los programadores del cliente y el mantenimiento del programa.
Tu clase debe estar diseñada para que sea lo más fácil de usar posible. Debe considerar los posibles cambios con anticipación y diseñarlos para que puedan implementarse fácilmente más adelante.
25. Tenga cuidado con las "complicaciones de objetos enormes".
Esto suele ser un problema para los programadores de procedimientos que son nuevos en el campo de la programación orientada a objetos, porque a menudo terminan escribiendo un programa de procedimientos y colocándolos en uno o dos objetos enormes en el medio. Tenga en cuenta que, con la excepción del marco de la aplicación (marco de la aplicación, anotación del traductor: una biblioteca de programas OO a gran escala muy especial que le ayuda a estructurar la ontología del programa), los objetos representan conceptos en el programa, no el programa en sí.
26. Si tiene que utilizar una forma fea para lograr una acción, limite la parte fea a una clase.
27. Si tiene que utilizar alguna forma no portátil para lograr una acción, abstraigala y limítela a una clase. Esta "capa adicional de dirección indirecta" evita que las piezas no portátiles se extiendan por todo el programa.
La manifestación específica de este enfoque es el patrón de diseño Puente.
28. Los objetos no deberían usarse sólo para contener datos.
Los objetos también deben tener comportamientos bien definidos y claramente delimitados. A veces es apropiado usar "objetos de datos", pero solo cuando un contenedor general no es aplicable, es apropiado usar objetos de datos deliberadamente para empaquetar y transmitir un grupo de elementos de datos.
29. Cuando desee generar nuevas clases a partir de clases existentes, dé prioridad a la composición.
Solo debes utilizar la herencia cuando sea necesario. Si elige la herencia cuando la composición es apropiada, su diseño introducirá una complejidad innecesaria.
30. Utilice mecanismos de herencia y anulación de funciones para mostrar diferencias de comportamiento y utilice campos (miembros de datos) para mostrar diferencias de estado.
El ejemplo extremo de esta oración es heredar diferentes clases para expresar varios colores sin usar el campo "color".
31. Cuidado con la variabilidad.
Es posible que dos objetos con diferente semántica tengan la misma acción (o responsabilidad). Existe una tentación natural en el mundo OO que hace que las personas quieran heredar otra subclase de una clase para obtener los beneficios de la herencia. Esto se llama "variabilidad". Sin embargo, no existe ninguna razón válida para forzar la creación de una relación superclase/subclase que no existe. Una mejor solución es escribir una clase base única que cree una interfaz común para las dos clases derivadas; este método consumirá más espacio, pero puede usarlo como desee. Los mecanismos de herencia obtienen beneficios y se pueden realizar importantes descubrimientos de diseño.
32. Tenga en cuenta las restricciones a la herencia.
El diseño más claro y comprensible es agregar funciones a las clases heredadas; eliminar funciones antiguas (en lugar de agregar nuevas funciones) durante el proceso de herencia es un diseño cuestionable. Sin embargo, las reglas se pueden romper. Si se trata de una biblioteca de clases antigua, puede ser más eficaz restringir la funcionalidad a una subclase de una clase que rediseñar toda la estructura para que la nueva clase encaje bien con la antigua.
33. Utilice patrones de diseño para reducir la "funcionalidad desnuda".
Por ejemplo, si su clase solo debe producir un único objeto, no lo complete de manera irreflexiva y sin diseño, y luego escriba "Sólo se debe producir una copia del objeto". comenta, solo dale una palmadita en el trasero y vete. Empaquételo como un singleton (Anotación: un patrón de diseño famoso, que puede traducirse como "una sola pieza"). Si el programa principal tiene mucho código de programa confuso "para generar objetos", busque patrones creativos, como métodos de fábrica, para que el precio pueda usarse para encapsular la acción de generación y reducir la "funcionalidad desnuda" (funcionalidad desnuda) no solo hace que su programa sea más fácil de entender y mantener, pero también disuade a los mantenedores bien intencionados de causar accidentes.
34. Tenga cuidado con la “parálisis del análisis”.
Recuerde que a menudo es necesario mantener un proyecto en marcha antes de tener toda la información. Y, a menudo, la mejor y más rápida forma de comprender lo desconocido es dar un paso adelante en lugar de limitarse a hablar de ello. No hay forma de conocer la solución hasta que se encuentre. Java tiene cortafuegos integrados, déjalos funcionar. Los errores que cometa en una sola clase o en un grupo de clases no dañan la integridad de todo el sistema.
35. Cuando crea que tiene un buen análisis, diseño o implementación, intente practicarlo.
Traiga a alguien externo al equipo; no tiene que ser un consultor, puede ser miembro de otro equipo de la empresa.
Pedirle a esa persona que eche un nuevo vistazo a su trabajo identificará los problemas en una etapa en la que pueden modificarse fácilmente y la recompensa será mayor que el tiempo y el dinero invertidos en el ejercicio. Implementación
36. En términos generales, siga los hábitos de programación de Sun.
La documentación relevante sobre precios se puede encontrar en: java.sun.com/docs/codeconv/idex.html. Este libro se adhiere a estas convenciones tanto como sea posible. El código de programa que ven muchos programadores de Java se compone de estos hábitos. Si te quedas obstinadamente en el estilo de escritura del pasado, tus lectores (código de programa) lo tendrán más difícil. Independientemente de los hábitos de escritura que decida adoptar, manténgalos constantes durante todo el programa. Puede encontrar una herramienta gratuita para reorganizar programas Java en home.wtal.de/software-solutions/jindent.
37. Cualquiera que sea el estilo de escritura que utilices, realmente puede marcar la diferencia si tu equipo (o mejor aún, toda tu empresa) puede estandarizarlo. Esto significa que todos pueden modificar su trabajo si otros no se adhieren al estilo de escritura, y es un juego limpio. El valor de la estandarización es que se dedica menos esfuerzo mental a analizar el código del programa, por lo que puede centrarse en el significado sustancial del código del programa.
38. Siga las convenciones estándar de uso de mayúsculas.
La primera letra del nombre de la clase debe estar en mayúscula. La primera letra de los miembros de datos, funciones y objetos (referencias) debe estar en minúscula. Todas las letras del nombre de identificación deben ser contiguas y la primera letra de todas las letras que no sean iniciales debe estar en mayúscula. Por ejemplo: ThisIsAClassName thisIsAMethodOrFieldName Si especifica inicializadores constantes (inicializadores constantes) en la definición de un tipo básico final estático, entonces el nombre de identificación debe estar todo en mayúsculas y representa una constante en tiempo de compilación. Los paquetes son un caso especial, sus nombres están todos en minúsculas, incluso si la primera letra no es el caso. Los nombres de dominio (org, net, edu, etc.) deben estar todos en minúsculas. (Este fue un cambio de Java 1.1 a Java 2).
39. No inventes nombres “decorativos” de miembros de datos privados.
Normalmente esta forma va precedida de un guión bajo y otros caracteres, siendo la notación húngara el peor ejemplo. En esta nomenclatura hay que añadir caracteres adicionales para indicar el tipo, finalidad, ubicación, etc. de los datos. Es como si estuvieras usando lenguaje ensamblador y el compilador no proporciona ninguna ayuda. Este método de denominación es confuso y difícil de leer, y también es difícil de implementar y mantener. Deje que las clases y los paquetes se encarguen del "alcance del nombre".
40. Cuando desarrolles una clase universal, sigue la forma canónica.
Incluyendo equals(), hashCode(), clone() (implementando Cloneable), e implementando Comparable y Serialiable, etc.
41 Para aquellas funciones que "obtienen o cambian valores de datos privados", utilice las convenciones de nomenclatura de Java Beans como "get", "set" y "is", incluso si no lo cree. estás escribiendo en ese momento Java Beans. Esto no sólo facilita el uso de su clase de la misma manera que Beans, sino que también es un método de denominación estándar para dichas funciones, lo que facilita la comprensión por parte de los lectores.
42. Para cada clase que diseñe, considere agregarle una prueba pública estática (), que contiene el código de prueba de la función de la clase.
No es necesario eliminar la prueba para incluir el programa en el proyecto. Y si algo cambia, puedes volver a ejecutar la prueba fácilmente. Este código de programa también se puede utilizar como ejemplo del uso de clases.
43. A veces es necesario heredar para acceder a los miembros protegidos de la clase base.
Esto puede llevar a la necesidad de conocer múltiples tipos de bases. Si no necesita realizar una conversión ascendente, primero puede derivar una nueva clase y luego realizar la acción de acceso protegido, y luego declarar la nueva clase como un objeto miembro en todas las clases que "necesitan usar los miembros protegidos anteriores" en lugar de heredar directamente.
44. Evitar el uso de funciones finales únicamente por motivos de eficiencia.
Utilice la función final solo cuando el programa esté activo pero no se esté ejecutando lo suficientemente rápido, y cuando la herramienta de medición del rendimiento (perfilador) muestre que la acción de llamada de una determinada función se ha convertido en un cuello de botella.
45. Si dos clases están relacionadas por alguna razón funcional (como contenedores e iteradores), intente hacer que una de las clases sea una clase implícita de la otra clase (clase interna).
Esto no sólo enfatiza la relación entre los dos, sino que también permite reutilizar el mismo nombre de clase en un solo paquete "anidando el nombre de clase dentro de otra clase". La biblioteca de contenedores de Java define una clase Iterador implícita (interna) en cada clase de contenedor, proporcionando así una interfaz común para el contenedor. Otra razón para utilizar clases implícitas es hacerlas parte de una implementación privada. Aquí, las clases implícitas traerán beneficios para ocultar información, no para brindar beneficios a la correlación de clases mencionada anteriormente, ni para prevenir la contaminación del espacio de nombres (contaminación del espacio de nombres).
46. Debe prestar atención a esas clases altamente acopladas en cualquier momento. Considere los beneficios que las clases internas aportan al desarrollo y mantenimiento del programa. El uso de clases implícitas no es para eliminar el acoplamiento entre clases, sino para hacer que la relación de acoplamiento sea más obvia y conveniente.
47. No seas víctima de la “optimización prematura”.
Eso sería una locura. Especialmente en las primeras etapas de la construcción del sistema, no se preocupe por escribir (o evitar) métodos nativos, declarar ciertos números como finales, ajustar la eficiencia del código del programa, etc. Su principal problema debería ser demostrar primero la exactitud del diseño, a menos que el diseño en sí requiera cierto grado de eficiencia.
48. Haga que el alcance (alcance) sea lo más pequeño posible, de modo que el alcance visible y la vida útil del objeto sean lo más pequeños posible.
Este enfoque reduce la posibilidad de que un objeto se utilice en el lugar equivocado, ocultando un error indetectable. Suponga que tiene un contenedor y un fragmento de programa que accede al contenedor. Si copia este código y lo usa en un contenedor nuevo, puede usar accidentalmente el tamaño del contenedor anterior como límite de acceso del nuevo contenedor. Estos errores pueden detectarse en tiempo de compilación si el contenedor antiguo ya no está a su alcance.
49. Utilice el contenedor proporcionado por la biblioteca estándar de Java.
Familiarícese con su uso. Como resultado, aumentará significativamente su productividad. Dé prioridad a ArrayList para manejar secuencias (secuencias), HashSet para manejar conjuntos (conjuntos), HashMap para manejar matrices asociativas (matrices asociativas) y Linkedlist (no Stack) para manejar chozas y colas.
50. Para un programa robusto, cada componente debe ser robusto.
Utilice todas las poderosas herramientas de mejora proporcionadas por Java en cada clase que escriba: permisos de acceso, excepciones, verificación de tipos, etc. De esta manera, puede pasar de forma segura al siguiente nivel de abstracción a medida que construye su sistema.
51. Es mejor tener errores durante la compilación que durante la ejecución.
Intenta solucionar el problema más cercano a donde se produce.
Priorice el manejo de los problemas "donde se produce la excepción" y capture las excepciones en el controlador más cercano que tenga suficiente información para manejar la excepción. Haga lo que pueda para manejar la excepción en esta etapa; si no puede resolver el problema, debe lanzar la excepción nuevamente.
52. Cuidado con las definiciones de funciones largas.
Una función debe ser una unidad funcional corta que "describe e implementa una parte separable de la interfaz de clase". Las funciones que son demasiado largas y complejas no sólo son difíciles de mantener, sino también costosas de mantener. Quizás esté intentando hacer demasiadas cosas. Si encuentra este tipo de función, significa que debe dividirse en funciones polifásicas. Esta función también le recuerda que es posible que necesite escribir una nueva clase. Las funciones pequeñas también se pueden reutilizar en tu clase. (A veces las funciones tienen que ser grandes, pero sólo deben hacer una cosa).
53. Mantenlo "Privado" tanto como sea posible.
Una vez expuesto el perfil de la biblioteca (método, clase o campo) al mundo exterior. Ya no podrás eliminarlos. Porque si los elimina, romperá algún código de programa existente, por lo que deberán reescribirse o rediseñarse. Si expones sólo las partes necesarias, puedes cambiar otras cosas sin causar daño. El diseño siempre evolucionará, por lo que este es un grado de libertad muy importante. De esta forma, se minimizará el impacto de los cambios en el código de implementación en las clases derivadas. En un entorno de subprocesos múltiples, la privacidad es particularmente importante: solo los datos privados pueden protegerse para que no sean destruidos por aplicaciones no sincronizadas (no controladas por sincronización).
54. Haga un uso extensivo de las anotaciones y utilice la "sintaxis del documento de anotaciones" de javadoc para generar documentación del programa.
Sin embargo, los comentarios deben dar un significado real al código del programa; es muy molesto si simplemente reiteran lo que el código del programa ya ha dicho claramente. Tenga en cuenta que normalmente las clases Java y los nombres de sus funciones son muy largos para reducir la cantidad de anotaciones.
55. Evite el uso de "números mágicos", que son números codificados en el código del programa; si intenta cambiarlos, se convertirán en su pesadilla, porque nunca podrá hacerlo. qué "100" en realidad significa "tamaño de matriz" o algo más. Debe generar nombres descriptivos de constantes y utilizar los nombres de constantes en su programa. Esto hace que el programa sea más fácil de entender y de mantener.
56. Al escribir constructores, considere los estados de excepción. En el mejor de los casos, el constructor no realiza ninguna acción que genere una excepción.
En el segundo mejor caso, las clases solo heredan (o se sintetizan a partir de) clases robustas, por lo que si se produce alguna excepción, no es necesario limpiarla. En otros casos, debes limpiar las clases sintetizadas en la cláusula final. Si un constructor está destinado a fallar, la acción apropiada es generar una excepción para que la persona que llama no asuma ciegamente que el objeto se ha generado correctamente y continúe la ejecución.
57. Si su clase necesita limpiarse después de que el programador cliente haya terminado de usar el objeto, coloque la acción de limpieza en una función única y bien definida. Es mejor llamarlo cleanup() para que puedas decirle a otros lo que hace. Además, coloque el indicador booleano en la clase para representar si el objeto se ha limpiado, de modo que finalize() pueda verificar su condición de muerte (consulte el Capítulo 4).
58. finalize() solo se puede utilizar para probar las condiciones de muerte del objeto (consulte el Capítulo 4) para facilitar la depuración.
En circunstancias especiales, puede ser necesario liberar parte de la memoria que no será recolectada como basura. Debido a que es posible que no se invoque al recolector de basura para procesar su objeto, no puede usar finalize() para realizar las acciones de limpieza necesarias. Por este motivo, debe escribir su propia función de "limpieza". En la clase finalize(), verifique para confirmar que el objeto efectivamente se haya limpiado y, si el objeto no se ha limpiado, genere una excepción derivada de Runtime Exception. Antes de usar esta arquitectura, asegúrese de que finalize() funcione correctamente en su sistema (esto puede requerir llamar a System.gc() para confirmar).
59. Si un objeto debe limpiarse dentro de un alcance específico (alcance) en lugar de ser reclamado por el mecanismo de recolección de basura, utilice el siguiente método e inmediatamente después del éxito ingrese a una sección de prueba; con una cláusula final. La cláusula Finalmente desencadena una acción de limpieza.
60. Cuando anule finalize() durante la herencia, recuerde llamar a superfinalize().
Pero si tu "superclase directamente superior" es Objeto, esta acción no es necesaria. Debe hacer que super.finalize() sea la última acción del finalize() anulado en lugar de la primera acción para garantizar que los componentes de la clase base todavía estén disponibles cuando los necesite.
61. Cuando escriba contenedores de objetos de tamaño fijo, conviértalos en matrices, especialmente cuando devuelva este contenedor desde una función.
De esta manera, puede obtener los beneficios de la "verificación de tipos en tiempo de compilación" de la matriz, y es posible que el receptor de la matriz no necesite "transmitir primero los objetos en la matriz" antes de poder usarlos. . Tenga en cuenta que la clase base de la biblioteca contenedora (Java. Util. Collection) tiene dos toArray (), que pueden lograr este propósito.
62. Entre interfaz y clase abstracta, se prefiere la primera.
Si sabe que algo está a punto de diseñarse como una clase base, su primera opción debería ser convertirlo en una interfaz; solo debe cambiarlo si debe incluir funciones o miembros de datos para resumen. class. La interfaz solo está relacionada con "qué acciones quiere realizar el cliente", mientras que la clase se centra más en los detalles de implementación.
63. Realizar únicamente la única acción necesaria en el constructor: establecer el objeto en el estado apropiado.
Evite llamar a otras funciones (excepto las funciones finales), porque estas funciones pueden ser anuladas por otras y provocar que obtenga resultados inesperados durante el proceso de construcción (consulte el Capítulo 7 para obtener más información detallada). Es menos probable que los constructores pequeños y simples generen excepciones o causen problemas.
64. Para evitar una experiencia muy frustrante, asegúrese de que por cada nombre en su classpath, solo haya una clase que no se haya colocado en los paquetes. De lo contrario, el compilador primero encontrará otra clase con el mismo nombre e informará un mensaje de error. Si sospecha que hay algún problema con su classpath, intente buscar un archivo .class con el mismo nombre en cada punto inicial de la classpath. Lo mejor es poner todas las clases en paquetes.
65. Presta atención a los errores de sobrecarga cometidos accidentalmente.
Si anula una función de clase base sin escribir su nombre correctamente, se agregará una nueva función en lugar de sobrescribir la función original. Pero la situación es perfectamente legal, por lo que no recibirá ningún mensaje de error del compilador o del sistema de ejecución; el código de su programa simplemente no funciona correctamente, eso es todo.
66. Cuidado con la optimización prematura.
Primero haga que el programa sea rápido, luego hágalo rápido, pero sólo si es necesario (es decir, sólo si se demuestra que el programa encuentra un cuello de botella en el rendimiento en una determinada sección de código). A menos que haya utilizado un generador de perfiles de rendimiento para identificar cuellos de botella, probablemente esté perdiendo el tiempo. El "costo oculto" del ajuste del rendimiento hace que el código de su programa sea menos legible y más difícil de mantener.
67. Recuerde, el código de un programa tarda más en leerse que en escribirse.
Un diseño claro puede producir programas fáciles de entender. Las notas, detalles y ejemplos no tienen precio. Estas cosas pueden ayudarte a ti y a quienes te sucedan. Al menos, su frustración por encontrar información útil en la documentación en línea de Java debería ser suficiente para convencerlo de esto.