Red de conocimiento informático - Material del sitio web - Cómo escribir buen código Java

Cómo escribir buen código Java

Cómo escribir un buen código Java

1. La elegancia tiene un precio.

En términos de beneficios a corto plazo, encontrar una solución elegante a un problema parece llevar más tiempo. Pero cuando finalmente implemente la solución correctamente y la aplique fácilmente a casos nuevos sin pasar horas, o incluso días o meses de arduo trabajo, descubrirá que todo el arduo trabajo que realizó valió la pena (si no la gente puede medirlo). Esto no sólo hace que su programa sea 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. Esto requiere algo de experiencia para comprenderlo, porque cuando intentas hacer que un fragmento de código de programa sea más elegante, no estás trabajando de manera eficiente. Pero resiste a aquellos que te empujan a trabajar más rápido, porque eso sólo te ralentizará.

2. Ser capaz de moverse antes de moverse rápidamente.

Esta regla aún se aplica incluso si ha determinado que cierta parte del código del programa es crítica y es el principal cuello de botella en el sistema. Mantenga el diseño lo más simple posible para que el sistema funcione correctamente en primer lugar. Si el programa no se ejecuta lo suficientemente rápido, mida su rendimiento. Casi siempre descubrirá que lo que pensaba que era el "cuello de botella" no es el problema. Pase su tiempo a la vanguardia.

3. Tenga presente el principio de "avance".

Si estás explorando un problema demasiado complejo, intenta imaginar cuáles son los movimientos básicos del problema y asume que esta pequeña pieza resolverá mágicamente la parte más difícil. Esta "pequeña pieza" es en realidad el objeto: escriba el código de programa que usa el objeto, luego mire el objeto y vuelva a empaquetar las partes más difíciles en otros objetos, y así sucesivamente.

4. Distinguir entre desarrolladores de clases y usuarios de clases (programadores clientes).

Los usuarios de la clase desempeñan el papel de "clientes" y no necesitan (ni conocen) cómo funciona la clase internamente. Los desarrolladores de clases deben ser expertos en diseñar y escribir clases para que la mayoría de los programadores novatos puedan usar la clase y desempeñarse de manera confiable en sus programas. 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 forma segura en el programa. La facilidad de uso de una biblioteca depende de su permeabilidad.

5. Cuando escribas una clase, intenta darle un nombre claro y comprensible y minimiza los comentarios innecesarios.

La interfaz que proporcione a los programadores del cliente debe mantenerse conceptualmente simple. Por este motivo, utilice la sobrecarga de funciones si ello da como resultado una interfaz intuitiva y fácil de usar.

6. También debe analizar y diseñar el sistema de modo que el número de clases, el número de interfaces públicas y el número de asociaciones entre estas clases y otras clases (especialmente las clases base) se mantengan en un nivel determinado. mínimo.

Si los resultados de su diseño son más que esto, entonces pregúntese: ¿todo ello tendrá valor durante la vida del programa? Si no, mantenerlos te costará. Los equipos de desarrollo tienden a no mantener nada "inútil"; este es un fenómeno que muchos métodos de diseño no pueden explicar.

7. Automatiza todo al máximo. Primero escriba el código del programa de prueba (antes de escribir la clase) y hágalo funcionar con la clase. Utilice un archivo MAKE o una herramienta similar para automatizar las operaciones de prueba.

De esta manera, todos los cambios del programa se verifican automáticamente y los errores se descubren inmediatamente con simplemente ejecutar el programa de prueba. Debido a que comprende la seguridad que brinda su arquitectura de prueba, tendrá el valor de realizar cambios drásticos cuando descubra nuevos requisitos. Recuerde, las mayores mejoras en los lenguajes de programación provienen de las operaciones de prueba integradas proporcionadas por mecanismos como la verificación de tipos, el manejo de excepciones, etc. Pero estas características sólo pueden ayudarle hasta cierto punto. Al desarrollar un sistema confiable, usted debe verificar personalmente la naturaleza de la clase o programa.

8. Escriba código de prueba antes de escribir una clase para verificar si su clase está bien diseñada. Si no puede escribir código de prueba, no sabrá cómo se verá su clase. Escribir código de prueba a menudo puede revelar funcionalidades o limitaciones adicionales que no necesariamente estaban presentes durante el análisis y el diseño.

El código de prueba también puede servir como programa de muestra para demostrar el uso de una clase.

9. Todos los problemas de diseño de software se pueden simplificar "introduciendo una capa adicional de dirección conceptual". Esta ley básica de la ingeniería de software es la base de la abstracción conceptual y una característica importante de la programación orientada a objetos.

10. Las indirectas deben ser significativas (como se indica en la Directriz 9).

El significado puede ser tan simple como "poner código de programa *** en una función única". Si el nivel de indirección (o abstracción, encapsulación, etc.) que agrega no tiene sentido, probablemente sea tan malo como no tener el nivel apropiado de indirección.

11. Haz que la clase sea lo más pequeña y sin cortes (atómica) posible.

Dale a cada clase un propósito único y claro.

Si sus clases o sistema se vuelven demasiado complejos, reduzca las clases complejas a unas pocas clases más simples. Uno de los indicadores más obvios de esto es el tamaño de la clase: si la clase es grande, entonces la probabilidad de que se use en exceso es alta y, por lo tanto, se debe reducir. Las pistas que sugieren un rediseño de clases incluyen:

1) Declaraciones de cambio complejas: considere aplicar polimorfismo.

2) Muchas funciones manejan tipos de operaciones muy diferentes: considere dividirlas en varias clases diferentes.

12. Cuidado con las largas listas de parámetros.

Las listas de parámetros largas pueden dificultar la escritura, lectura y mantenimiento de llamadas a funciones. Debería intentar mover funciones a una clase más apropiada y utilizar objetos como parámetros siempre que sea posible.

13. No te repitas una y otra vez.

Si un fragmento de código de programa sigue apareciendo en muchas funciones de clase derivada, colóquelo en la función de clase base y llámelo en la función de clase derivada. Hacerlo no sólo ahorra 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 basura también puede agregar una funcionalidad útil a la interfaz a través del código del programa.

14. Tenga cuidado con las declaraciones de cambio o las cadenas de cláusulas if-else.

Esto generalmente representa lo que se llama "codificación de tipo verificado". Esto significa que la elección de qué fragmento de código de programa ejecutar se basa en algún tipo de información (inicialmente, el tipo exacto puede no ser obvio). A menudo se puede utilizar la herencia y el polimorfismo para reemplazar dicho código; las llamadas a métodos polimórficos realizan automáticamente la verificación de tipos y proporcionan más confiabilidad y extensibilidad más sencilla.

15.

15. Desde una perspectiva de diseño, identificar qué cambiará y separarlo de lo que no.

Es decir, identifique los elementos del sistema que es probable que cambie y encapsúlelos en clases. Puede aprender mucho sobre esta idea en el libro Thinking in Java Patterns (disponible de forma gratuita en www.BruceEckel.Com).

16. No utilice subclases para ampliar la funcionalidad básica.

Si el elemento de la interfaz es muy importante para la clase, debe colocarse en la clase base en lugar de agregarse cuando se deriva. Si agregó funciones durante la herencia, tal vez debería repensar todo el diseño.

17 Menos es más.

Comience con la interfaz más pequeña de la clase y manténgala lo más pequeña y simple posible mientras resuelve el problema. No imagine todas las formas posibles en que se puede utilizar una clase. Una vez que la clase se utilice realmente, naturalmente sabrá cómo ampliar la interfaz. Sin embargo, una vez que la clase está en uso, la interfaz no se puede reducir sin afectar el código del cliente. Si desea agregar más funciones, no hay problema: no afectarán el código del cliente existente, solo es necesario volver a compilarlas. Pero incluso si una nueva función reemplaza una función anterior, mantenga la interfaz existente. Si debe ampliar la interfaz de una función existente "agregando más comillas", escriba una función sobrecargada con las nuevas comillas, esto no afectará a ningún cliente de la función existente;

18. Lee tus clases en voz alta para asegurarte de que son lógicas.

Especifique la relación entre la clase base y la clase derivada como "is-a", y la relación entre la clase y el objeto miembro como "has-a".

19. Cuando dudes en heredar o compilar, pregúntate si necesitas subirlo a una clase base.

Si no, elija la composición (es decir, utilice objetos miembro). De esta forma, no se producirá el problema de "demasiados tipos básicos". Si utiliza la herencia, los usuarios pensarán que deberían poder realizar la transición hacia arriba.

20. Utilice miembros de datos para representar cambios en valores y utilice métodos sobrecargados para representar cambios en comportamiento.

Es decir, si encuentra una clase que tiene variables de estado cuyas funciones cambian entre diferentes comportamientos en función de los valores de esas variables, es posible que desee rediseñar la clase para mostrar subclases y diferencias entre métodos sobrecargados. .

21. Cuidado con la sobrecarga.

No se debe seleccionar condicionalmente una función para ejecutar un bloque de código de programa basado en un valor de referencia. En este caso, debe escribir dos o más métodos sobrecargados

22. Usar jerarquía de excepciones

Es mejor derivar la jerarquía de excepciones específica de la clase de jerarquía de excepciones estándar de Java para que la persona capturar la excepción puede detectar una excepción específica y luego solo capturar la excepción base.

Es mejor derivar clases específicas de la jerarquía de excepciones estándar de Java para que la persona que detecta excepciones pueda detectar excepciones específicas y solo detectar excepciones básicas en el futuro. Si agrega una nueva excepción derivada, el programa cliente original aún puede detectar la excepción a través de su tipo base.

23. A veces la simple agregación es suficiente.

El sistema de confort de los pasajeros en un avión se compone de múltiples elementos discretos: asientos, aire acondicionado, equipo de vídeo, etc., y necesitarás generar muchas de estas cosas en el avión. ¿Los declararías miembros privados y desarrollarías una interfaz completamente nueva? No. En este ejemplo, estos elementos también forman parte de la interfaz pública, por lo que siguen siendo seguros. Por supuesto, la simple agregación no es una solución común, pero a veces lo es.

24 Intente pensar en el problema desde la perspectiva del programador del cliente y del mantenedor del programa.

Tu clase debe ser lo más fácil de usar posible. Debe anticipar los posibles cambios y diseñarlos para que puedan lograrse fácilmente más adelante.

25. Cuidado con la "complicación de objetos enormes".

Este es a menudo un problema al que se enfrentan los programadores de procedimientos nuevos en la programación orientada a objetos, ya que tienden a terminar escribiendo un programa de procedimientos y colocándolo en uno o dos objetos enormes. Tenga en cuenta que, con la excepción de los marcos de aplicaciones, los objetos representan ideas en un programa, no el programa en sí.

26. Si tienes que hacer algo feo, entonces limita la parte fea a una clase.

27.

27. Si debe implementar una operación de alguna manera no portátil, abstráigala y limítela a una clase. Esta "capa adicional de indirección" evita que la no portabilidad se extienda por todo el programa. El patrón de diseño Bridge es la encarnación de este enfoque.

28. Los objetos no deben usarse sólo para contener datos.

Los objetos también deben tener un comportamiento bien definido. A veces el término "objeto de datos" es apropiado, pero el empaquetado y transporte deliberado de un conjunto de elementos de datos en un objeto de datos sólo es apropiado cuando no es aplicable un descriptor genérico.

29. Al intentar generar nuevas clases a partir de clases existentes, dé prioridad a la composición.

Debes utilizar la herencia sólo cuando sea necesario. Si elige la herencia cuando la composición es apropiada, introducirá una complejidad innecesaria en su diseño.

30. Utilice la herencia y la sobrecarga de funciones para mostrar diferencias de comportamiento y utilice campos para mostrar diferencias de estado.

Un ejemplo extremo de esta afirmación es heredar de diferentes clases para representar diferentes colores sin utilizar el campo "color". Cuidado con las diferencias.

Dos objetos con diferente semántica pueden tener la misma operación (o responsabilidad).

En el mundo OO, existe una tentación inherente de desear heredar una subclase de una clase para obtener los beneficios de la herencia. Esto se llama "mutabilidad".

Sin embargo, no hay ninguna buena razón para forzar una relación superclase/subclase donde no existe ninguna. Una mejor solución sería escribir una clase base que proporcione una interfaz para ambas clases derivadas; esto ocupará más espacio, pero obtendrá los beneficios esperados de la herencia y es posible que tenga un gran descubrimiento de diseño.

32. Presta atención a las restricciones de herencia.

El diseño más claro y comprensible es agregar funcionalidad a una clase heredada; eliminar funcionalidad antigua (en lugar de agregar funcionalidad nueva) durante la herencia es un diseño cuestionable. Sin embargo, las reglas se pueden romper. Si se trata de una biblioteca de clases formada por clases antiguas, puede ser más eficaz restringir la funcionalidad a subclases de la clase que reformular toda la estructura para que la nueva clase sea proporcional a la antigua.

33. Utilizar patrones de diseño para reducir la "funcionalidad básica".

Por ejemplo, si su clase solo puede producir un objeto, entonces no implemente esta función de manera irreflexiva y no diseñada, y luego escriba el comentario "Solo puede producir un objeto". Simplemente se fue. Encapsularlo como un singleton. Si hay mucho código de programa confuso "para generar objetos" en el programa principal, entonces puede encontrar patrones creativos como métodos de fábrica, de modo que la acción de generación se pueda encapsular con precios, reduciendo así la "funcionalidad desnuda y sin disfraz". del programa (desnuda). Reducir la "funcionalidad desnuda" no sólo hace que su programa sea más fácil de entender y mantener, sino que también desalienta a los mantenedores bien intencionados pero inesperados.

34. Cuidado con la "parálisis del análisis".

Recuerda que muchas veces hay que empezar un proyecto antes de tener toda la información. Y la mejor y más rápida manera de comprender lo desconocido es, a menudo, dar un paso adelante, no sólo hablar. Java tiene cortafuegos integrados, déjalos funcionar. Los errores que cometa en una clase o conjunto de clases no comprometerán la integridad de todo el sistema.

35. Cuando creas que tienes un buen análisis, diseño o implementación, intenta practicarlo nuevamente.

Presente a alguien ajeno al equipo; no es necesario que sea un consultor, sino que también puede ser miembro de otro equipo de la empresa. Invitarlo a mirar su trabajo con una nueva perspectiva detectará los problemas en una etapa fácilmente solucionable y las recompensas superarán el tiempo y el dinero invertido en el ejercicio. Implementación

36. En general, siga las prácticas de programación de Sun.

Para conocer los precios, consulte la siguiente documentación: java.sun.com/docs/codeconv/idex.html. Este libro sigue estas convenciones tanto como sea posible. Gran parte del código de programa que ven los programadores de Java se compone de estos hábitos. Si se apega obstinadamente a su estilo de escritura anterior, a sus lectores (del código de programa) les resultará más difícil entenderlo. Independientemente de los hábitos de escritura que decida adoptar, sea coherente durante todo el programa. Puede encontrar herramientas gratuitas para reorganizar programas Java en home.wtal.de/software-solutions/jindent.

37. No importa qué estilo de escritura utilices, realmente puede marcar una gran diferencia si tu equipo (o toda tu empresa, mejor aún) puede estandarizarlo. Esto significa que todos pueden modificar su propio trabajo si otros no siguen el estilo de escritura, y es un juego limpio. El valor de la estandarización es que analizar el código del programa requiere menos esfuerzo mental, por lo que puede concentrarse en la esencia del código.

38. Seguir las convenciones de capitalización estandarizadas.

La primera letra del nombre de la clase está en mayúscula. La primera letra de los miembros de datos, funciones y objetos (referencias) debe estar en minúscula. Cada palabra de todos los nombres de identificación debe estar concatenada y la primera letra de todas las palabras que no sean iniciales debe estar en mayúscula. Por ejemplo: thisIsAClassName thisIsAMethodOrFieldName Si se especifica un inicializador constante en una definición de tipo base final estática, el nombre de identidad 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 con letras que no se inicializan.

Los nombres de dominio (org, net, edu, etc.) deben estar en minúsculas. (Este fue un cambio con respecto a Java 1.1 al migrar a Java 2).

39. No inventes tus propios nombres de miembros de datos privados "decorativos".

Esto suele tomar la forma de un guión bajo y otros caracteres en la parte superior, siendo el símbolo húngaro el peor ejemplo. En esta nomenclatura hay que añadir caracteres extra para indicar el tipo, finalidad, ubicación, etc. de los datos. Es como si estuvieras usando lenguaje ensamblador y el compilador no proporciona ningún cofactor. Esto es confuso y difícil de leer, y no es fácil de implementar y mantener. Deje que las clases y los paquetes se encarguen del "alcance del nombre".

40. Al formular clases genéricas, siga 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 "get" de Java Beans.

42 Utilice convenciones de nomenclatura como "set" y "is. " , incluso si no cree que esté escribiendo un Java Bean en ese momento. Esto no sólo facilita el uso de beans en sus clases, sino que también establece una convención de nomenclatura estándar para dichas funciones, lo que facilita su comprensión para los lectores.

42. Para cada clase que desarrolle, considere agregar prueba pública estática(), que contiene código de prueba para las funciones de la clase.

No es necesario que elimines la prueba al incorporar el programa a tu proyecto. Si algo cambia, puede volver a ejecutar la prueba fácilmente. El código del programa también sirve como ejemplo del uso de la clase.

43. A veces es necesario acceder a miembros protegidos de una clase base mediante herencia.

Esto puede dar lugar a que sea necesario identificar varias clases base. Si no necesita actualización, puede derivar una nueva clase para realizar operaciones de acceso protegido y luego declarar la nueva clase como un objeto miembro en todas las clases que "necesitan usar dicho miembro protegido" en lugar de heredar directamente.

44. Evitar el uso de funciones finales únicamente por motivos de eficiencia.

Utilice funciones finales sólo cuando el programa pueda ejecutarse pero no lo suficientemente rápido, y cuando el generador de perfiles muestre que las llamadas a funciones son el cuello de botella.

45. Si dos clases están relacionadas por algunas razones funcionales (como contenedores e iteradores), intente hacer que una de las clases sea una clase interna de la otra.

Esto no sólo enfatiza la conexió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 iteradora implícita (interna) dentro de cada clase de contenedor, proporcionando así una copia de la interfaz común del contenedor. Otra razón para utilizar clases implícitas es hacerlas parte de una implementación privada. En este caso, el beneficio de las clases implícitas es ocultar información, no la asociatividad de clases mencionada anteriormente, ni evitar la contaminación del espacio de nombres.

46. En cualquier momento, debes prestar atención a aquellas clases altamente acopladas. Considere los beneficios de las clases internas para el desarrollo y mantenimiento de programas. El propósito de utilizar clases internas no es eliminar el acoplamiento entre clases, sino hacer que la relación de acoplamiento sea más obvia y conveniente.

47. No seas víctima de la “optimización prematura”.

Esta fue una experiencia estresante. Especialmente en las primeras etapas de la construcción de un sistema, no se preocupe si escribir (o evitar) funciones nativas (métodos nativos), si declarar ciertos números como finales, si ajustar el código del programa para mayor eficiencia, etc. Su principal problema debería ser demostrar que el diseño es correcto en primer lugar, a menos que el diseño en sí requiera un cierto nivel de eficiencia.

48. Reducir el alcance tanto como sea posible, para que la visibilidad y el ciclo de vida del objeto sean lo más pequeños posible.

Esto reducirá la posibilidad de que "los objetos se utilicen en el lugar equivocado, ocultando errores indetectables". Suponga que tiene un contenedor y un fragmento de programa que accede al contenedor. Si copia el código del programa y lo usa en un contenedor nuevo, puede limitar accidentalmente el tamaño del contenedor antiguo al acceso del contenedor nuevo. Si el contenedor antiguo ya no está a su alcance, se producirá un error de este tipo durante la compilación.

49. Utilice los contenedores proporcionados por la biblioteca estándar de Java.

Familiarizarse con su uso. Como resultado, serás significativamente más productivo. Para secuencias, elija ArrayList; para conjuntos, elija HashSet; para matrices asociativas, elija HashMap para cobertizos y colas, elija Linkedlist (en lugar de Stack).

50. Para un programa robusto, cada componente debe ser robusto.

Utilice todas las herramientas que mejoran la solidez que proporciona Java en cada clase que escriba: permisos de acceso, excepciones, verificación de tipos y más. De esta manera, puede pasar de forma segura al siguiente nivel de abstracción al construir su sistema.

51. Es mejor tener errores durante la compilación que durante la ejecución.

Intenta abordar los problemas lo más cerca posible de donde ocurren. Priorice los problemas de "dónde se lanzó la excepción" y detecte la excepción en el controlador más cercano que tenga suficiente información para manejar la excepción. En esta etapa, tome todas las medidas posibles para solucionar la excepción; si el problema no se puede resolver, la excepción debe lanzarse nuevamente.

52. Cuidado con las definiciones de funciones largas.

Una función debe ser una unidad breve de funcionalidad que "describe e implementa una parte separable de la interfaz de clase". Las funciones largas y complejas no sólo son difíciles de mantener, sino también costosas. Quizás esté intentando hacer demasiado. Si encuentra este tipo de función, significa que debe dividirla en una función de varias etapas. Estas funciones también le recuerdan que es posible que necesite escribir una nueva clase y que se pueden reutilizar funciones pequeñas en la clase. (A veces las funciones tienen que ser grandes para funcionar, pero sólo deben hacer una cosa).

53. Mantenlo lo más "privado" posible.

Una vez expuesto el archivo de configuración de la biblioteca (método, clase o campo). Nunca podrás eliminarlos. Si los elimina, romperá algún código de programa existente, que deberá reescribirse o rediseñarse. Si solo se revelan las piezas necesarias, se pueden cambiar otras cosas sin causar daños. El diseño siempre está evolucionando, por lo que este es un grado de libertad muy importante. De esta manera, los cambios en el código de implementación tienen un impacto mínimo en las clases derivadas. La privacidad es especialmente importante en entornos multiproceso: sólo los datos privados están protegidos del uso asincrónico.

54. Haga un uso extensivo de las anotaciones y utilice la "sintaxis de documentación de anotaciones" de javadoc para generar documentación para su programa.

Sin embargo, los comentarios deben dar un significado real al código del programa; simplemente reiterar lo que ya está explícitamente establecido en el código del programa es molesto. Tenga en cuenta que las clases de Java y sus funciones suelen tener nombres largos para minimizar la cantidad de comentarios.

55. Evite el uso de "números mágicos", números escritos en el código del programa; si intenta cambiar estos números, será una pesadilla porque nunca sabrá qué significa "100". "tamaño de matriz" o algo así. Debe generar nombres constantes descriptivos y usarlos en su programa. Esto hará que el programa sea más fácil de entender y mantener.

56. Al escribir constructores, considere las excepciones. En el mejor de los casos, el constructor no hace nada que pueda generar una excepción.

En el segundo mejor escenario, la clase simplemente hereda (o sintetiza) una clase robusta, por lo que no hay necesidad de limpiar si se produce alguna excepción. En otros casos, se debe limpiar la clase sintetizada en una cláusula finalmente, y si el constructor debe fallar, es apropiado lanzar una excepción para que el llamador no asuma ciegamente que el objeto se ha generado correctamente y continúe la ejecución.

57. Si su clase necesita ser limpiada después de que "el programador cliente haya terminado de usar el objeto", coloque la operación de limpieza en una función bien definida. Es mejor llamarlo cleanup() para que puedas decirles a otros qué hace la función. Además, agregue un indicador booleano a la clase para indicar si el objeto se ha limpiado para que finalize() pueda verificar si existe una condición de muerte (consulte el Capítulo 4).

58. finalize() solo se puede utilizar para comprobar la condición de muerte del objeto (consulte el Capítulo 4), lo cual es útil para la depuración.

En circunstancias especiales, puede ser necesario liberar parte de la memoria que no será recolectada como basura. Dado que es posible que no se llame al recolector de basura para deshacerse de sus objetos, no puede usar finalize() para realizar la limpieza necesaria. Por lo tanto, debes escribir tu propia función de "limpieza". En la clase finalize(), verifique que el objeto realmente se haya limpiado y, si el objeto no se ha limpiado, genere una excepción derivada de una excepción de tiempo de ejecución. Antes de usar esta arquitectura, asegúrese de que finalize() funcione en su sistema (es posible que deba llamar a System.gc() para confirmar esto).

59. Si un objeto debe limpiarse dentro de un alcance específico en lugar de ser reclamado por el mecanismo de recolección de basura, utilice el siguiente método: inicialice el objeto y luego ingrese inmediatamente a la sección try con una cláusula finalmente.

60. Cuando anulas finalize() durante la herencia, recuerda llamar a super.

Sin embargo, si tu "superclase directa" es un objeto, no lo necesitas. Debe usar super.finalize() como la última acción de un finalize() sobrecargado en lugar de la primera para garantizar que el componente de la clase base todavía esté disponible cuando lo necesite.

61. Cuando escribas contenedores de objetos de tamaño fijo, conviértelos en matrices, especialmente cuando los devuelvas desde funciones.

De esta manera se obtienen los beneficios de la "verificación de tipos en tiempo de compilación" de las matrices, y el destinatario de la matriz puede utilizar la matriz sin "convertir primero los objetos de la matriz". Tenga en cuenta que hay dos toArray() en la clase base de la biblioteca contenedora (Java.Util.Collection) que implementan esta funcionalidad.

62. Entre interfaces y clases abstractas, es preferible la primera.

Si sabe que algo se va a diseñar como una clase base, su primera opción debería ser diseñarlo como una interfaz sólo si tiene que incluir funciones o miembros de datos en caso de cambiarlo a abstracto; clase. La interfaz solo está relacionada con "qué acción quiere realizar el cliente", y la clase sólo está relacionada con "qué acción quiere realizar el cliente". Las interfaces sólo se ocupan de "lo que el cliente quiere hacer", mientras que las clases se centran más en los detalles de implementación.

63. Realizar la única acción necesaria en el constructor: establecer el objeto en el estado apropiado.

Evite llamar a otras funciones (excepto funciones finales) porque estas funciones pueden ser sobrecargadas por otras, produciendo resultados inesperados durante la construcción (consulte el Capítulo 7 para obtener más información). Es menos probable que los constructores pequeños y simples generen excepciones o causen problemas.

64 Para evitar una experiencia frustrante, asegúrese de que para cada nombre en el classpath haya solo una clase que no esté en el paquete; de ​​lo contrario, el compilador primero encontrará otras clases con el mismo nombre y devolverá un mensaje de error. Si sospecha que hay un problema de classpath, intente ubicar un archivo .class con el mismo nombre en cada punto inicial de la classpath. Es una buena idea poner todas las clases en un paquete.

65. Cuidado con los errores de recarga inesperados.

Si no escribe correctamente el nombre de una función de clase base cuando la anula, se agregará una nueva función en lugar de anular la función original. Pero 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 se ejecutará correctamente, eso es todo.

66. Cuidado con la optimización prematura.

Primero haga que el programa se ejecute, luego hágalo más rápido, pero sólo si es necesario (es decir, sólo si un cierto punto en el código del programa demuestra ser un cuello de botella en el rendimiento, simplemente haga esto). A menos que haya encontrado el cuello de botella utilizando un generador de perfiles, probablemente esté perdiendo el tiempo. El "costo oculto" del ajuste del rendimiento es que hace que el código del programa sea menos legible y más fácil de mantener.

67. Recuerde, el código de un programa es más legible que la escritura.

El diseño claro produce programas que son fáciles de entender. Los comentarios, explicaciones detalladas y ejemplos son invaluables. Estas cosas pueden ayudarle a usted y a sus sucesores. Al menos, la frustración que experimenta cuando descubre información útil en la documentación en línea de Java debería ser suficiente para convencerlo de esto.