Java Language Es
Java Language Es
Java Language Es
#java
Tabla de contenido
Acerca de 1
Observaciones 2
Instalando Java 3
¿Que sigue? 3
Pruebas 3
Otro 3
Versiones 4
Examples 4
Examples 11
Introducción a JNA 11
¿Qué es JNA? 11
¿A dónde ir ahora? 12
Capítulo 3: Afirmando 13
Sintaxis 13
Parámetros 13
Observaciones 13
Examples 13
Examples 14
Examples 17
Enfoque general 17
Observaciones 20
Examples 21
Capítulo 7: Anotaciones 25
Introducción 25
Sintaxis 25
Observaciones 25
Tipos de parametros 25
Examples 25
Anotaciones incorporadas 25
Valores predeterminados 30
Meta-Anotaciones 30
@Objetivo 30
Valores disponibles 30
@Retencion 31
Valores disponibles 32
@Documentado 32
@Heredado 32
@Repeable 33
Repetir anotaciones 34
Anotaciones heredadas 35
Ejemplo 35
La anotacion 36
El procesador de anotaciones. 36
embalaje 38
Integración IDE 39
Netbeans 39
Resultado 40
Examples 43
Introducción 46
Examples 46
Introducción 49
Observaciones 49
Actuación 49
Examples 49
Introducción 49
Invocando un método 51
Constructor de llamadas 53
Proxies dinámicos 57
Capítulo 11: AppDynamics y TIBCO BusinessWorks Instrumentation para una fácil integración 61
Introducción 61
Examples 61
Introducción 63
Observaciones 63
Examples 63
Applet mínimo 63
Examples 68
Apuntar a un camino 72
Cierre 76
Agregando Directorios 81
Introducción 84
Examples 84
Introducción 87
Sintaxis 87
Parámetros 87
Examples 87
Casos basicos 87
Introducción 88
Es posible que las matrices no se puedan reinicializar con la sintaxis de acceso directo d 95
en bucle 107
Object.clone () 107
Arrays.copyOf () 108
System.arraycopy () 108
Arrays.copyOfRange () 108
Observaciones 117
Examples 117
Reproducir un archivo de audio en bucle 117
Introducción 121
Observaciones 121
Examples 121
Observaciones 126
Examples 126
-XXaggresivo 126
-XXallocClearChunks 126
-XXallocClearChunkSize 127
-XXcallProfiling 127
-XXdisableFatSpin 127
-XXdumpSize 128
-XXexitOnOutOfMemory 128
Introducción 130
Examples 130
1.Adición 130
2.Subtraction 131
3.Multiplicacion 131
4.Division 131
6. Poder 132
7.Max 133
8.Min 133
BigDecimal.valueOf () 135
Introducción 136
Sintaxis 136
Observaciones 136
Examples 137
Inicialización 137
Introducción 144
Sintaxis 144
Examples 144
Observaciones 147
Examples 147
Creando objetos de calendario 147
Encontrando AM / PM 148
Introducción 149
Observaciones 149
Examples 149
Introducción 153
Observaciones 153
Examples 153
Observaciones 155
Examples 155
Examples 158
Un ejemplo que utiliza un sistema criptográfico híbrido que consiste en OAEP y GCM 158
Introducción 163
Examples 163
Sintaxis 164
Parámetros 164
Observaciones 164
Examples 165
Introducción 176
Sintaxis 176
Examples 176
Introducción 190
Sintaxis 190
Observaciones 190
Examples 191
Introducción 196
Examples 196
Introducción 197
Observaciones 197
Examples 197
Introducción 200
Examples 200
Introducción 201
Sintaxis 201
Observaciones 201
Examples 202
Constructores 207
Introducción 210
Sintaxis 210
Examples 210
Constructores 215
Observaciones 220
Examples 220
Introducción 226
Observaciones 226
Examples 226
Variables 227
Constantes 227
Modificadores 230
Sangría 231
Anotaciones 234
Literales 236
Tirantes 236
Examples 238
Pilas 239
Ejemplo 239
BlockingQueue 240
Deque 242
Introducción 244
Observaciones 244
Examples 245
INCORRECTO 248
CORRECTO 249
Creando su propia estructura de Iterable para usar con Iterator o para cada bucle. 256
Observaciones 261
Examples 261
Introducción 272
Examples 272
Examples 276
Sintaxis 277
Observaciones 277
Examples 277
Introducción 285
Observaciones 285
C ++ 285
Java 285
C ++ 286
Java 286
C ++ 286
Java 286
Polimorfismo 287
Examples 290
Ejemplo de C ++ 290
Ejemplo de Java 291
C ++ 291
Java 291
C ++ 292
Java 292
C ++ 292
Java 292
Ejemplo de C ++ 294
C ++ 294
Java 295
C ++ 295
Java 295
Interfaz 295
C ++ 295
Java 295
Observaciones 296
Examples 296
Referencias 299
Introducción 302
Examples 302
Examples 304
Inicialización 305
Introducción 309
Observaciones 309
Examples 309
Examples 313
Introducción 319
Sintaxis 319
Examples 319
h21 327
Uso de flujos de Map.Entry para conservar los valores iniciales después del mapeo 339
Observaciones 346
Examples 346
Parámetros 353
Examples 354
Introducción 361
Observaciones 361
Examples 361
Prerrequisitos 364
Observaciones 369
Examples 369
Introducción 370
Sintaxis 370
Observaciones 371
Examples 371
Examples 378
Examples 383
Java SE 385
Java EE 385
Java ME 386
Java FX 386
Introducción 389
Observaciones 389
Examples 389
ThreadPoolExecutor 390
Programar tareas para que se ejecuten a una hora determinada, después de un retraso o repe 392
Introducción 403
Observaciones 403
Examples 403
Sintaxis 409
Observaciones 409
Examples 409
Introducción 419
Observaciones 419
Examples 419
Introducción 422
Examples 422
Introducción 423
Examples 423
Introducción 424
Sintaxis 424
Observaciones 424
Restricciones 424
Examples 425
Introducción 443
Examples 443
Pitfall: utilizando == para comparar objetos de envoltorios primitivos, como Integer 443
Observaciones 455
Examples 455
Pitfall - Usar nulo para representar una matriz o colección vacía 456
En resumen 459
Introducción 462
Observaciones 462
Examples 462
Solución 462
Pitfall: el uso de 'nuevo' para crear instancias de contenedor primitivas es ineficiente 464
Pitfall: el uso de size () para comprobar si una colección está vacía es ineficiente. 468
Pitfall - Interning Strings para que puedas usar == es una mala idea 472
Fragilidad 472
Pitfall - Las lecturas / escrituras pequeñas en flujos no almacenados en búfer son inefici 474
Observaciones 477
Examples 477
Trampa: omitir llaves: los problemas de "colgar si" y "colgar de otra manera" 480
Pitfall - Declarar clases con los mismos nombres que las clases estándar 483
Pitfall: las importaciones de comodines pueden hacer que su código sea frágil 485
Introducción 488
Examples 488
Sintaxis 497
Parámetros 497
Observaciones 497
Examples 497
Introducción 503
Examples 503
Sintaxis 504
Observaciones 504
Examples 504
Observaciones 506
Examples 506
Si / Else 510
Descanso 512
Observaciones 515
Examples 515
Evaluando un NodeList en un documento XML 515
Introducción 518
Observaciones 518
Examples 518
Introducción 522
Sintaxis 522
Examples 522
Introducción 539
Intento-finalmente 545
prueba-captura-finalmente 545
Introducción 548
Observaciones 548
Examples 548
Introducción 555
Sintaxis 555
Examples 555
Introducción 572
Sintaxis 572
Observaciones 572
Importaciones 572
Escollos 572
Examples 573
Usando expresiones regulares con comportamiento personalizado compilando el patrón con ban 574
Examples 578
Instante 579
Introducción 583
Examples 583
Examples 586
Sintaxis 587
Parámetros 587
Examples 587
Observaciones 593
Examples 593
Examples 598
Introducción 599
Sintaxis 599
Observaciones 599
Examples 599
El diamante 603
Nota: 609
Soluciones 609
Diferentes formas de implementar una interfaz genérica (o extender una clase genérica) 613
Obtenga una clase que satisfaga el parámetro genérico en tiempo de ejecución 615
Examples 617
Manifestación 625
Observaciones 627
Examples 627
Finalización 627
Introducción 635
Examples 635
Introducción 638
Examples 638
Introducción 642
Sintaxis 642
Observaciones 642
Examples 642
Herencia 647
Sintaxis 659
Parámetros 659
Observaciones 659
Examples 659
Introducción 661
Observaciones 663
Examples 663
Explicación: 666
Ejemplo: 666
Observaciones 667
Examples 667
Sintaxis 672
Observaciones 672
Examples 672
Introducción 677
Examples 677
Suposiciones 677
Introducción 690
Observaciones 690
Examples 691
Subcadenas 698
Regex 707
Introducción 712
Sintaxis 712
Examples 712
Variables 722
Métodos 722
Introducción 725
Examples 725
Lista de interfaces funcionales estándar de Java Runtime Library por firma 725
Observaciones 728
Examples 728
Introducción 732
Observaciones 732
Examples 732
Observaciones 734
Examples 734
Parámetros 737
Observaciones 737
Examples 737
Código C ++ 738
Salida 739
Código C ++ 740
Salida 740
Observaciones 743
Examples 743
Introducción 753
Observaciones 753
Examples 753
Introducción 757
Sintaxis 757
Observaciones 757
Examples 758
Introducción 759
Sintaxis 759
Parámetros 759
Observaciones 759
Examples 759
Especificando una instancia de XmlAdapter para (re) usar datos existentes 764
Ejemplo 765
Adaptador 765
Examples 769
Introducción 770
Examples 770
Examples 775
Introducción 780
Sintaxis 780
Observaciones 780
Examples 781
Expresiones 781
Variables 781
Introducción 784
Observaciones 784
Examples 784
Detalles 787
Deserialización: 787
JSONObject.NULL 789
Detalles 791
Nota 792
Observaciones 793
Historia 793
Examples 793
Examples 796
Examples 797
Pitfall - Demasiados hilos hace que una aplicación sea más lenta. 799
Introducción 806
Examples 806
BufferedReader 806
Introducción 806
Introducción 809
Examples 809
Introducción 811
Examples 811
Introducción 812
Examples 812
Introducción 821
Sintaxis 821
Observaciones 821
Examples 822
CopyOnWriteArrayList 833
RoleUnresolvedList 834
Apilar 834
Vector 834
Observaciones 835
Examples 835
Lugar 837
Idioma 837
Introducción 839
Sintaxis 839
Observaciones 839
Examples 840
Introducción 846
Observaciones 846
Examples 846
Sintaxis 855
Los operadores de asignación (=, + =, - =, * =, / =,% =, << =, >> =, >>> =, & =, | = y ^ = 859
Observaciones 866
Examples 866
Introducción 872
Examples 872
Introducción 874
Examples 874
Introducción 875
Observaciones 875
Examples 875
Componiendo el Mapa <X, Y> y el Mapa <Y, Z> para obtener el Mapa <X, Z> 882
Introducción 887
Examples 890
Introducción 891
Observaciones 891
Examples 891
Introducción 894
Sintaxis 894
Parámetros 894
Examples 895
Introducción 896
Sintaxis 896
Observaciones 896
Referencias: 897
Examples 897
Observaciones 903
Examples 903
Comportamiento 906
Examples 912
Introducción 919
Examples 919
final 919
volátil 920
estático 921
resumen 922
sincronizado 923
transitorio 924
strictfp 924
Sintaxis 925
Observaciones 925
Examples 925
Introducción 928
Sintaxis 928
Observaciones 928
Examples 928
Observaciones 933
Examples 933
Sintaxis 935
Examples 935
Observaciones 939
Examples 939
Fallas típicas de diseño que evitan que una clase sea inmutable. 941
Sintaxis 945
Examples 945
Introducción 947
Sintaxis 947
Examples 947
Mapa 948
Filtrar 949
Introducción 952
Examples 952
Introducción 958
Observaciones 958
Examples 958
Introducción 960
Observaciones 960
Examples 960
Examples 970
PreferenceChangeEvent 970
NodeChangeEvent 970
Sintaxis 977
Parámetros 977
Observaciones 977
Examples 977
Observaciones 980
Examples 980
ch.vorburger.exec 981
Introducción 985
Observaciones 985
Examples 985
Productor-consumidor 986
CountDownLatch 988
Sincronización 989
Semáforo 1003
Obtenga el estado de todas las hebras iniciadas por su programa, excluyendo las hebras del 1004
Examples 1009
Introducción 1011
Examples 1011
Introducción 1021
Examples 1021
Introducción 1024
Observaciones 1024
Salida 1024
Eliminación de Java y Tail-Call 1024
Examples 1024
Ejemplo 1028
Solución 1028
Ejemplo 1028
Por qué la eliminación de la llamada de cola no está implementada en Java (todavía) 1031
Introducción 1032
Observaciones 1032
Examples 1033
Cargando recursos del mismo nombre desde múltiples archivos JAR 1034
Sintaxis 1036
Examples 1036
Ejemplo de socket: leer una página web utilizando un socket simple 1039
Multidifusión 1041
Notas 1044
Observaciones 1045
Examples 1045
Examples 1048
Examples 1052
Introducción 1055
Observaciones 1055
Examples 1055
La jce 1055
Aleatoriedad y tu 1055
Observaciones 1057
Examples 1057
Servicio 1057
Uso 1058
Introducción 1061
Examples 1061
Introducción 1066
Examples 1066
Inicialización perezosa segura para subprocesos utilizando la clase de soporte | Implement 1067
Introducción 1071
Observaciones 1071
Examples 1071
Introducción 1075
Examples 1075
Introducción 1076
Examples 1076
Introducción 1078
Sintaxis 1078
Observaciones 1078
Examples 1078
Observaciones 1081
Examples 1081
Examples 1084
Introducción 1087
Examples 1087
Observaciones 1088
Examples 1088
Sintaxis 1092
Examples 1092
Introducción 1094
Parámetros 1094
Observaciones 1094
Examples 1094
Examples 1098
Creando un tipo de referencia 1098
Desreferenciación 1098
Introducción 1099
Sintaxis 1099
Observaciones 1099
Examples 1100
Examples 1110
Introducción 1112
Examples 1112
Introducción 1113
Examples 1113
Sintaxis 1118
Examples 1118
Introducción 1121
Observaciones 1121
Examples 1121
Introducción 1124
Examples 1124
Realización de tareas asíncronas donde no se necesita un valor de retorno utilizando una i 1124
Realización de tareas asíncronas donde se necesita un valor de retorno utilizando una inst 1125
Observaciones 1130
Examples 1130
Capítulo 183: Visibilidad (control de acceso a los miembros de una clase) 1132
Sintaxis 1132
Observaciones 1132
Examples 1132
Introducción 1136
Sintaxis 1136
Parámetros 1136
Observaciones 1136
Examples 1136
package-info.java 1138
Examples 1139
Creditos 1145
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: java-language
It is an unofficial and free Java Language ebook created for educational purposes. All the content
is extracted from Stack Overflow Documentation, which is written by many hardworking individuals
at Stack Overflow. It is neither affiliated with Stack Overflow nor official Java Language.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/es/home 1
Capítulo 1: Empezando con el lenguaje Java
Observaciones
El lenguaje de programación de Java es ...
• Uso general : está diseñado para ser utilizado para escribir software en una amplia
variedad de dominios de aplicación y carece de funciones especializadas para cualquier
dominio específico.
• Portátil : se puede compilar en cualquier plataforma con javac y los archivos de clase
resultantes se pueden ejecutar en cualquier plataforma que tenga una JVM.
El objetivo de Java es permitir que los desarrolladores de aplicaciones "escriban una vez, se
ejecuten en cualquier lugar" (WORA), lo que significa que el código compilado de Java puede
ejecutarse en todas las plataformas que admiten Java sin la necesidad de una recompilación.
El código Java se compila a un código de bytes (los archivos .class ) que, a su vez, son
interpretados por la Máquina Virtual de Java (JVM). En teoría, el código de bytes creado por un
compilador de Java debería ejecutarse de la misma manera en cualquier JVM, incluso en un tipo
diferente de computadora. La JVM podría (y en los programas del mundo real) elegir compilar en
comandos de máquina nativos las partes del código de bytes que se ejecutan a menudo. Esto se
denomina "compilación Just-in-time (JIT)".
• Java Standard Edition (SE) es la edición que está diseñada para uso general.
• Java Enterprise Edition (EE) agrega una gama de facilidades para crear servicios de "grado
empresarial" en Java. Java EE se cubre por separado .
• Java Micro Edition (ME) se basa en un subconjunto de Java SE y está diseñado para su uso
en dispositivos pequeños con recursos limitados.
https://riptutorial.com/es/home 2
Hay un tema separado en las ediciones de Java SE / EE / ME .
Cada edición tiene múltiples versiones. Las versiones de Java SE se enumeran a continuación.
Instalando Java
Hay un tema separado sobre la instalación de Java (edición estándar) .
¿Que sigue?
Aquí hay enlaces a temas para continuar aprendiendo y entendiendo el lenguaje de programación
Java. Estos temas son los conceptos básicos de la programación de Java para comenzar.
Pruebas
Si bien Java no tiene soporte para realizar pruebas en la biblioteca estándar, existen bibliotecas
de terceros que están diseñadas para admitir pruebas. Las dos bibliotecas de pruebas de
unidades más populares son:
Otro
• Los patrones de diseño para Java están cubiertos en los patrones de diseño .
https://riptutorial.com/es/home 3
• La programación para Android está cubierta en Android .
• Las tecnologías Java Enterprise Edition están cubiertas en Java EE .
• Las tecnologías Oracle JavaFX están cubiertas en JavaFX .
1. En la sección Versiones , la fecha de finalización de la vida útil (gratuita) es cuando Oracle dejará de publicar
nuevas actualizaciones de Java SE en sus sitios públicos de descarga. Los clientes que necesitan acceso continuo a
correcciones de errores críticos y correcciones de seguridad, así como el mantenimiento general de Java SE pueden
obtener soporte a largo plazo a través del soporte de Oracle Java SE .
Versiones
Java SE 9 (acceso
Ninguna futuro 2017-07-27
temprano)
Patio de
Java SE 1.2 antes del 2009-11-04 1998-12-08
recreo
Examples
Creando tu primer programa Java
Cree un nuevo archivo en su editor de texto o IDE llamado HelloWorld.java . Luego pegue este
bloque de código en el archivo y guarde:
https://riptutorial.com/es/home 4
Corre en vivo en Ideone
Nota: Para que Java reconozca esto como una public class (y no arroje un error de tiempo de
compilación ), el nombre del archivo debe ser el mismo que el nombre de la clase ( HelloWorld en
este ejemplo) con una extensión .java . También debe haber un modificador de acceso public
antes de él.
Las convenciones de nomenclatura recomiendan que las clases de Java comiencen con un
carácter en mayúscula y estén en formato de caja de camello (en el que la primera letra de cada
palabra se escribe con mayúscula). Las convenciones recomiendan contra guiones bajos ( _ ) y
signos de dólar ( $ ).
cd /path/to/containing/folder/
Ingrese javac seguido del nombre del archivo y la extensión de la siguiente manera:
$ javac HelloWorld.java
Es bastante común que el error 'javac' is not recognized as an internal or external command,
operable program or batch file. incluso cuando haya instalado el JDK y pueda ejecutar el
programa desde IDE ej. eclipse etc. Dado que la ruta no se agrega al entorno de forma
predeterminada.
En caso de que obtenga esto en Windows, para resolverlo, primero intente javac.exe su ruta
javac.exe , es muy probable que esté en su C:\Program Files\Java\jdk(version number)\bin . A
continuación, intente ejecutarlo con a continuación.
Anteriormente, cuando llamábamos a javac , era igual que el comando anterior. Solo en ese caso,
su OS sabía dónde residía javac . Así que vamos a decirlo ahora, de esta manera no tienes que
escribir todo el camino cada vez. Necesitaríamos agregar esto a nuestro PATH
No puedes deshacer esto así que ten cuidado. Primero copia tu ruta existente al bloc de notas.
Luego, para obtener la ruta de acceso exacta a su javac busque manualmente la carpeta donde
reside javac haga clic en la barra de direcciones y luego cópiela. Debería verse como c:\Program
Files\Java\jdk1.8.0_xx\bin
En el campo "Valor variable", pegue este EN FRENTE de todos los directorios existentes, seguido
https://riptutorial.com/es/home 5
de un punto y coma (;). NO BORRAR ninguna entrada existente.
El compilador generará entonces un código de bytes archivo llamado HelloWorld.class que puede
ser ejecutado en la máquina virtual de Java (JVM) . El compilador del lenguaje de programación
Java, javac , lee los archivos de origen escritos en el lenguaje de programación Java y los compila
en archivos de clase de código de bytecode . Opcionalmente, el compilador también puede
procesar las anotaciones encontradas en los archivos de origen y de clase utilizando la API de
Procesamiento de Anotación Pluggable . El compilador es una herramienta de línea de comandos,
pero también se puede invocar utilizando la API del compilador de Java.
Para ejecutar su programa, ingrese java seguido del nombre de la clase que contiene el método
main ( HelloWorld en nuestro ejemplo). Observe cómo se omite .class :
$ java HelloWorld
¡Hola Mundo!
Nota: Para que los comandos de Java ( java , javac , etc.) sean reconocidos, deberá asegurarse
de que:
Deberá usar un compilador ( javac ) y un ejecutor ( java ) proporcionado por su JVM. Para saber
qué versiones tiene instaladas, ingrese java -version y javac -version en la línea de comandos. El
número de versión de su programa se imprimirá en el terminal (por ejemplo, 1.8.0_73 ).
https://riptutorial.com/es/home 6
HelloWorld , un método main y una declaración dentro del método main .
La palabra clave de class comienza la definición de clase para una clase llamada HelloWorld .
Cada aplicación Java contiene al menos una definición de clase ( Más información sobre clases ).
Este es un método de punto de entrada (definido por su nombre y firma de public static void
main(String[]) ) desde el cual JVM puede ejecutar su programa. Cada programa de Java debería
tener uno. Es:
• public: lo que significa que el método también se puede llamar desde cualquier lugar desde
fuera del programa. Ver Visibilidad para más información sobre esto.
• static : significa que existe y se puede ejecutar por sí mismo (a nivel de clase sin crear un
objeto).
• void : significa que no devuelve ningún valor. Nota: Esto es diferente a C y C ++ donde se
espera un código de retorno como int (la forma de Java es System.exit() ).
• Una matriz (normalmente llamada args ) de String s pasa como argumentos a la función
principal (por ejemplo, desde los argumentos de la línea de comando )
Piezas no requeridas:
• El nombre args es un nombre de variable, por lo que puede llamarse como quieras, aunque
normalmente se llama args .
• Si su tipo de parámetro es una matriz ( String[] args ) o Varargs ( String... args ) no
importa porque las matrices se pueden pasar a varargs.
Nota: una sola aplicación puede tener varias clases que contengan un método de punto de
entrada ( main ). El punto de entrada de la aplicación está determinado por el nombre de clase
pasado como un argumento al comando java .
System.out.println("Hello, World!");
Elemento Propósito
https://riptutorial.com/es/home 7
Elemento Propósito
este es el nombre del campo estático del tipo PrintStream dentro de la clase
out
System contiene la funcionalidad de salida estándar.
"Hello, este es el literal de cadena que se pasa como parámetro al método println .
World!" Las comillas dobles en cada extremo delimitan el texto como una cadena.
Aquí hay otro ejemplo que demuestra el paradigma OO. Vamos a modelar un equipo de fútbol
con un miembro (¡sí, uno!). Puede haber más, pero lo discutiremos cuando lleguemos a los
arreglos.
https://riptutorial.com/es/home 8
class Member {
private String name;
private String type;
private int level; // note the data type here
private int rank; // note the data type here as well
¿Por qué usamos private aquí? Bueno, si alguien desea saber su nombre, debe preguntarle
directamente, en lugar de buscar en su bolsillo y sacar su tarjeta de Seguro Social. Este private
hace algo así: impide que las entidades externas accedan a sus variables. Solo puede devolver
miembros private través de las funciones de obtención (que se muestran a continuación).
Después de ponerlo todo junto, y de agregar los métodos de obtención y el método principal,
como se mencionó anteriormente, tenemos:
class Member {
private String name;
private String type;
private int level;
private int rank;
https://riptutorial.com/es/home 9
return this.type; // my type is ...
}
Salida:
Aurieel
light
10
1
Corre en ideone
Una vez más, el método main dentro de la clase de Test es el punto de entrada a nuestro
programa. Sin el método main , no podemos decirle a la Máquina Virtual Java (JVM) desde dónde
comenzar la ejecución del programa.
1 - Debido a que la clase HelloWorld tiene poca relación con la clase System , solo puede acceder a datos public .
https://riptutorial.com/es/home 10
Capítulo 2: Acceso nativo de Java
Examples
Introducción a JNA
¿Qué es JNA?
Java Native Access (JNA) es una biblioteca desarrollada por la comunidad que proporciona a los
programas Java un acceso fácil a las bibliotecas compartidas nativas (archivos .dll en Windows,
archivos .so en Unix ...)
CRuntimeLibrary.java
package jna.introduction;
import com.sun.jna.Library;
import com.sun.jna.Native;
// We declare the printf function we need and the library containing it (msvcrt)...
public interface CRuntimeLibrary extends Library {
CRuntimeLibrary INSTANCE =
(CRuntimeLibrary) Native.loadLibrary("msvcrt", CRuntimeLibrary.class);
MyFirstJNAProgram.java
package jna.introduction;
https://riptutorial.com/es/home 11
public class MyFirstJNAProgram {
public static void main(String args[]) {
CRuntimeLibrary.INSTANCE.printf("Hello World from JNA !");
}
}
¿A dónde ir ahora?
Salta a otro tema aquí o salta al sitio oficial .
https://riptutorial.com/es/home 12
Capítulo 3: Afirmando
Sintaxis
• afirmar expresión1 ;
• afirmar expresión1 : expresión2 ;
Parámetros
Parámetro Detalles
Observaciones
Por defecto, las aserciones están deshabilitadas en tiempo de ejecución.
Las aserciones son declaraciones que arrojarán un error si su expresión se evalúa como false .
Las afirmaciones solo deben usarse para probar el código; nunca deben ser utilizados en la
producción.
Examples
Comprobando aritmética con aseverar.
a = 1 - Math.abs(1 - a % 2);
return a;
https://riptutorial.com/es/home 13
Capítulo 4: Agentes de Java
Examples
Modificando clases con agentes.
En primer lugar, asegúrese de que el agente que se está utilizando tenga los siguientes atributos
en el archivo Manifest.mf:
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Iniciar un agente java permitirá que el agente acceda a la clase de Instrumentación. Con
Instrumentation puede llamar a addTransformer (transformador ClassFileTransformer) .
ClassFileTransformers te permitirá reescribir los bytes de las clases. La clase tiene un solo
método que suministra el ClassLoader que carga la clase, el nombre de la clase, una instancia de
java.lang.Class, es ProtectionDomain y, por último, los bytes de la propia clase.
Se parece a esto:
Modificar una clase puramente de bytes puede llevar siglos. Para remediar esto, hay bibliotecas
que se pueden usar para convertir los bytes de clase en algo más utilizable.
En este ejemplo, usaré ASM, pero otras alternativas como Javassist y BCEL tienen
características similares.
Desde aquí se pueden hacer cambios al objeto ClassNode. Esto hace que cambiar el acceso al
campo / método sea increíblemente fácil. Además, con la API del árbol de ASM, la modificación
del código de bytes de los métodos es muy sencilla.
Una vez que las ediciones hayan finalizado, puede volver a convertir el ClassNode en bytes con
el siguiente método y devolverlos en el método de transformación :
https://riptutorial.com/es/home 14
public static byte[] getNodeBytes(ClassNode cn, boolean useMaxs) {
ClassWriter cw = new ClassWriter(useMaxs ? ClassWriter.COMPUTE_MAXS :
ClassWriter.COMPUTE_FRAMES);
cn.accept(cw);
byte[] b = cw.toByteArray();
return b;
}
Los agentes se pueden agregar a una JVM en tiempo de ejecución. Para cargar un agente,
deberá usar VirtualMachine.attatch (Id . De cadena) de Attach API. A continuación, puede cargar
un jar de agente compilado con el siguiente método:
Esto no llamará premain ((String agentArgs, Instrumentation inst) en el agente cargado, sino que
llamará a agentmain (String agentArgs, Instrumentation inst) . Esto requiere que Agent-Class esté
configurado en el agente Manifest.mf.
import java.lang.instrument.Instrumentation;
Cuando esté compilado en un archivo jar, abra el Manifiesto y asegúrese de que tenga el atributo
de clase principal.
Premain-Class: PremainExample
https://riptutorial.com/es/home 15
Para usar el agente con otro programa java "myProgram", debe definir el agente en los
argumentos de JVM:
https://riptutorial.com/es/home 16
Capítulo 5: Ajuste de rendimiento de Java
Examples
Enfoque general
Internet está repleto de consejos para mejorar el rendimiento de los programas Java. Quizás el
consejo número uno sea la conciencia. Eso significa:
El primer punto se debe hacer durante la etapa de diseño si se habla de un nuevo sistema o
módulo. Si se habla de código heredado, las herramientas de análisis y prueba entran en escena.
La herramienta más básica para analizar el rendimiento de su JVM es JVisualVM, que se incluye
en el JDK.
En Java, es demasiado "fácil" crear muchas instancias de String que no son necesarias. Esa y
otras razones pueden hacer que su programa tenga muchas cadenas que el GC está ocupado
limpiando.
myString += "foo";
El problema es que cada + crea una nueva Cadena (generalmente, ya que los nuevos
compiladores optimizan algunos casos). Se puede hacer una optimización posible utilizando
StringBuilder o StringBuffer :
https://riptutorial.com/es/home 17
Si crea cadenas largas con frecuencia (por ejemplo, SQL), use una API de construcción de
cadenas.
fuente
Teniendo en cuenta este sabio consejo, este es el procedimiento recomendado para optimizar
programas:
2. Llegue a un estado de trabajo y (idealmente) desarrolle pruebas unitarias para las partes
clave del código base.
4. Medir el rendimiento.
5. Compare el rendimiento medido con sus criterios para determinar qué tan rápido debe ser la
aplicación. (Evite criterios poco realistas, inalcanzables o no cuantificables como "lo más
rápido posible".)
6. Si ha cumplido con los criterios, PARE. Tu trabajo está hecho. (Cualquier esfuerzo adicional
es probablemente una pérdida de tiempo.)
https://riptutorial.com/es/home 18
8. Examine los resultados de la creación de perfiles y elija los "hotspots de rendimiento" más
grandes (no optimizados); Es decir, las secciones del código donde la aplicación parece
estar gastando más tiempo.
9. Analice la sección del código del hotspot para tratar de entender por qué es un cuello de
botella y piense en una manera de hacerlo más rápido.
11. Vuelva a ejecutar el punto de referencia para ver si el cambio de código ha mejorado el
rendimiento:
Claramente, hay un punto más allá del cual la optimización del punto de acceso es una pérdida
de esfuerzo. Si llegas a ese punto, debes adoptar un enfoque más radical. Por ejemplo:
Pero siempre que sea posible, confíe en las herramientas y la medición en lugar del instinto para
dirigir su esfuerzo de optimización.
https://riptutorial.com/es/home 19
Capítulo 6: Análisis XML utilizando las API de
JAXP
Observaciones
El análisis XML es la interpretación de documentos XML para manipular su contenido mediante
construcciones sensibles, ya sean "nodos", "atributos", "documentos", "espacios de nombres" o
eventos relacionados con estas construcciones.
Java tiene una API nativa para el manejo de documentos XML, llamada JAXP, o API de Java para
el procesamiento XML . JAXP y una implementación de referencia se han incluido en todas las
versiones de Java desde Java 1.4 (JAXP v1.1) y han evolucionado desde entonces. Java 8
enviado con la versión 1.6 de JAXP.
La API proporciona diferentes formas de interactuar con documentos XML, que son:
Bajo la interfaz del Modelo de objetos de documento, un documento XML se representa como un
árbol, comenzando con el "Elemento del documento". El tipo base de la API es el tipo de Node ,
permite navegar de un Node a su padre, sus hijos o sus hermanos (aunque, no todos los Node
pueden tener hijos, por ejemplo, los nodos de Text son finales en el árbol, y nunca tener hijos).
Las etiquetas XML se representan como Element s, que amplían notablemente el Node con
métodos relacionados con atributos.
La interfaz DOM es muy útil ya que permite un análisis de una línea de documentos XML como
árboles y permite una modificación fácil del árbol construido (adición de nodo, supresión, copia,
...) y, finalmente, su serialización (de nuevo al disco). ) modificaciones posteriores. Sin embargo,
esto tiene un precio: el árbol reside en la memoria, por lo tanto, los árboles DOM no siempre son
prácticos para grandes documentos XML. Además, la construcción del árbol no siempre es la
forma más rápida de tratar con el contenido XML, especialmente si uno no está interesado en
todas las partes del documento XML.
https://riptutorial.com/es/home 20
La API de SAX es una API orientada a eventos para tratar con documentos XML. Bajo este
modelo, los componentes de un documento XML se interpretan como eventos (por ejemplo, "se
ha abierto una etiqueta", "se ha cerrado una etiqueta", "se ha encontrado un nodo de texto", "se
ha encontrado un comentario"). ..
La API de SAX utiliza un enfoque de "análisis de inserción", donde un Parser SAX es responsable
de interpretar el documento XML e invoca métodos en un delegado (un ContentHandler ) para
tratar cualquier evento que se encuentre en el documento XML. Por lo general, uno nunca escribe
un analizador, pero proporciona un controlador para recopilar todas las informaciones necesarias
del documento XML.
La interfaz SAX supera las limitaciones de la interfaz DOM manteniendo solo los datos mínimos
necesarios en el nivel del analizador (por ejemplo, contextos de espacios de nombres, estado de
validación), por lo tanto, solo las informaciones que guarda ContentHandler , de las que usted, el
desarrollador, es responsable, son guardado en la memoria. La desventaja es que no hay manera
de "retroceder en el tiempo / el documento XML" con este enfoque: mientras que DOM permite
que un Node regrese a su padre, no existe tal posibilidad en SAX.
La API comienza con XMLStreamReader (o XMLEventReader ), que son las puertas de acceso a
través de las cuales el desarrollador puede preguntar a nextEvent() , de forma nextEvent() .
Examples
Analizar y navegar un documento utilizando la API DOM
Uno puede usar el siguiente código para construir un árbol DOM a partir de una String :
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
https://riptutorial.com/es/home 21
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
https://riptutorial.com/es/home 22
</library>
Uno puede usar el siguiente código para analizarlo y construir un mapa de títulos de libros por ID
de libro.
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
System.out.println(bookTitlesById);
}
Esto produce:
https://riptutorial.com/es/home 23
Found start of element: book
Found start of element: notABook
{1=Effective Java, 2=Java Concurrency In Practice}
Para el análisis de documentos más complejos (elementos más profundos, anidados, ...), es una
buena práctica "delegar" el analizador a sub-métodos u otros objetos, por ejemplo, tener una
clase o método BookParser , y hacer que se ocupe de cada elemento de START_ELEMENT a
END_ELEMENT de la etiqueta XML del libro.
También se puede usar un objeto de Stack para mantener datos importantes arriba y abajo del
árbol.
https://riptutorial.com/es/home 24
Capítulo 7: Anotaciones
Introducción
En Java, una anotación es una forma de metadatos sintácticos que se pueden agregar al código
fuente de Java. Proporciona datos sobre un programa que no forma parte del programa en sí. Las
anotaciones no tienen ningún efecto directo en el funcionamiento del código que anotan. Clases,
métodos, variables, parámetros y paquetes pueden ser anotados.
Sintaxis
• @AnnotationName // 'Anotación de marcador' (sin parámetros)
• @AnnotationName (someValue) // establece el parámetro con el nombre 'valor'
• @AnnotationName (param1 = value1) // parámetro con nombre
• @AnnotationName (param1 = value1, param2 = value2) // múltiples parámetros nombrados
• @AnnotationName (param1 = {1, 2, 3}) // parámetro de matriz con nombre
• @AnnotationName ({value1}) // array con un solo elemento como parámetro con el nombre
'value'
Observaciones
Tipos de parametros
Solo se permiten expresiones constantes de los siguientes tipos para los parámetros, así como
matrices de estos tipos:
• String
• Class
• tipos primitivos
• Tipos de enumeración
• Tipos de anotaciones
Examples
Anotaciones incorporadas
La edición estándar de Java viene con algunas anotaciones predefinidas. No es necesario que los
defina por sí mismo y puede usarlos inmediatamente. Permiten al compilador habilitar algunas
comprobaciones fundamentales de métodos, clases y código.
@Anular
Esta anotación se aplica a un método y dice que este método debe anular un método de
https://riptutorial.com/es/home 25
superclase o implementar una definición de método de superclase abstracta. Si esta anotación se
utiliza con cualquier otro tipo de método, el compilador arrojará un error.
Superclase de concreto
Clase abstracta
No funciona
class Logger1 {
public void log(String logString) {
System.out.prinln(logString);
}
}
class Logger2 {
// This will throw compile-time error. Logger2 is not a subclass of Logger1.
// log method is not overriding anything
@Override
public void log(String logString) {
System.out.println("Log 2" + logString);
}
}
El propósito principal es detectar errores, donde crees que estás anulando un método, pero en
realidad estás definiendo uno nuevo.
class Vehicle {
public void drive() {
System.out.println("I am driving");
https://riptutorial.com/es/home 26
}
}
• En Java 5, significaba que el método anotado tenía que anular un método no abstracto
declarado en la cadena de superclase.
• Desde Java 6 en adelante, también se satisface si el método anotado implementa un
método abstracto declarado en la jerarquía de superclase / interfaz de clases.
(Ocasionalmente, esto puede causar problemas al realizar un back-port del código a Java 5.)
@Obsoleto
Esto marca el método como obsoleto. Puede haber varias razones para esto:
La anotación hará que el compilador emita un error si lo usa. Los IDE también pueden resaltar
este método de alguna manera como desaprobado
class ComplexAlgorithm {
@Deprecated
public void oldSlowUnthreadSafeMethod() {
// stuff here
}
@SuppressWarnings
https://riptutorial.com/es/home 27
En casi todos los casos, cuando el compilador emite una advertencia, la acción más apropiada es
corregir la causa. En algunos casos (por ejemplo, el código genérico que usa un código pre-
genérico seguro para los tipos) puede que no sea posible y es mejor suprimir las advertencias
que espera y no puede corregir, por lo que puede ver más claramente las advertencias
inesperadas.
Esta anotación se puede aplicar a toda una clase, método o línea. Toma la categoría de
advertencia como parámetro.
@SuppressWarnings("deprecation")
public class RiddledWithWarnings {
// several methods calling deprecated code here
}
@SuppressWarning("finally")
public boolean checkData() {
// method calling return from within finally block
}
Es mejor limitar el alcance de la anotación tanto como sea posible, para evitar que también se
supriman las advertencias inesperadas. Por ejemplo, al limitar el alcance de la anotación a una
sola línea:
Las advertencias admitidas por esta anotación pueden variar de compilador a compilador. Solo
las advertencias unchecked y de deprecation se mencionan específicamente en el JLS. Se
ignorarán los tipos de advertencia no reconocidos.
@SafeVarargs
Hay casos en que el uso es seguro, en cuyo caso puede anotar el método con la anotación
SafeVarargs para suprimir la advertencia. Esto obviamente oculta la advertencia si su uso no es
seguro también.
@FunctionalInterface
Esta es una anotación opcional utilizada para marcar un FunctionalInterface. Hará que el
compilador se queje si no cumple con la especificación FunctionalInterface (tiene un solo método
abstracto)
https://riptutorial.com/es/home 28
@FunctionalInterface
public interface ITrade {
public boolean check(Trade t);
}
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
@interface MyDefaultAnnotation {
@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeVisibleAnnotation {
@MyDefaultAnnotation
static class RuntimeCheck1 {
}
@MyRuntimeVisibleAnnotation
static class RuntimeCheck2 {
}
Los tipos de anotación se definen con @interface . Los parámetros se definen de manera similar a
los métodos de una interfaz regular.
@interface MyAnnotation {
String param1();
boolean param2();
int[] param3(); // array parameter
https://riptutorial.com/es/home 29
}
Valores predeterminados
@interface MyAnnotation {
String param1() default "someValue";
boolean param2() default true;
int[] param3() default {};
}
Meta-Anotaciones
Las meta-anotaciones son anotaciones que se pueden aplicar a los tipos de anotación. La meta-
anotación predefinida especial define cómo se pueden usar los tipos de anotación.
@Objetivo
La meta-anotación de @Target restringe los tipos a los que se puede aplicar la anotación.
@Target(ElementType.METHOD)
@interface MyAnnotation {
// this annotation can only be applied to methods
}
Valores disponibles
@Retention(RetentionPolicy.RUNTIME)
ANNOTATION_TYPE tipos de anotaciones @interface MyAnnotation
@MyAnnotation
CONSTRUCTOR constructores public MyClass() {}
https://riptutorial.com/es/home 30
ejemplo de uso en el elemento de
Tipo de elemento objetivo
destino
@XmlElement
MÉTODO metodos public int getCount() {...}
public Rectangle(
@NamedArg("width") double
width,
Parámetros de método /
PARÁMETRO @NamedArg("height") double
constructor height) {
...
}
Java SE 8
ejemplo de uso en el elemento de
Tipo de elemento objetivo
destino
Object o = "42";
TYPE_USE Uso de un tipo String s = (@MyAnnotation String)
o;
@Retencion
La meta-anotación de @Retention define la visibilidad de la anotación durante el proceso de
https://riptutorial.com/es/home 31
compilación o ejecución de las aplicaciones. De forma predeterminada, las anotaciones se
incluyen en los archivos .class , pero no son visibles en tiempo de ejecución. Para hacer que una
anotación sea accesible en tiempo de ejecución, RetentionPolicy.RUNTIME debe establecerse en
esa anotación.
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
// this annotation can be accessed with reflections at runtime
}
Valores disponibles
Política de
Efecto
retención
@Documentado
La meta-anotación @Documented se usa para marcar anotaciones cuyo uso debe ser documentado
por los generadores de documentación API como javadoc . No tiene valores. Con @Documented ,
todas las clases que usan la anotación la incluirán en su página de documentación generada. Sin
@Documented , no es posible ver qué clases usan la anotación en la documentación.
@Heredado
La meta-anotación @Inherited es relevante para las anotaciones que se aplican a las clases. No
tiene valores. Marcar una anotación como @Inherited altera la forma en que funciona la consulta
de anotación.
• Para una anotación no heredada, la consulta solo examina la clase que se está
examinando.
• Para una anotación heredada, la consulta también verificará la cadena de superclase
(recursivamente) hasta que se encuentre una instancia de la anotación.
Tenga en cuenta que solo se consultan las superclases: se ignorarán todas las anotaciones
asociadas a las interfaces en la jerarquía de clases.
https://riptutorial.com/es/home 32
@Repeable
La meta-anotación @Repeatable se agregó en Java 8. Indica que se pueden adjuntar múltiples
instancias de la anotación al destino de la anotación. Esta meta-anotación no tiene valores.
Puede obtener las propiedades actuales de la anotación utilizando Reflexión para obtener el
Método o el Campo o la Clase que tiene aplicada una anotación, y luego obtener las propiedades
deseadas.
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String key() default "foo";
String value() default "bar";
}
class AnnotationExample {
// Put the Annotation on the method, but leave the defaults
@MyAnnotation
public void testDefaults() throws Exception {
// Using reflection, get the public method "testDefaults", which is this method with
no args
Method method = AnnotationExample.class.getMethod("testDefaults", null);
https://riptutorial.com/es/home 33
} catch( Exception e ) {
// Shouldn't throw any Exceptions
System.err.println("Exception [" + e.getClass().getName() + "] - " +
e.getMessage());
e.printStackTrace(System.err);
}
}
}
La salida será
foo = bar
baz = buzz
Repetir anotaciones
Hasta Java 8, dos instancias de la misma anotación no se podían aplicar a un solo elemento. La
solución estándar era usar una anotación de contenedor que contenga una matriz de alguna otra
anotación:
// Author.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String value();
}
// Authors.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
Author[] value();
}
// Test.java
@Authors({
@Author("Mary"),
@Author("Sam")
})
public class Test {
public static void main(String[] args) {
Author[] authors = Test.class.getAnnotation(Authors.class).value();
for (Author author : authors) {
System.out.println(author.value());
// Output:
// Mary
// Sam
}
}
}
Java SE 8
Java 8 proporciona una forma más limpia y transparente de usar anotaciones de contenedor,
utilizando la anotación @Repeatable . Primero agregamos esto a la clase de Author :
@Repeatable(Authors.class)
https://riptutorial.com/es/home 34
Esto le dice a Java que trate las múltiples anotaciones de @Author como si estuvieran rodeadas
por el contenedor @Authors . También podemos usar Class.getAnnotationsByType() para acceder a
la matriz @Author por su propia clase, en lugar de a través de su contenedor:
@Author("Mary")
@Author("Sam")
public class Test {
public static void main(String[] args) {
Author[] authors = Test.class.getAnnotationsByType(Author.class);
for (Author author : authors) {
System.out.println(author.value());
// Output:
// Mary
// Sam
}
}
}
Anotaciones heredadas
Por defecto, las anotaciones de clase no se aplican a los tipos que las extienden. Esto se puede
cambiar agregando la anotación @Inherited a la definición de anotación
Ejemplo
Considere las siguientes 2 anotaciones:
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotationType {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UninheritedAnnotationType {
}
@UninheritedAnnotationType
class A {
}
@InheritedAnnotationType
class B extends A {
}
class C extends B {
}
https://riptutorial.com/es/home 35
ejecutando este código
System.out.println(new A().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println("_________________________________");
System.out.println(new A().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(UninheritedAnnotationType.class));
null
@InheritedAnnotationType()
@InheritedAnnotationType()
_________________________________
@UninheritedAnnotationType()
null
null
Tenga en cuenta que las anotaciones solo pueden heredarse de las clases, no de las interfaces.
La anotacion
La anotación @Setter es un marcador que se puede aplicar a los métodos. La anotación se
descartará durante la compilación y no estará disponible posteriormente.
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Setter {
}
El procesador de anotaciones.
El SetterProcessor utiliza la clase SetterProcessor para procesar las anotaciones. Comprueba, si
los métodos anotados con la anotación @Setter son public , static métodos no static con un
nombre que comienza con set y que tienen una letra mayúscula como cuarta letra. Si una de
https://riptutorial.com/es/home 36
estas condiciones no se cumple, se escribe un error en el Messager . El compilador escribe esto en
stderr, pero otras herramientas podrían usar esta información de manera diferente. Por ejemplo,
el IDE de NetBeans permite al usuario especificar procesadores de anotación que se utilizan para
mostrar mensajes de error en el editor.
package annotation.processor;
import annotation.Setter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
@SupportedAnnotationTypes({"annotation.Setter"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SetterProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
{
// get elements annotated with the @Setter annotation
Set<? extends Element> annotatedElements =
roundEnv.getElementsAnnotatedWith(Setter.class);
https://riptutorial.com/es/home 37
// check, if setter is public
if (!method.getModifiers().contains(Modifier.PUBLIC)) {
printError(method, "setter must be public");
}
@Override
public void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
embalaje
Para ser aplicado por el compilador, el procesador de anotaciones debe estar disponible para el
SPI (ver ServiceLoader ).
annotation.processor.SetterProcessor
import annotation.Setter;
@Setter
https://riptutorial.com/es/home 38
private void setValue(String value) {}
@Setter
public void setString(String value) {}
@Setter
public static void main(String[] args) {}
Esto se podría evitar especificando la opción -proc:none para javac . También puede renunciar a la
compilación habitual especificando -proc:only lugar.
Integración IDE
Netbeans
Los procesadores de anotación se pueden utilizar en el editor de NetBeans. Para hacer esto, el
procesador de anotaciones debe especificarse en la configuración del proyecto:
https://riptutorial.com/es/home 39
4. en la ventana emergente que aparece, ingrese el nombre de clase completamente calificado
del procesador de anotaciones y haga clic en Ok .
Resultado
Las anotaciones pueden aparecer antes de los tipos o declaraciones. Es posible que aparezcan
en un lugar donde se puedan aplicar tanto a un tipo como a una declaración.
A qué se aplica exactamente una anotación se rige por la "meta-anotación" @Target . Consulte
"Definición de tipos de anotación" para obtener más información.
Las anotaciones se utilizan para una multitud de propósitos. Los marcos como Spring y Spring-
MVC hacen uso de anotaciones para definir dónde se deben inyectar las dependencias o dónde
se deben enrutar las solicitudes.
Otros marcos usan anotaciones para la generación de código. Lombok y JPA son ejemplos
principales, que usan anotaciones para generar código Java (y SQL).
Este tema tiene como objetivo proporcionar una visión global de:
Cuando se introdujeron las anotaciones de Java por primera vez, no había ninguna disposición
https://riptutorial.com/es/home 40
para anotar el objetivo de un método de instancia o el parámetro de constructor oculto para un
constructor de clases internas. Esto se solucionó en Java 8 con la adición de declaraciones de
parámetros del receptor ; ver JLS 8.4.1 .
El siguiente ejemplo ilustra la sintaxis para ambos tipos de parámetros del receptor:
El único propósito de los parámetros del receptor es permitirle agregar anotaciones. Por ejemplo,
puede tener una anotación personalizada @IsOpen cuyo propósito es afirmar que un objeto
Closeable no se ha cerrado cuando se llama a un método. Por ejemplo:
En un nivel, la anotación @IsOpen sobre this podría simplemente servir como documentación. Sin
embargo, potencialmente podríamos hacer más. Por ejemplo:
https://riptutorial.com/es/home 41
Añadir múltiples valores de anotación
Un parámetro de anotación puede aceptar múltiples valores si se define como una matriz. Por
ejemplo, la anotación estándar @SuppressWarnings se define así:
El parámetro de value es una matriz de cadenas. Puede establecer varios valores utilizando una
notación similar a los inicializadores de matriz:
@SuppressWarnings({"unused"})
@SuppressWarnings({"unused", "javadoc"})
@SuppressWarnings("unused")
https://riptutorial.com/es/home 42
Capítulo 8: Apache Commons Lang
Examples
Implementar el método equals ()
Para implementar fácilmente el método equals de un objeto, puede usar la clase EqualsBuilder .
@Override
public boolean equals(Object obj) {
return builder.isEquals();
}
Usando la reflexión:
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, false);
}
el parámetro booleano es para indicar si los iguales deben verificar los campos transitorios.
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, "field1", "field2");
}
Para implementar hashCode método hashCode de un objeto, puede usar la clase HashCodeBuilder .
@Override
public int hashCode() {
https://riptutorial.com/es/home 43
HashCodeBuilder builder = new HashCodeBuilder();
builder.append(field1);
builder.append(field2);
builder.append(field3);
return builder.hashCode();
}
Usando la reflexión:
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, false);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "field1", "field2");
}
Para implementar fácilmente el método toString de un objeto, puede usar la clase ToStringBuilder
.
@Override
public String toString() {
return builder.toString();
}
Resultado de ejemplo:
ar.com.jonat.lang.MyClass@dd7123[<null>,0,false]
@Override
public String toString() {
https://riptutorial.com/es/home 44
builder.append("field1",field1);
builder.append("field2",field2);
builder.append("field3",field3);
return builder.toString();
}
Resultado de ejemplo:
ar.com.jonat.lang.MyClass@dd7404[field1=<null>,field2=0,field3=false]
@Override
public String toString() {
return builder.toString();
}
Resultado de ejemplo:
ar.com.bna.lang.MyClass@ebbf5c[
field1=<null>
field2=0
field3=false
]
Hay algunos estilos, por ejemplo JSON, sin nombre de clase, cortos, etc.
Vía la reflexión:
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
https://riptutorial.com/es/home 45
Capítulo 9: API de apilación
Introducción
Antes de Java 9, el acceso a los marcos de la pila de hilos estaba limitado a una clase interna
sun.reflect.Reflection . Específicamente el método sun.reflect.Reflection::getCallerClass .
Algunas bibliotecas se basan en este método que está en desuso.
Examples
Imprimir todos los marcos de pila de la secuencia actual
1 package test;
2
3 import java.lang.StackWalker.StackFrame;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.util.List;
7 import java.util.stream.Collectors;
8
9 public class StackWalkerExample {
10
11 public static void main(String[] args) throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
12 Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
13 fooMethod.invoke(null, (Object[]) null);
14 }
15 }
16
17 class FooHelper {
18 protected static void foo() {
19 BarHelper.bar();
20 }
21 }
22
23 class BarHelper {
24 protected static void bar() {
25 List<StackFrame> stack = StackWalker.getInstance()
26 .walk((s) -> s.collect(Collectors.toList()));
27 for(StackFrame frame : stack) {
28 System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " +
frame.getMethodName());
29 }
30 }
31 }
https://riptutorial.com/es/home 46
Salida:
test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main
A continuación se imprime la clase de llamada actual. Tenga en cuenta que, en este caso,
StackWalker debe crearse con la opción RETAIN_CLASS_REFERENCE , para que Class instancias de la
Class se conserven en los objetos StackFrame . De lo contrario se produciría una excepción.
class FooHelper {
protected static void foo() {
BarHelper.bar();
}
}
class BarHelper {
protected static void bar() {
System.out.println(StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).getCallerClass());
}
}
Salida:
class test.FooHelper
Un par de otras opciones permiten que los seguimientos de pila incluyan marcos de
implementación y / o reflexión. Esto puede ser útil para propósitos de depuración. Por ejemplo,
podemos agregar la opción SHOW_REFLECT_FRAMES a la instancia de StackWalker momento de la
creación, para que también se impriman los marcos para los métodos reflectivos:
package test;
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;
https://riptutorial.com/es/home 47
public class StackWalkerExample {
class FooHelper {
protected static void foo() {
BarHelper.bar();
}
}
class BarHelper {
protected static void bar() {
// show reflection methods
List<StackFrame> stack = StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES)
.walk((s) -> s.collect(Collectors.toList()));
for(StackFrame frame : stack) {
System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " +
frame.getMethodName());
}
}
}
Salida:
test.BarHelper 27 bar
test.FooHelper 20 foo
jdk.internal.reflect.NativeMethodAccessorImpl -2 invoke0
jdk.internal.reflect.NativeMethodAccessorImpl 62 invoke
jdk.internal.reflect.DelegatingMethodAccessorImpl 43 invoke
java.lang.reflect.Method 563 invoke
test.StackWalkerExample 14 main
Tenga en cuenta que los números de línea para algunos métodos de reflexión pueden no estar
disponibles, por lo que StackFrame.getLineNumber() puede devolver valores negativos.
https://riptutorial.com/es/home 48
Capítulo 10: API de reflexión
Introducción
Reflection es comúnmente utilizado por programas que requieren la capacidad de examinar o
modificar el comportamiento en tiempo de ejecución de las aplicaciones que se ejecutan en la
JVM. Java Reflection API se usa para ese propósito donde permite inspeccionar clases,
interfaces, campos y métodos en tiempo de ejecución, sin saber sus nombres en el momento de
la compilación. Y también hace posible instanciar nuevos objetos, e invocar métodos utilizando la
reflexión.
Observaciones
Actuación
Tenga en cuenta que la reflexión puede disminuir el rendimiento, solo úselo cuando su tarea no
pueda completarse sin reflexión.
Examples
Introducción
Lo esencial
La API de reflexión permite verificar la estructura de clase del código en tiempo de ejecución e
invocar el código dinámicamente. Esto es muy poderoso, pero también es peligroso ya que el
compilador no es capaz de determinar estáticamente si las invocaciones dinámicas son válidas.
Un ejemplo simple sería obtener los constructores públicos y los métodos de una clase
determinada:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
https://riptutorial.com/es/home 49
Constructor<?>[] constructors = clazz.getConstructors(); // returns all public constructors of
String
Method[] methods = clazz.getMethods(); // returns all public methods from String and parents
Con esta información es posible instanciar el objeto y llamar a diferentes métodos dinámicamente.
El siguiente ejemplo muestra cómo extraer la información de tipo genérico en los tres casos:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
System.out.println("Method parameter:");
final Type parameterType = method.getGenericParameterTypes()[0];
displayGenericType(parameterType, "\t");
System.out.println("Field type:");
final Type fieldType = field.getGenericType();
displayGenericType(fieldType, "\t");
https://riptutorial.com/es/home 50
}
Method parameter:
java.util.Map<java.lang.String, java.lang.Double>
java.lang.String
java.lang.Double
Method return type:
java.util.List<java.lang.Number>
java.lang.Number
Field type:
java.util.Map<java.lang.String, java.util.Map<java.lang.Integer,
java.util.List<java.lang.String>>>
java.lang.String
java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>
java.lang.Integer
java.util.List<java.lang.String>
java.lang.String
Invocando un método
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Para hacerlo, deberá usar el método Clase # getField () de una manera como la que se muestra a
continuación:
https://riptutorial.com/es/home 51
Field nameField = SomeClass.class.getDeclaredField("NAME");
// Get the field in class Field "modifiers". Note that it does not
// need to be static
Field modifiersField = Field.class.getDeclaredField("modifiers");
// Set the value of the modifiers field under an object for non-static fields
modifiersField.setInt(nameField, newModifiersOnNameField);
// Here I can directly access it. If needed, use reflection to get it. (Below)
System.out.println(SomeClass.NAME);
Obtener campos es mucho más fácil. Podemos usar Field # get () y sus variantes para obtener su
valor:
Cuando use Class # getDeclaredField , utilícelo para obtener un campo en la clase en sí:
class Hacked {
public String someState;
}
https://riptutorial.com/es/home 52
Constructor de llamadas
Donde la variable de constructors tendrá una instancia de Constructor para cada constructor
público declarado en la clase.
Si conoce los tipos de parámetros precisos del constructor al que desea acceder, puede filtrar el
constructor específico. El siguiente ejemplo devuelve el constructor público de la clase dada que
toma un Integer como parámetro:
enum Compass {
NORTH(0),
EAST(90),
SOUTH(180),
WEST(270);
private int degree;
Compass(int deg){
degree = deg;
}
public int getDegree(){
return degree;
}
}
En Java, una clase de enumeración es como cualquier otra clase, pero tiene algunas constantes
definidas para los valores de enumeración. Además, tiene un campo que es una matriz que
contiene todos los valores y dos métodos estáticos con values() nombre values() y
https://riptutorial.com/es/home 53
.
valueOf(String)
Podemos ver esto si usamos Reflection para imprimir todos los campos de esta clase
for(Field f : Compass.class.getDeclaredFields())
System.out.println(f.getName());
La salida será:
NORTE
ESTE
SUR
OESTE
la licenciatura
ENUM $ VALORES
Así que podríamos examinar clases de enumeración con Reflexión como cualquier otra clase.
Pero la API de Reflection ofrece tres métodos específicos de enumeración.
control de enumeración
Compass.class.isEnum();
recuperando valores
Devuelve una matriz de todos los valores de enumeración como Compass.values () pero sin la
necesidad de una instancia.
enumeración constante
for(Field f : Compass.class.getDeclaredFields()){
if(f.isEnumConstant())
System.out.println(f.getName());
}
Dada una String contiene el nombre de una clase, se puede acceder a su objeto de Class usando
Class.forName :
https://riptutorial.com/es/home 54
throw new IllegalStateException(ex);
}
Java SE 1.2
import java.lang.reflect.*;
class NewInstanceWithReflection{
public NewInstanceWithReflection(){
System.out.println("Default constructor");
}
public NewInstanceWithReflection( String a){
System.out.println("Constructor :String => "+a);
}
public static void main(String args[]) throws Exception {
NewInstanceWithReflection object =
(NewInstanceWithReflection)Class.forName("NewInstanceWithReflection").newInstance();
Constructor constructor = NewInstanceWithReflection.class.getDeclaredConstructor( new
Class[] {String.class});
NewInstanceWithReflection object1 =
(NewInstanceWithReflection)constructor.newInstance(new Object[]{"StackOverFlow"});
}
}
salida:
Default constructor
Constructor :String => StackOverFlow
Explicación:
https://riptutorial.com/es/home 55
Uso incorrecto de la API de Reflection para cambiar variables privadas y
finales
La reflexión es útil cuando se usa correctamente para el propósito correcto. Al utilizar la reflexión,
puede acceder a las variables privadas y reinicializar las variables finales.
import java.lang.reflect.*;
class A {
private String name;
public int age;
public final String rep;
public static int count=0;
public A(){
name = "Unset";
age = 0;
rep = "Reputation";
count++;
}
}
Salida:
https://riptutorial.com/es/home 56
A.name=StackOverFlow
A.age=20
A.rep=New Reputation
A.count=25
Explicación:
rompe ambas barreras se puede utilizar para cambiar las variables privadas y finales
Reflection
como se explicó anteriormente.
Si desea crear una instancia de una clase anidada interna, debe proporcionar un objeto de clase
de la clase envolvente como un parámetro adicional con la Clase # getDeclaredConstructor .
Proxies dinámicos
Los proxies dinámicos realmente no tienen mucho que ver con Reflection, pero son parte de la
API. Es básicamente una forma de crear una implementación dinámica de una interfaz. Esto
podría ser útil al crear servicios de maqueta.
Un proxy dinámico es una instancia de una interfaz que se crea con el llamado controlador de
invocación que intercepta todas las llamadas de método y permite el manejo de su invocación
manualmente.
https://riptutorial.com/es/home 57
public void someMethod1();
public int someMethod2(String s);
}
if(methodName.equals("someMethod1")){
System.out.println("someMethod1 was invoked!");
return null;
}
if(methodName.equals("someMethod2")){
System.out.println("someMethod2 was invoked!");
System.out.println("Parameter: " + args[0]);
return 42;
}
if(methodName.equals("anotherMethod")){
System.out.println("anotherMethod was invoked!");
return null;
}
System.out.println("Unkown method!");
return null;
}
};
https://riptutorial.com/es/home 58
Parameter: stackoverflow
anotherMethod was invoked!
La API de Reflection podría usarse para cambiar los valores de los campos privados y finales
incluso en la biblioteca predeterminada de JDK. Esto podría usarse para manipular el
comportamiento de algunas clases bien conocidas como veremos.
Lo que no es posible
Comencemos primero con la única limitación significa que el único campo que no podemos
cambiar con Reflexión. Ese es el Java SecurityManager . Se declara en java.lang.System as
for(Field f : System.class.getDeclaredFields())
System.out.println(f);
Cuerdas locas
Cada cadena Java está representada por la JVM como una instancia de la clase de String . Sin
embargo, en algunas situaciones, la JVM ahorra espacio de almacenamiento utilizando la misma
instancia para las cadenas que son. Esto sucede para los literales de cadena, y también para las
cadenas que han sido "internadas" llamando a String.intern() . Entonces, si tiene "hello" en su
código varias veces, siempre será la misma instancia de objeto.
Se supone que las cuerdas son inmutables, pero es posible usar la reflexión "malvada" para
cambiarlas. El siguiente ejemplo muestra cómo podemos cambiar los caracteres en una cadena
reemplazando su campo de value .
https://riptutorial.com/es/home 59
Así que este código imprimirá "apestas!"
1 = 42
Todo es verdad
Y de acuerdo con este post de stackoverflow podemos usar la reflexión para hacer algo realmente
malo.
Tenga en cuenta que lo que estamos haciendo aquí hará que la JVM se comporte de forma
inexplicable. Esto es muy peligroso.
https://riptutorial.com/es/home 60
Capítulo 11: AppDynamics y TIBCO
BusinessWorks Instrumentation para una
fácil integración
Introducción
Como AppDynamics pretende proporcionar una manera de medir el rendimiento de las
aplicaciones, la velocidad de desarrollo, la entrega (implementación) de las aplicaciones es un
factor esencial para que los esfuerzos de DevOps sean un verdadero éxito. La supervisión de una
aplicación TIBCO BW con AppD es generalmente simple y no requiere mucho tiempo, pero
cuando se implementan grandes conjuntos de aplicaciones, la instrumentación rápida es la clave.
Esta guía muestra cómo instrumentar todas sus aplicaciones BW en un solo paso sin modificar
cada aplicación antes de implementar.
Examples
Ejemplo de instrumentación de todas las aplicaciones BW en un solo paso
para Appdynamics
4. Vaya al final del archivo y agregue (reemplace? Con sus propios valores según sea
necesario o elimine el indicador que no se aplica): java.extended.properties = -javaagent:
/opt/appd/current/appagent/javaagent.jar - Dappdynamics.http.proxyHost =? -
Dappdynamics.http.proxyPort =? -Dappdynamics.agent.applicationName =? -
Dappdynamics.agent.tierName =? -Dappdynamics.agent.nodeName =% tibco.deployment%
-Dappdynamics.controller.ssl.enabled =? -Dappdynamics.controller.sslPort =? -
Dappdynamics.agent.logs.dir =? -Dappdynamics.agent.runtime.dir =? -
Dappdynamics.controller.hostName =? -Dappdynamics.controller.port =? -
Dappdynamics.agent.accountName =? -Dappdynamics.agent.accountAccessKey =?
5. Guardar archivo y volver a desplegar. Todas sus aplicaciones ahora deben ser
https://riptutorial.com/es/home 61
instrumentadas automáticamente en el momento del despliegue.
Lea AppDynamics y TIBCO BusinessWorks Instrumentation para una fácil integración en línea:
https://riptutorial.com/es/java/topic/10602/appdynamics-y-tibco-businessworks-instrumentation-
para-una-facil-integracion
https://riptutorial.com/es/home 62
Capítulo 12: Applets
Introducción
Los applets han sido parte de Java desde su lanzamiento oficial y se han utilizado para enseñar
Java y programación durante varios años.
Los últimos años han visto un impulso activo para alejarse de los applets y otros complementos
del navegador, con algunos navegadores que los bloquean o no los apoyan activamente.
En 2016, Oracle anunció sus planes de dejar de usar el complemento, pasando a una web sin
complementos
Observaciones
Un applet es una aplicación Java que normalmente se ejecuta dentro de un navegador web. La
idea básica es interactuar con el usuario sin la necesidad de interactuar con el servidor y transferir
información. Este concepto fue muy exitoso alrededor del año 2000 cuando la comunicación por
Internet era lenta y costosa.
nombre del
descripción
método
stop() se llama cada vez que el applet se superpone con otras ventanas
Examples
Applet mínimo
https://riptutorial.com/es/home 63
private String str = "StackOverflow";
@Override
public void init() {
setBackground(Color.gray);
}
@Override
public void destroy() {}
@Override
public void start() {}
@Override
public void stop() {}
@Override
public void paint(Graphics g) {
g.setColor(Color.yellow);
g.fillRect(1,1,300,150);
g.setColor(Color.red);
g.setFont(new Font("TimesRoman", Font.PLAIN, 48));
g.drawString(str, 10, 80);
}
}
Java SE 1.2
Antes de Java 1.2 y la introducción de los applets de API swing se extendió desde
java.applet.Applet .
Los applets no requieren un método principal. El punto de entrada está controlado por el ciclo de
vida. Para usarlos, necesitan estar incrustados en un documento HTML. Este es también el punto
donde se define su tamaño.
<html>
<head></head>
<body>
<applet code="MyApplet.class" width="400" height="200"></applet>
</body>
</html>
Los applets podrían usarse fácilmente para crear una GUI. Actúan como un Container y tienen un
método add() que toma cualquier componente awt o swing .
@Override
public void init(){
https://riptutorial.com/es/home 64
panel = new JPanel();
button = new JButton("ClickMe!");
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent ae) {
if(((String)cmbBox.getSelectedItem()).equals("greet")) {
JOptionPane.showMessageDialog(null,"Hello " + textField.getText());
} else {
JOptionPane.showMessageDialog(null,textField.getText() + " stinks!");
}
}
});
cmbBox = new JComboBox<>(new String[]{"greet", "offend"});
textField = new JTextField("John Doe");
panel.add(cmbBox);
panel.add(textField);
panel.add(button);
add(panel);
}
}
Puede usar el método getAppletContext() para obtener un objeto AppletContext que le permite
solicitar al navegador que abra un enlace. Para ello utiliza el método showDocument() . Su segundo
parámetro le dice al navegador que use una nueva ventana _blank o la que muestra el applet
_self .
Los applets de Java son capaces de cargar diferentes recursos. Pero como se ejecutan en el
navegador web del cliente, debe asegurarse de que estos recursos sean accesibles. Los applets
no pueden acceder a los recursos del cliente como el sistema de archivos local.
Si desea cargar recursos desde la misma URL en la que está almacenado el Applet, puede usar
el método getCodeBase() para recuperar la URL base. Para cargar recursos, los applets ofrecen los
métodos getImage() y getAudioClip() para cargar imágenes o archivos de audio.
https://riptutorial.com/es/home 65
Cargar y mostrar una imagen.
@Override
public void init(){
try {
img = getImage(new URL("http://cdn.sstatic.net/stackexchange/img/logos/so/so-
logo.png"));
} catch (MalformedURLException e) { /* omitted for brevity */ }
}
@Override
public void paint(Graphics g) {
g.drawImage(img, 0, 0, this);
}
}
@Override
public void init(){
try {
audioClip = getAudioClip(new URL("URL/TO/AN/AUDIO/FILE.WAV"));
} catch (MalformedURLException e) { /* omitted for brevity */ }
}
@Override
public void start() {
audioClip.play();
}
@Override
public void stop(){
audioClip.stop();
}
}
https://riptutorial.com/es/home 66
add(sp);
// load text
try {
URL url = new URL("http://www.textfiles.com/fun/quotes.txt");
InputStream in = url.openStream();
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
String line = "";
while((line = bf.readLine()) != null) {
textArea.append(line + "\n");
}
} catch(Exception e) { /* omitted for brevity */ }
}
}
https://riptutorial.com/es/home 67
Capítulo 13: Archivo I / O
Introducción
La E / S de Java (entrada y salida) se utiliza para procesar la entrada y producir la salida. Java
utiliza el concepto de flujo para agilizar la operación de E / S. El paquete java.io contiene todas las
clases necesarias para las operaciones de entrada y salida. El manejo de archivos también se
realiza en java mediante la API de E / S de Java.
Examples
Leyendo todos los bytes a un byte []
Java SE 7
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
try {
byte[] data = Files.readAllBytes(path);
} catch(IOException e) {
e.printStackTrace();
}
import java.awt.Image;
import javax.imageio.ImageIO;
...
try {
Image img = ImageIO.read(new File("~/Desktop/cat.png"));
} catch (IOException e) {
e.printStackTrace();
}
Java SE 7
https://riptutorial.com/es/home 68
} catch (IOException ioe) {
// Handle I/O Exception
ioe.printStackTrace();
}
Java SE 7
La mayoría de las API de archivos java.io aceptan tanto String como File como argumentos, por
lo que también podría usar
Los flujos proporcionan el acceso más directo al contenido binario, por lo que cualquier
implementación de InputStream / OutputStream siempre opera en int s y byte s.
// Read a chunk
byte[] data = new byte[1024];
int nBytesRead = inputStream.read(data);
if (nBytesRead >= 0) { // A negative value represents end of stream
// Write the chunk to another stream
outputStream.write(data, 0, nBytesRead);
}
Hay algunas excepciones, probablemente la más notable, PrintStream que agrega la "capacidad
de imprimir representaciones de varios valores de datos de manera conveniente". Esto permite
utilizar System.out como InputStream binario y como salida textual utilizando métodos como
System.out.println() .
https://riptutorial.com/es/home 69
Además, algunas implementaciones de flujo funcionan como una interfaz para contenidos de alto
nivel, como objetos Java (consulte Serialización) o tipos nativos, por ejemplo, DataOutputStream /
DataInputStream .
Con las clases Writer y Reader , Java también proporciona una API para flujos de caracteres
explícitos. Aunque la mayoría de las aplicaciones basarán estas implementaciones en flujos, la
API de flujo de caracteres no expone ningún método para contenido binario.
Siempre que sea necesario codificar caracteres en datos binarios (por ejemplo, al usar las clases
InputStreamWriter / OutputStreamWriter ), debe especificar un conjunto de caracteres si no desea
depender del conjunto de caracteres predeterminado de la plataforma. En caso de duda, utilice
una codificación compatible con Unicode, por ejemplo, UTF-8 que sea compatible con todas las
plataformas Java. Por lo tanto, probablemente debería alejarse de clases como FileWriter y
FileReader ya que siempre usan el conjunto de caracteres predeterminado de la plataforma. Una
mejor manera de acceder a los archivos utilizando secuencias de caracteres es esta:
Uno de los Reader s más utilizados es BufferedReader que proporciona un método para leer líneas
enteras de texto de otro lector y es probablemente la forma más sencilla de leer una línea de
caracteres en línea de secuencia:
https://riptutorial.com/es/home 70
\ Z es el símbolo EOF (fin de archivo). Cuando se establece como delimitador, el Escáner leerá el
relleno hasta que se alcance el indicador EOF.
https://riptutorial.com/es/home 71
}
}
}
Estos ejemplos asumen que ya sabes lo que es NIO de Java 7 en general, y estás acostumbrado
a escribir código usando java.io.File . Utilice estos ejemplos como un medio para encontrar
rápidamente más documentación centrada en NIO para la migración.
Hay mucho más en el NIO de Java 7, como los archivos asignados en memoria o la apertura de
un archivo ZIP o JAR utilizando FileSystem . Estos ejemplos solo cubrirán un número limitado de
casos de uso básicos.
Como regla básica, si está acostumbrado a realizar una operación de lectura / escritura del
sistema de archivos utilizando un método de instancia java.io.File , lo encontrará como un
método estático dentro de java.nio.file.Files .
Apuntar a un camino
// -> IO
File file = new File("io.txt");
// -> NIO
Path path = Paths.get("nio.txt");
// -> NIO
Path directory = Paths.get("C:/");
Path pathInDirectory = directory.resolve("nio.txt");
// -> NIO to IO
File fileFromPath = Paths.get("nio.txt").toFile();
https://riptutorial.com/es/home 72
Compruebe si el archivo existe y elimínelo si
existe.
// -> IO
if (file.exists()) {
boolean deleted = file.delete();
if (!deleted) {
throw new IOException("Unable to delete file");
}
}
// -> NIO
Files.deleteIfExists(path);
// -> IO
if (file.exists()) {
// Note: Not atomic
throw new IOException("File already exists");
}
try (FileOutputStream outputStream = new FileOutputStream(file)) {
for (String line : lines) {
outputStream.write((line + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
}
}
// -> NIO
try (OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW)) {
for (String line : lines) {
outputStream.write((line + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
}
}
https://riptutorial.com/es/home 73
carpeta
// -> IO
for (File selectedFile : folder.listFiles()) {
// Note: Depending on the number of files in the directory folder.listFiles() may take a
long time to return
System.out.println((selectedFile.isDirectory() ? "d" : "f") + " " +
selectedFile.getAbsolutePath());
}
// -> NIO
Files.walkFileTree(directory, EnumSet.noneOf(FileVisitOption.class), 1, new
SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path selectedPath, BasicFileAttributes attrs)
throws IOException {
System.out.println("d " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path selectedPath, BasicFileAttributes attrs) throws
IOException {
System.out.println("f " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
});
// -> NIO
// Note: Symbolic links are NOT followed unless explicitly passed as an argument to
Files.walkFileTree
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws
IOException {
System.out.println("d " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path selectedPath, BasicFileAttributes attrs) throws
IOException {
System.out.println("f " + selectedPath.toAbsolutePath());
return FileVisitResult.CONTINUE;
}
});
https://riptutorial.com/es/home 74
System.out.println((selectedFile.isDirectory() ? "d" : "f") + " " +
selectedFile.getAbsolutePath());
if (selectedFile.isDirectory()) {
// Note: Symbolic links are followed
recurseFolder(selectedFile);
}
}
}
Tenga en cuenta que desde Java 1.7 se introdujo la declaración try-with-resources lo que hizo
que la implementación de la operación de lectura / escritura sea mucho más sencilla:
https://riptutorial.com/es/home 75
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Puede leer un archivo binario utilizando este fragmento de código en todas las versiones
recientes de Java:
Java SE 1.4
Si está utilizando Java 7 o posterior, hay una forma más sencilla de usar la nio API :
Java SE 7
Cierre
Un archivo puede ser bloqueado usando la API FileChannel que se puede adquirir de los streams y
readers de Input Input.
https://riptutorial.com/es/home 76
/*
* try to lock the file. true means whether the lock is shared or not i.e. multiple
processes can acquire a
* shared lock (for reading only) Using false with readable channel only will generate an
exception. You should
* use a writable channel (taken from FileOutputStream) when using false. tryLock will
always return immediately
*/
FileLock lock = channel.tryLock(0, Long.MAX_VALUE, true);
if (lock == null) {
System.out.println("Unable to acquire lock");
} else {
System.out.println("Lock acquired successfully");
}
// you can also use blocking call which will block until a lock is acquired.
channel.lock();
// Once you have completed desired operations of file. release the lock
if (lock != null) {
lock.release();
}
Podemos copiar directamente los datos de una fuente a un sumidero de datos utilizando un bucle.
En este ejemplo, estamos leyendo datos de un InputStream y, al mismo tiempo, escribimos en un
OutputStream. Una vez que hayamos terminado de leer y escribir, tenemos que cerrar el recurso.
utiliza un Buffer para leer / escribir datos. Un búfer es un contenedor de tamaño fijo donde
Channel
podemos escribir un bloque de datos a la vez. Channel es bastante más rápido que la E / S basada
https://riptutorial.com/es/home 77
en flujo.
Para leer los datos de un archivo usando Channel necesitamos los siguientes pasos:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
if (!inputFile.exists()) {
System.out.println("The input file doesn't exit.");
return;
}
try {
FileInputStream fis = new FileInputStream(inputFile);
FileChannel fileChannel = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
https://riptutorial.com/es/home 78
}
}
}
Podemos usar el Channel para copiar el contenido del archivo más rápido. Para hacerlo, podemos
usar el método transferTo() de FileChannel .
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
https://riptutorial.com/es/home 79
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source))) {
byte data;
while ((data = (byte) bis.read()) != -1) {
System.out.println((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Para escribir datos en un archivo usando Channel necesitamos los siguientes pasos:
import java.io.*;
import java.nio.*;
public class FileChannelWrite {
try {
FileOutputStream fos = new FileOutputStream(outputFile);
FileChannel fileChannel = fos.getChannel();
byte[] bytes = text.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(bytes);
fileChannel.write(buffer);
fileChannel.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
Podemos usar la clase PrintStream para escribir un archivo. Tiene varios métodos que le permiten
imprimir cualquier valor de tipo de datos. println() método println() agrega una nueva línea. Una
vez que hayamos terminado de imprimir, tenemos que vaciar el PrintStream .
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.time.LocalDate;
https://riptutorial.com/es/home 80
public class FileWritingDemo {
public static void main(String[] args) {
String destination = "file1.txt";
ps.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
Agregando Directorios
Para crear un nuevo directorio a partir de una instancia de un File , deberá utilizar uno de los dos
métodos siguientes: mkdirs() o mkdir() .
• mkdir() : crea el directorio nombrado por este nombre de ruta abstracto. ( fuente )
• mkdirs() : crea el directorio nombrado por esta ruta de acceso abstracta, incluidos los
directorios primarios necesarios pero no existentes. Tenga en cuenta que si esta operación
falla, es posible que haya logrado crear algunos de los directorios principales necesarios. (
fuente )
// assume that neither "A New Folder" or "A New Folder 2" exist
https://riptutorial.com/es/home 81
multiDir.mkdirs(); // will make the directory
A veces, una biblioteca de terceros mal diseñada escribirá diagnósticos no deseados en las
System.err System.out o System.err . Las soluciones recomendadas para esto serían encontrar una
mejor biblioteca o (en el caso de código abierto) solucionar el problema y contribuir con un parche
para los desarrolladores.
Si las soluciones anteriores no son factibles, entonces debería considerar redirigir los flujos.
En un sistema UNIX, Linux o MacOSX se puede hacer desde el shell usando > redirección. Por
ejemplo:
El primero redirige la salida estándar y el error estándar a "/ dev / null", que desecha todo lo
escrito en esas secuencias. El segundo redirige la salida estándar a "out.log" y el error estándar a
"error.log".
(Para obtener más información sobre la redirección, consulte la documentación del shell de
comandos que está utilizando. Se aplican consejos similares a Windows).
También es posible redirigir las secuencias dentro de una aplicación Java usando System.setOut()
y System.setErr() . Por ejemplo, el siguiente fragmento de código redirige la salida estándar y el
error estándar a 2 archivos de registro:
Si desea deshacerse de la salida por completo, puede crear una secuencia de salida que
"escribe" en un descriptor de archivo no válido. Esto es funcionalmente equivalente a escribir en "/
dev / null" en UNIX.
https://riptutorial.com/es/home 82
de comandos.
La API del sistema de archivos de Java 7 permite leer y agregar entradas desde o hacia un
archivo Zip usando la API del archivo NIO de Java de la misma manera que opera en cualquier
otro sistema de archivos.
FileSystem es un recurso que debe cerrarse correctamente después de su uso, por lo tanto, debe
usarse el bloque try-with-resources.
https://riptutorial.com/es/home 83
Capítulo 14: Archivos JAR Multi-Release
Introducción
Una de las características introducidas en Java 9 es el Jar de lanzamiento múltiple (MRJAR), que
permite agrupar código dirigido a múltiples lanzamientos de Java dentro del mismo archivo Jar. La
característica se especifica en JEP 238 .
Examples
Ejemplo de contenido de un archivo Jar multi-release.
jar root
- A.class
- B.class
- C.class
- D.class
- META-INF
- versions
- 9
- A.class
- B.class
- 10
- A.class
• En JDKs <9, solo las clases en la entrada raíz son visibles para el tiempo de ejecución de
Java.
• En un JDK 9, las clases A y B se cargarán desde el directorio root/META-INF/versions/9 ,
mientras que C y D se cargarán desde la entrada base.
• En un JDK 10, la clase A se cargaría desde el directorio root/META-INF/versions/10 .
El comando jar se puede usar para crear un Jar de varias versiones que contiene dos versiones
de la misma clase compilada para Java 8 y Java 9, aunque con una advertencia que indica que
las clases son idénticas:
https://riptutorial.com/es/home 84
La opción --release 9 le dice a jar que incluya todo lo que sigue (el paquete de demo dentro del
directorio sampleproject-9 ) dentro de una entrada versionada en MRJAR, es decir, bajo root/META-
INF/versions/9 . El resultado son los siguientes contenidos:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
Ahora creamos una clase llamada Main que imprime la URL de SampleClass y la agregamos para
la versión Java 9:
package demo;
import java.net.URL;
La razón es que la herramienta jar impide agregar clases públicas a las entradas versionadas si
no se agregan a las entradas base también. Esto se hace para que MRJAR exponga la misma
API pública para las diferentes versiones de Java. Tenga en cuenta que en tiempo de ejecución,
esta regla no es necesaria. Solo se puede aplicar con herramientas como el jar . En este caso
particular, el propósito de Main es ejecutar código de ejemplo, por lo que simplemente podemos
agregar una copia en la entrada base. Si la clase formara parte de una implementación más
nueva que solo necesitamos para Java 9, se podría hacer no pública.
Para agregar Main a la entrada raíz, primero debemos compilarlo para apuntar a una versión
anterior a Java 9. Esto se puede hacer usando la nueva opción --release de javac :
https://riptutorial.com/es/home 85
La ejecución de la clase Main muestra que SampleClass se carga desde el directorio versionado:
jar root
- demo
- SampleClass.class
- META-INF
- versions
- 9
- demo
- SampleClass.class
package demo;
import java.net.URL;
https://riptutorial.com/es/home 86
Capítulo 15: Arrays
Introducción
Las matrices permiten el almacenamiento y la recuperación de una cantidad arbitraria de valores.
Son análogos a los vectores en matemáticas. Las matrices de matrices son análogas a las
matrices y actúan como matrices multidimensionales. Las matrices pueden almacenar cualquier
tipo de datos: primitivas como int o tipos de referencia como Object .
Sintaxis
• ArrayType[] myArray; // Declarando matrices
• ArrayType myArray[]; // Otra sintaxis válida (menos utilizada y desaconsejada)
• ArrayType[][][] myArray; // Declaración de matrices irregulares multidimensionales
(repetición [] s)
• ArrayType myVar = myArray[index]; // Elemento de acceso (lectura) en el índice
• myArray[index] = value; // Asignar valor al index de posición de la matriz
• ArrayType[] myArray = new ArrayType[arrayLength]; // Sintaxis de inicialización de matriz
• int[] ints = {1, 2, 3}; // Sintaxis de inicialización de la matriz con los valores
proporcionados, la longitud se deduce del número de valores proporcionados: {[valor1 [,
valor2] *]}
• new int[]{4, -5, 6} // Can be used as argument, without a local variable
• int[] ints = new int[3]; // same as {0, 0, 0}
• int[][] ints = {{1, 2}, {3}, null}; // Inicialización de matriz multidimensional. int []
extiende Object (y también lo hace anyType []), por lo que null es un valor válido.
Parámetros
Parámetro Detalles
Tipo de la matriz. Puede ser primitivo ( int , long , byte ) u Objetos ( String ,
ArrayType
MyObject , etc.).
Examples
Creación e inicialización de matrices
https://riptutorial.com/es/home 87
Casos basicos
int[] numbers1 = new int[3]; // Array for 3 int values, default value is 0
int[] numbers2 = { 1, 2, 3 }; // Array literal of 3 int values
int[] numbers3 = new int[] { 1, 2, 3 }; // Array of 3 int values initialized
int[][] numbers4 = { { 1, 2 }, { 3, 4, 5 } }; // Jagged array literal
int[][] numbers5 = new int[5][]; // Jagged array, one dimension 5 long
int[][] numbers6 = new int[5][4]; // Multidimensional array: 5x4
float[] boats = new float[5]; // Array of five 32-bit floating point numbers.
double[] header = new double[] { 4.56, 332.267, 7.0, 0.3367, 10.0 };
// Array of five 64-bit floating point numbers.
String[] theory = new String[] { "a", "b", "c" };
// Array of three strings (reference type).
Object[] dArt = new Object[] { new Object(), "We love Stack Overflow.", new Integer(3) };
// Array of three Objects (reference type).
Para el último ejemplo, tenga en cuenta que los subtipos del tipo de matriz declarada están
permitidos en la matriz.
Las matrices para tipos definidos por el usuario también pueden construirse de manera similar a
los tipos primitivos
Java SE 8
// Streams - JDK 8+
Stream<Integer> toStream = Arrays.stream( initial );
Integer[] fromStream = toStream.toArray( Integer[]::new );
https://riptutorial.com/es/home 88
Introducción
Una matriz es una estructura de datos que contiene un número fijo de valores primitivos o
referencias a instancias de objetos.
Cada elemento de una matriz se denomina elemento, y se accede a cada elemento por su índice
numérico. La longitud de una matriz se establece cuando se crea la matriz:
Debido a que todas las matrices están int indexadas, el tamaño de una matriz debe ser
especificado por una int . El tamaño de la matriz no se puede especificar como un long :
Las matrices utilizan un sistema de índice de base cero , lo que significa que la indexación
comienza en 0 y termina en length - 1 .
Por ejemplo, la siguiente imagen representa una matriz con tamaño 10 . Aquí, el primer elemento
está en el índice 0 y el último elemento está en el índice 9 , en lugar de que el primer elemento
esté en el índice 1 y el último elemento en el índice 10 (consulte la figura a continuación).
https://riptutorial.com/es/home 89
Los accesos a elementos de matrices se realizan en tiempo constante . Eso significa que
acceder al primer elemento de la matriz tiene el mismo costo (en el tiempo) de acceder al
segundo elemento, al tercer elemento y así sucesivamente.
Java ofrece varias formas de definir e inicializar matrices, incluidas las notaciones literales y de
constructor . Al declarar matrices utilizando el new Type[length] constructor new Type[length] ,
cada elemento se inicializará con los siguientes valores predeterminados:
• 0 para tipos numéricos primitivos : byte , short , int , long , float y double .
• '\u0000' (carácter nulo) para el tipo char .
• false para el tipo boolean .
• null para los tipos de referencia .
Al declarar una matriz, [] aparecerá como parte del tipo al comienzo de la declaración (después
del nombre del tipo), o como parte del declarador para una variable en particular (después del
nombre de la variable), o ambos:
int array5[]; /*
equivalent to */ int[] array5;
int a, b[], c[][]; /*
equivalent to */ int a; int[] b; int[][] c;
int[] a, b[]; /*
equivalent to */ int[] a; int[][] b;
int a, []b, c[][]; /*
Compilation Error, because [] is not part of the type at beginning
of the declaration, rather it is before 'b'. */
// The same rules apply when declaring a method that returns an array:
int foo()[] { ... } /* equivalent to */ int[] foo() { ... }
En el siguiente ejemplo, ambas declaraciones son correctas y pueden compilarse y ejecutarse sin
ningún problema. Sin embargo, tanto la Convención de codificación de Java como la Guía de
estilo de Google Java desalientan el formulario entre corchetes después del nombre de la
variable: los corchetes identifican el tipo de matriz y deben aparecer con la designación de tipo .
Lo mismo se debe utilizar para las firmas de retorno de método.
https://riptutorial.com/es/home 90
float array[]; /* and */ int foo()[] { ... } /* are discouraged */
float[] array; /* and */ int[] foo() { ... } /* are encouraged */
El tipo desalentado está pensado para adaptarse a los usuarios de C en transición , que están
familiarizados con la sintaxis de C que tiene los corchetes después del nombre de la variable.
Sin embargo, como se trata de una matriz vacía, no se pueden leer ni asignar elementos de ella:
Estas matrices vacías suelen ser útiles como valores de retorno, por lo que el código de llamada
solo tiene que preocuparse de tratar con una matriz, en lugar de un valor null potencial que
puede llevar a una NullPointerException .
El tamaño de la matriz se puede determinar utilizando un campo final público llamado length :
Creará dos matrices int tres longitudes: a[0] y a[1] . Esto es muy similar a la inicialización clásica
de estilo C de matrices multidimensionales rectangulares.
https://riptutorial.com/es/home 91
A diferencia de C , donde solo se admiten matrices multidimensionales rectangulares, las
matrices internas no tienen que ser de la misma longitud, ni siquiera definidas:
Aquí, a[0] es una matriz int una longitud, mientras que a[1] es una matriz int dos longitudes y
a[2] es null . Las matrices de este tipo se denominan matrices irregulares o matrices irregulares ,
es decir, son matrices de matrices. Las matrices multidimensionales en Java se implementan
como matrices de matrices, es decir, array[i][j][k] es equivalente a ((array[i])[j])[k] . A
diferencia de C # , la array[i,j] sintaxis array[i,j] no es compatible con Java.
Vivir en Ideone
Además de los String literales y primitivas mostradas anteriormente, la sintaxis de acceso directo
https://riptutorial.com/es/home 92
para array de inicialización también trabaja con canónicas Object tipos:
Debido a que las matrices son covariantes, una matriz de tipo de referencia se puede inicializar
como una matriz de una subclase, aunque se ArrayStoreException una ArrayStoreException si
intenta establecer un elemento en algo diferente a una String :
La sintaxis de acceso directo no se puede usar para esto porque la sintaxis de acceso directo
tendría un tipo implícito de Object[] .
Una matriz se puede inicializar con cero elementos utilizando String[] emptyArray = new String[0]
. Por ejemplo, una matriz con una longitud cero como esta se usa para crear una Array partir de
una Collection cuando el método necesita el tipo de tiempo de ejecución de un objeto.
Tanto en los tipos primitivos como en los de referencia, una inicialización de matriz vacía (por
ejemplo, String[] array8 = new String[3] ) inicializará la matriz con el valor predeterminado para
cada tipo de datos .
public MyGenericClass() {
a = new T[5]; // Compile time error: generic array creation
}
}
En su lugar, se pueden crear utilizando uno de los siguientes métodos: (tenga en cuenta que
estos generarán advertencias sin marcar)
Este es el método más simple, pero como la matriz subyacente aún es del tipo Object[] ,
este método no proporciona seguridad de tipo. Por lo tanto, este método de crear una matriz
se usa mejor solo dentro de la clase genérica, no se expone públicamente.
https://riptutorial.com/es/home 93
public MyGenericClass(Class<T> clazz) {
a = (T[]) Array.newInstance(clazz, 5);
}
Arrays.fill() se puede usar para llenar una matriz con el mismo valor después de la
inicialización:
Vivir en Ideone
fill() también puede asignar un valor a cada elemento del rango especificado de la matriz:
Vivir en Ideone
Java SE 8
El siguiente ejemplo crea una matriz de enteros y establece todos sus elementos en su valor de
índice respectivo:
Vivir en Ideone
Sin embargo, es posible crear una nueva matriz y asignarla a la variable que se utiliza para hacer
referencia a la antigua matriz. Si bien esto hace que la matriz referenciada por esa variable se
reinicialice, el contenido de la variable es una matriz completamente nueva. Para hacer esto, el
new operador se puede usar con un inicializador de matriz y asignarse a la variable de matriz:
Vivir en Ideone
https://riptutorial.com/es/home 95
• Object[] toArray()
Java SE 5
Java SE 5
// The array does not need to be created up front with the correct size.
// Only the array type matters. (If the size is wrong, a new array will
// be created with the same type.)
String[] stringArray = set.toArray(new String[0]);
La diferencia entre ellos es más que tener resultados tipificados frente a los no tipificados. Su
rendimiento también puede diferir (para más detalles, lea esta sección de análisis de rendimiento
):
Java SE 8
A partir de Java SE 8+, donde se introdujo el concepto de Stream , es posible utilizar el Stream
producido por la colección para crear una nueva matriz utilizando el método Stream.toArray .
Ejemplos tomados de dos respuestas ( 1 , 2 ) a Convertir 'ArrayList a' String [] 'en Java en
desbordamiento de pila.
https://riptutorial.com/es/home 96
Arrays a una cadena
Java SE 5
Desde Java 1.5, puede obtener una representación en String del contenido de la matriz
especificada sin iterar sobre todos sus elementos. Simplemente use Arrays.toString(Object[]) o
Arrays.deepToString(Object[]) para arreglos multidimensionales:
int[][] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
System.out.println(Arrays.deepToString(arr)); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Si no existe una toString() anulada para la clase, se utilizará la toString() de Object heredada.
Por lo general, la salida no es muy útil, por ejemplo:
El método Arrays.asList() se puede usar para devolver una List tamaño fijo que contiene los
elementos de la matriz dada. La List resultante será del mismo tipo de parámetro que el tipo base
de la matriz.
Nota : esta lista está respaldada por ( una vista de) la matriz original, lo que significa que
https://riptutorial.com/es/home 97
cualquier cambio en la lista cambiará la matriz y viceversa. Sin embargo, los cambios en la lista
que cambiarían su tamaño (y por lo tanto la longitud de la matriz) generarán una excepción.
Para crear una copia de la lista, use el constructor de java.util.ArrayList tomando una Collection
como un argumento:
Java SE 5
Java SE 7
En Java SE 7 y versiones posteriores, se pueden usar un par de corchetes angulares <> (conjunto
vacío de argumentos de tipo), lo que se denomina Diamante . El compilador puede determinar los
argumentos de tipo del contexto. Esto significa que la información de tipo se puede omitir al llamar
al constructor de ArrayList y se deducirá automáticamente durante la compilación. Esto se
denomina Inferencia de tipos, que forma parte de Java Generics .
// Using Arrays.asList()
// Using ArrayList.addAll()
// Using Collections.addAll()
Un punto que vale la pena mencionar sobre el Diamante es que no se puede usar con Clases
Anónimas .
Java SE 8
// Using Streams
https://riptutorial.com/es/home 98
• Este método devuelve List , que es una instancia de Arrays$ArrayList (clase interna estática
de Arrays ) y no java.util.ArrayList . La List resultante es de tamaño fijo. Eso significa que
agregar o quitar elementos no es compatible y emitirá una UnsupportedOperationException :
• Se puede crear una nueva List pasando una List respaldada por una matriz al constructor
de una Nueva List . Esto crea una nueva copia de los datos, que tiene un tamaño variable y
que no está respaldado por la matriz original:
• Llamar a <T> List<T> asList(T... a) en una matriz primitiva, como int[] , producirá una
List<int[]> cuyo único elemento es la matriz primitiva de origen en lugar de los elementos
reales de la matriz de origen.
El motivo de este comportamiento es que los tipos primitivos no pueden utilizarse en lugar
de los parámetros de tipo genérico, por lo que la matriz primitiva completa reemplaza el
parámetro de tipo genérico en este caso. Para convertir una matriz primitiva en una List , en
primer lugar, convierta la matriz primitiva en una matriz del tipo de envoltura correspondiente
(es decir, llame a Arrays.asList en un Integer[] lugar de a int[] ).
Ver demostración
Integer[] arr = {1, 2, 3}; // object array of Integer (wrapper for int)
System.out.println(Arrays.asList(arr).contains(1));
Ver demostración
System.out.println(Arrays.asList(1,2,3).contains(1));
Ver demostración
Es posible definir una matriz con más de una dimensión. En lugar de acceder al proporcionar un
índice único, se accede a una matriz multidimensional especificando un índice para cada
dimensión.
https://riptutorial.com/es/home 99
La declaración de matriz multidimensional se puede hacer agregando [] para cada dimensión a
una decoración de matriz regular. Por ejemplo, para hacer una matriz int bidimensional, agregue
otro conjunto de corchetes a la declaración, como int[][] . Esto continúa para matrices
tridimensionales ( int[][][] ) y así sucesivamente.
Para definir una matriz bidimensional con tres filas y tres columnas:
int rows = 3;
int columns = 3;
int[][] table = new int[rows][columns];
La matriz se puede indexar y asignarle valores con esta construcción. Tenga en cuenta que los
valores no asignados son los valores predeterminados para el tipo de una matriz, en este caso 0
para int .
table[0][0] = 0;
table[0][1] = 1;
table[0][2] = 2;
También es posible crear una instancia de una dimensión a la vez, e incluso hacer matrices no
rectangulares. Estos se conocen más comúnmente como matrices dentadas .
Es importante tener en cuenta que aunque es posible definir cualquier dimensión de la matriz
dentada, se debe definir su nivel anterior.
// valid
String[][] employeeGraph = new String[30][];
// invalid
int[][] unshapenMatrix = new int[][10];
// also invalid
int[][][] misshapenGrid = new int[100][][10];
https://riptutorial.com/es/home 100
Fuente de la imagen: http://math.hws.edu/eck/cs124/javanotes3/c8/s5.html
Las matrices multidimensionales y matrices irregulares también se pueden inicializar con una
expresión literal. Lo siguiente declara y llena una matriz int 2x3:
int[][] table = {
{1, 2, 3},
{4, 5, 6}
};
Nota : los subarreglos irregulares también pueden ser null . Por ejemplo, el siguiente código
declara y llena una matriz int bidimensional cuyo primer subarreglo es null , el segundo
subarreglo es de longitud cero, el tercer subarreglo es de una longitud y el último subarreglo es
una matriz de dos longitudes:
int[][] table = {
null,
{},
{1},
{1,2}
};
Para matrices multidimensionales es posible extraer matrices de dimensión de nivel inferior por
sus índices:
ArrayIndexOutOfBoundsException
https://riptutorial.com/es/home 101
La ArrayIndexOutOfBoundsException produce cuando se accede a un índice no existente de una
matriz.
Las matrices están indexadas en base a cero, por lo que el índice del primer elemento es 0 y el
índice del último elemento es la capacidad de la matriz menos 1 (es decir, array.length - 1 ).
Por lo tanto, cualquier solicitud de un elemento de matriz por el índice i tiene que satisfacer la
condición 0 <= i < array.length , de lo contrario se ArrayIndexOutOfBoundsException la
ArrayIndexOutOfBoundsException .
Salida:
Tenga en cuenta que el índice ilegal al que se accede también se incluye en la excepción ( 2 en el
ejemplo); esta información podría ser útil para encontrar la causa de la excepción.
Para evitar esto, simplemente verifique que el índice esté dentro de los límites de la matriz:
int index = 2;
if (index >= 0 && index < people.length) {
System.out.println(people[index]);
}
Las matrices son objetos que proporcionan espacio para almacenar hasta su tamaño de
elementos del tipo especificado. El tamaño de una matriz no se puede modificar después de crear
la matriz.
https://riptutorial.com/es/home 102
int len4 = arr4.length; // 7
El campo de length en una matriz almacena el tamaño de una matriz. Es un campo final y no
puede ser modificado.
Este código muestra la diferencia entre la length de una matriz y la cantidad de objetos que
almacena una matriz.
Resultado:
int a[] = { 1, 2, 3 };
int b[] = { 1, 2, 3 };
https://riptutorial.com/es/home 103
Object[] aObject = { a }; // aObject contains one element
Object[] bObject = { b }; // bObject contains one element
Debido a que los conjuntos y mapas utilizan equals() y hashCode() , los arreglos generalmente no
son útiles como elementos de conjunto o claves de mapa. hashCode() en una clase auxiliar que
implemente equals() y hashCode() en términos de los elementos de la matriz, o hashCode() a
instancias de List y almacene las listas.
Java SE 8
Puede iterar sobre matrices usando un bucle mejorado para (también conocido como foreach) o
usando índices de matrices:
https://riptutorial.com/es/home 104
Java SE 5
Vale la pena señalar aquí que no hay una forma directa de usar un iterador en un Array, pero a
través de la biblioteca de Arrays se puede convertir fácilmente en una lista para obtener un objeto
Iterable .
Para matrices primitivas (usando java 8) use flujos (específicamente en este ejemplo -
Arrays.stream -> IntStream ):
Si no puede usar secuencias (no java 8), puede elegir usar la biblioteca de guayabas de google:
En arreglos bidimensionales o más, ambas técnicas pueden usarse de una manera un poco más
compleja.
Ejemplo:
Java SE 5
Es imposible establecer un Array en un valor no uniforme sin usar un bucle basado en índices.
https://riptutorial.com/es/home 105
Por supuesto, también puede usar bucles while o do-while while cuando se iteran utilizando
índices.
Una nota de precaución: cuando utilice índices de matriz, asegúrese de que el índice esté entre
0 y array.length - 1 (ambos inclusive). No haga suposiciones de código rígido en la longitud de la
matriz, de lo contrario podría romper su código si la longitud de la matriz cambia pero sus valores
codificados no lo hacen.
Ejemplo:
// DON'T DO THIS :
for (int i = 0; i < 4; i++) {
numbers[i] += 1;
}
}
También es mejor si no usa cálculos sofisticados para obtener el índice, pero si lo usa para iterar
y si necesita valores diferentes, calcúlelos.
Ejemplo:
// DON'T DO THIS :
int doubleLength = array.length * 2;
for (int i = 0; i < doubleLength; i += 2) {
array[i / 2] = i;
}
}
Iterar sobre una matriz temporal en lugar de repetir el código puede hacer que su código sea más
limpio. Se puede utilizar donde se realiza la misma operación en múltiples variables.
https://riptutorial.com/es/home 106
// we want to print out all of these
String name = "Margaret";
int eyeCount = 16;
double height = 50.2;
int legs = 9;
int arms = 5;
// copy-paste approach:
System.out.println(name);
System.out.println(eyeCount);
System.out.println(height);
System.out.println(legs);
System.out.println(arms);
Tenga en cuenta que este código no debe usarse en secciones críticas para el rendimiento, ya
que se crea una matriz cada vez que se ingresa al bucle, y las variables primitivas se copiarán en
la matriz y, por lo tanto, no se podrán modificar.
Copiando matrices
en bucle
int[] a = { 4, 1, 3, 2 };
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
b[i] = a[i];
}
Tenga en cuenta que el uso de esta opción con una matriz de objetos en lugar de una matriz
primitiva llenará la copia con referencia al contenido original en lugar de una copia de la misma.
Object.clone ()
Dado que las matrices son Object en Java, puede usar Object.clone() .
int[] a = { 4, 1, 3, 2 };
int[] b = a.clone(); // [4, 1, 3, 2]
Tenga en cuenta que el método Object.clone para una matriz realiza una copia superficial , es
https://riptutorial.com/es/home 107
decir, devuelve una referencia a una nueva matriz que hace referencia a los mismos elementos
que la matriz de origen.
Arrays.copyOf ()
java.util.Arrays proporciona una manera fácil de realizar la copia de una matriz a otra. Aquí está
el uso básico:
Tenga en cuenta que Arrays.copyOf también proporciona una sobrecarga que le permite cambiar
el tipo de la matriz:
System.arraycopy ()
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int
length) Copia una matriz de la matriz de origen especificada, comenzando en la
posición especificada, a la posición especificada de la matriz de destino.
int[] a = { 4, 1, 3, 2 };
int[] b = new int[a.length];
System.arraycopy(a, 0, b, 0, a.length); // [4, 1, 3, 2]
Arrays.copyOfRange ()
Utilizado principalmente para copiar una parte de una matriz, también puede usarla para copiar
una matriz completa a otra como se muestra a continuación
int[] a = { 4, 1, 3, 2 };
int[] b = Arrays.copyOfRange(a, 0, a.length); // [4, 1, 3, 2]
Matrices de fundición
Las matrices son objetos, pero su tipo está definido por el tipo de los objetos contenidos. Por lo
tanto, uno no puede simplemente lanzar A[] a T[] , pero cada miembro A de A[] específico debe
ser lanzado a un objeto T Ejemplo genérico:
https://riptutorial.com/es/home 108
public static <T, A> T[] castArray(T[] target, A[] array) {
for (int i = 0; i < array.length; i++) {
target[i] = (T) array[i];
}
return target;
}
Usando ArrayList
Puede convertir la matriz en una java.util.List , eliminar el elemento y volver a convertir la lista
en una matriz de la siguiente manera:
// Creates a new array with the same size as the list and copies the list
// elements to it.
array = list.toArray(new String[list.size()]);
Usando System.arraycopy
System.arraycopy()se puede usar para hacer una copia de la matriz original y eliminar el elemento
que desee. A continuación un ejemplo:
https://riptutorial.com/es/home 109
// Copy the elements at the right of the index.
System.arraycopy(array, index + 1, result, index, array.length - index - 1);
System.out.println(Arrays.toString(result)); //[1, 3, 4]
Array Covariance
Las matrices de objetos son covariantes, lo que significa que así como Integer es una subclase
de Number , Integer[] es una subclase de Number[] . Esto puede parecer intuitivo, pero puede
resultar en un comportamiento sorprendente:
Aunque Integer[] es una subclase de Number[] , solo puede contener Integer s, y al intentar
asignar un elemento Long se genera una excepción de tiempo de ejecución.
Tenga en cuenta que este comportamiento es exclusivo de las matrices y que se puede evitar
utilizando una List genérica en su lugar:
No es necesario que todos los elementos de la matriz compartan el mismo tipo, siempre que sean
una subclase del tipo de la matriz:
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
I[] array10 = new I[] { new A(), new B(), new C() }; // Create an array with new
// operator and array initializer.
https://riptutorial.com/es/home 110
I[] array11 = { new A(), new B(), new C() }; // Shortcut syntax with array
// initializer.
I[] array13 = new A[] { new A(), new A() }; // Works because A implements I.
Object[] array14 = new Object[] { "Hello, World!", 3.14159, 42 }; // Create an array with
// new operator and array initializer.
La respuesta simple es que no puedes hacer esto. Una vez que se ha creado una matriz, su
tamaño no se puede cambiar. En cambio, una matriz solo puede "redimensionarse" creando una
nueva matriz con el tamaño apropiado y copiando los elementos de la matriz existente a la nueva.
Supongamos (por ejemplo) que es necesario agregar un nuevo elemento a la matriz listOfCities
definida como se listOfCities anteriormente. Para hacer esto, necesitarás:
Hay varias formas de hacer lo anterior. Antes de Java 6, la forma más concisa era:
Desde Java 6 en adelante, los métodos Arrays.copyOf y Arrays.copyOfRange pueden hacer esto de
manera más simple:
Para otras formas de copiar una matriz, consulte el siguiente ejemplo. Tenga en cuenta que
necesita una copia de matriz con una longitud diferente a la original al cambiar el tamaño.
• Copiando matrices
https://riptutorial.com/es/home 111
Hay dos inconvenientes principales con el cambio de tamaño de una matriz como se describe
anteriormente:
• Es ineficiente. Hacer una matriz más grande (o más pequeña) implica copiar muchos o
todos los elementos de la matriz existente, y asignar un nuevo objeto de matriz. Cuanto
mayor sea la matriz, más caro se vuelve.
• Debe poder actualizar cualquier variable "viva" que contenga referencias a la matriz anterior.
Una alternativa es crear la matriz con un tamaño suficientemente grande para comenzar. Esto
solo es viable si puede determinar ese tamaño con precisión antes de asignar la matriz . Si no
puede hacer eso, entonces surge nuevamente el problema de cambiar el tamaño de la matriz.
La otra alternativa es utilizar una clase de estructura de datos proporcionada por la biblioteca de
clases Java SE o una biblioteca de terceros. Por ejemplo, el marco de "colecciones" de Java SE
proporciona varias implementaciones de las API de List , Set y Map con diferentes propiedades de
tiempo de ejecución. La clase ArrayList es la más cercana a las características de rendimiento de
una matriz simple (p. Ej., Búsqueda O (N), obtención y configuración O (1), inserción y eliminación
aleatoria O (N) al tiempo que proporciona un cambio de tamaño más eficiente sin el problema de
actualización de referencia.
Hay muchas maneras de encontrar la ubicación de un valor en una matriz. Los siguientes
fragmentos de ejemplo suponen que la matriz es una de las siguientes:
Además, cada uno establece el index o el index index2 en el índice del elemento requerido, o -1 si
el elemento no está presente.
https://riptutorial.com/es/home 112
Usando una Stream
Java SE 8
Nota: Usar una búsqueda lineal directa es más eficiente que envolver en una lista.
Java SE 8
https://riptutorial.com/es/home 113
}
Ordenando matrices
import java.util.Arrays;
String no es un dato numérico, define su propio orden, que se denomina orden lexicográfico,
también conocido como orden alfabético. Cuando ordena una matriz de String usando el método
sort() , la matriz se ordena en el orden natural definido por la interfaz comparable, como se
muestra a continuación:
Orden creciente
Salida:
Orden decreciente
Salida:
String array after sorting in descending order : [Steve, Shane, John, Ben, Adam]
https://riptutorial.com/es/home 114
Para ordenar una matriz de objetos, todos los elementos deben implementar una interfaz
Comparable o Comparator para definir el orden de la clasificación.
Podemos usar cualquiera de los métodos de sort(Object[]) para ordenar una matriz de objetos
en su orden natural, pero debe asegurarse de que todos los elementos de la matriz deben
implementar Comparable .
Además, también deben ser mutuamente comparables, por ejemplo, e1.compareTo(e2) no debe
lanzar una ClassCastException para ningún elemento e1 y e2 en la matriz. Alternativamente, puede
ordenar una matriz de objetos en orden personalizado usando el método de sort(T[], Comparator)
como se muestra en el siguiente ejemplo.
Arrays.sort(courses);
System.out.println("Object array after sorting in natural order : " +
Arrays.toString(courses));
Salida:
Object array before sorting : [#101 Java@200 , #201 Ruby@300 , #301 Python@400 , #401
Scala@500 ]
Object array after sorting in natural order : [#101 Java@200 , #201 Ruby@300 , #301 Python@400
, #401 Scala@500 ]
Object array after sorting by price : [#101 Java@200 , #201 Ruby@300 , #301 Python@400 , #401
Scala@500 ]
Object array after sorting by name : [#101 Java@200 , #301 Python@400 , #201 Ruby@300 , #401
Scala@500 ]
Java SE 8
https://riptutorial.com/es/home 115
Con versiones inferiores, puede ser iterando la matriz primitiva y copiándola explícitamente a la
matriz en caja:
Java SE 8
De manera similar, una matriz en caja se puede convertir en una matriz de su contraparte
primitiva:
Java SE 8
Java SE 8
https://riptutorial.com/es/home 116
Capítulo 16: Audio
Observaciones
En lugar de usar el Clip muestra javax.sound.sampled, también puede usar el AudioClip que es de
la API del applet. Sin embargo, se recomienda usar Clip ya que AudioClip es más antiguo y
presenta funcionalidades limitadas.
Examples
Reproducir un archivo de audio en bucle
Importaciones necesarias:
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
Los archivos MIDI se pueden reproducir utilizando varias clases del paquete javax.sound.midi . Un
Sequencer realiza la reproducción del archivo MIDI, y muchos de sus métodos pueden usarse para
configurar controles de reproducción como el conteo de bucles, el tempo, el silenciamiento de
pistas y otros.
import java.io.File;
import java.io.IOException;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
https://riptutorial.com/es/home 117
Sequencer sequencer = MidiSystem.getSequencer(); // Get the default Sequencer
if (sequencer==null) {
System.err.println("Sequencer device not supported");
return;
}
sequencer.open(); // Open device
// Create sequence, the File must contain MIDI file data.
Sequence sequence = MidiSystem.getSequence(new File(args[0]));
sequencer.setSequence(sequence); // load it into sequencer
sequencer.start(); // start the playback
} catch (MidiUnavailableException | InvalidMidiDataException | IOException ex) {
ex.printStackTrace();
}
}
}
Se puede configurar un secuenciador para silenciar una o más de las pistas de la secuencia
durante la reproducción, por lo que ninguno de los instrumentos en esos juegos especificados. El
siguiente ejemplo configura la primera pista en la secuencia a silenciar:
import javax.sound.midi.Track;
// ...
sequencer.setLoopCount(3);
sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
El secuenciador no siempre tiene que reproducir la secuencia desde el principio, ni tiene que
reproducir la secuencia hasta el final. Puede comenzar y terminar en cualquier punto
especificando la marca en la secuencia para comenzar y terminar en. También es posible
especificar manualmente qué tic en la secuencia debe jugar el secuenciador desde:
sequencer.setLoopStartPoint(512);
sequencer.setLoopEndPoint(32768);
sequencer.setTickPosition(8192);
Los secuenciadores también pueden reproducir un archivo MIDI a un determinado tempo, que
puede controlarse especificando el tempo en tiempos por minuto (BPM) o microsegundos por
cuarto de nota (MPQ). El factor en el que se reproduce la secuencia también se puede ajustar.
sequencer.setTempoInBPM(1250f);
sequencer.setTempoInMPQ(4750f);
https://riptutorial.com/es/home 118
sequencer.setTempoFactor(1.5f);
sequencer.close();
También puedes usar el metal casi al desnudo al producir sonido con java. Este código escribirá
datos binarios sin procesar en el búfer de audio del sistema operativo para generar sonido. Es
extremadamente importante comprender las limitaciones y los cálculos necesarios para generar
un sonido como este. Dado que la reproducción es básicamente instantánea, los cálculos deben
realizarse casi en tiempo real.
Como tal, este método es inutilizable para un muestreo de sonido más complicado. Para tales
fines, el uso de herramientas especializadas es el mejor enfoque.
El siguiente método genera y emite directamente una onda rectangular de una frecuencia dada en
un volumen dado para una duración determinada.
Para una forma más diferenciada de generar diferentes ondas de sonido, son necesarios cálculos
sinusales y posiblemente tamaños de muestra más grandes. Esto da como resultado un código
significativamente más complejo y, por consiguiente, se omite aquí.
https://riptutorial.com/es/home 119
Salida de audio básica
El Hola Audio! de Java que reproduce un archivo de sonido desde el almacenamiento local o de
Internet tiene el siguiente aspecto. Funciona para archivos .wav sin comprimir y no debe usarse
para reproducir archivos mp3 o comprimidos.
import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;
// Constructor
public SoundClipTest() {
try {
// Open an audio input stream.
File soundFile = new File("/usr/share/sounds/alsa/Front_Center.wav"); //you could
also get the sound file with an URL
AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundFile);
AudioFormat format = audioIn.getFormat();
// Get a sound clip resource.
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip clip = (Clip)AudioSystem.getLine(info);
// Open audio clip and load samples from the audio input stream.
clip.open(audioIn);
clip.start();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
https://riptutorial.com/es/home 120
Capítulo 17: Autoboxing
Introducción
Autoboxing es la conversión automática que realiza el compilador de Java entre los tipos
primitivos y sus correspondientes clases de envoltorios de objetos. Ejemplo, conversión de int ->
Entero, doble -> Doble ... Si la conversión es a la inversa, esto se llama unboxing. Por lo general,
esto se usa en Colecciones que no pueden contener más que Objetos, donde se necesitan tipos
primitivos de boxeo antes de configurarlos en la colección.
Observaciones
Autoboxing puede tener problemas de rendimiento cuando se utiliza con frecuencia en su código.
• http://docs.oracle.com/javase/1.5.0/docs/guide/language/autoboxing.html
• ¿El autoempaquetamiento integral y el boxeo automático dan problemas de rendimiento?
Examples
Usando int y entero indistintamente
A medida que usa tipos genéricos con clases de utilidad, a menudo puede encontrar que los tipos
de números no son muy útiles cuando se especifican como tipos de objetos, ya que no son
iguales a sus contrapartes primitivas.
Java SE 7
Afortunadamente, las expresiones que evalúan a int pueden usarse en lugar de un Integer
cuando sea necesario.
ints.add(Integer.valueOf(i));
Y retiene las propiedades de Integer#valueOf , como tener los mismos objetos de Integer
almacenados en caché por la JVM cuando está dentro del rango de almacenamiento en caché de
números.
https://riptutorial.com/es/home 121
Esto también se aplica a:
• byte y Byte
• short y Short
• float y Float
• double y Double
• long y Long
• char y Character
• boolean y Boolean
Se debe tener cuidado, sin embargo, en situaciones ambiguas. Considere el siguiente código:
La interfaz java.util.List contiene tanto un remove(int index) (Método de interfaz de List ) como
un remove(Object o) (método heredado de java.util.Collection ). En este caso no se lleva a cabo
ningún boxeo y se llama a la remove(int index) .
Un ejemplo más del extraño comportamiento del código Java causado por los enteros automoxing
con valores en el rango de -128 a 127 :
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b); // true
System.out.println(c <= d); // true
System.out.println(c >= d); // true
System.out.println(c == d); // false
Esto sucede porque el operador >= llama implícitamente a intValue() que devuelve int mientras
que == compara las referencias , no los valores de int .
De forma predeterminada, Java almacena en caché los valores en el rango [-128, 127] , por lo
que el operador == funciona porque los Integers en este rango hacen referencia a los mismos
objetos si sus valores son los mismos. El valor máximo del rango -XX:AutoBoxCacheMax se puede
definir con la -XX:AutoBoxCacheMax JVM. Por lo tanto, si ejecuta el programa con -
XX:AutoBoxCacheMax=1000 , el siguiente código se imprimirá true :
Integer a = 1000;
Integer b = 1000;
System.out.println(a == b); // true
https://riptutorial.com/es/home 122
Boolean a = Boolean.TRUE;
if (a) { // a gets converted to boolean
System.out.println("It works!");
}
Eso funciona para while , do while y la condición en las declaraciones for también.
Confíe en el autoboxing y el auto-boxeo con cuidado, asegúrese de que los valores unboxed no
tengan valores null en el tiempo de ejecución.
normalmente consumirá una cantidad sustancial de memoria (alrededor de 60kb para 6k de datos
reales).
Además, los enteros en caja generalmente requieren viajes de ida y vuelta adicionales en la
memoria, y por lo tanto hacen que los cachés de CPU sean menos efectivos. En el ejemplo
anterior, la memoria a la que se accede se extiende a cinco ubicaciones diferentes que pueden
estar en regiones completamente diferentes de la memoria: 1. el objeto HashMap , 2. el objeto de
Entry[] table del mapa, 3. el objeto Entry , 4. el objeto objeto key entradas (boxeo de la clave
primitiva), 5. objeto de value entradas (boxeo del valor primitivo).
class Example {
int primitive; // Stored directly in the class `Example`
https://riptutorial.com/es/home 123
Integer boxed; // Reference to another memory location
}
La lectura en boxed requiere dos accesos de memoria, accediendo solo a uno primitive .
int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
sumOfSquares += square.get(i);
}
es equivalente a:
int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
sumOfSquares += square.get(Integer.valueOf(i)).intValue();
}
Para reducir esta sobrecarga, varias bibliotecas ofrecen colecciones optimizadas para tipos
primitivos que no requieren boxeo. Además de evitar la sobrecarga del boxeo, esta colección
requerirá aproximadamente 4 veces menos memoria por entrada. Si bien Java Hotspot puede
optimizar el autoboxing al trabajar con objetos en la pila en lugar del montón, no es posible
optimizar la sobrecarga de memoria y la indirección de la memoria resultante.
Las transmisiones Java 8 también tienen interfaces optimizadas para tipos de datos primitivos,
como IntStream que no requieren boxeo.
Nota: un tiempo de ejecución de Java típico mantiene un caché simple de Integer y otro objeto de
envoltorio primitivo que utilizan los métodos de fábrica valueOf , y mediante autofijación. Para
Integer , el rango predeterminado de este caché es de -128 a +127. Algunas JVM proporcionan
una opción de línea de comandos JVM para cambiar el tamaño / rango de la memoria caché.
Ejemplo:
int i;
Integer j;
void ex_method(Integer i)//Is a valid statement
void ex_method1(int j)//Is a valid statement
https://riptutorial.com/es/home 124
Caso 2: Mientras se pasan valores de retorno:
Cuando un método devuelve una variable de tipo primitivo, entonces se puede pasar un objeto de
la clase envoltura correspondiente como valor de retorno de manera intercambiable y viceversa.
Ejemplo:
int i;
Integer j;
int ex_method()
{...
return j;}//Is a valid statement
Integer ex_method1()
{...
return i;//Is a valid statement
}
int i=5;
Integer j=new Integer(7);
int k=i+j;//Is a valid statement
Integer m=i+j;//Is also a valid statement
Ejemplo:
En el ejemplo anterior, el valor del objeto no está asignado ni inicializado y, por lo tanto, en tiempo
de ejecución, el programa ejecutará una excepción de puntero nulo. Por lo tanto, el valor del
objeto nunca debe dejarse sin inicializar ni asignar.
https://riptutorial.com/es/home 125
Capítulo 18: Banderas JVM
Observaciones
Se recomienda encarecidamente que utilice estas opciones solamente:
Examples
-XXaggresivo
-XXaggressive es una colección de configuraciones que hacen que la JVM funcione a alta
velocidad y alcance un estado estable lo antes posible. Para lograr este objetivo, la JVM utiliza
más recursos internos al inicio; sin embargo, requiere una optimización menos adaptable una vez
que se alcanza el objetivo. Le recomendamos que utilice esta opción para aplicaciones de larga
duración que requieren un uso intensivo de la memoria y que funcionan solas.
Uso:
-XXaggressive:<param>
<param> Descripción
-XXallocClearChunks
Esta opción le permite borrar un TLA para referencias y valores en el tiempo de asignación de
TLA y obtener previamente el siguiente fragmento. Cuando se declara un entero, una referencia o
cualquier otra cosa, tiene un valor predeterminado de 0 o nulo (según el tipo). En el momento
adecuado, deberá borrar estas referencias y valores para liberar la memoria del montón para que
Java pueda usarla o reutilizarla. Puede hacerlo cuando se asigna el objeto o, al usar esta opción,
cuando solicita un nuevo TLA.
https://riptutorial.com/es/home 126
Uso:
-XXallocClearChunks
-XXallocClearChunks=<true | false>
-XXallocClearChunkSize
Cuando se usa con -XXallocClearChunkSize , esta opción establece el tamaño de los trozos que se
borrarán. Si se utiliza este indicador pero no se especifica ningún valor, el valor predeterminado
es 512 bytes.
Uso:
-XXallocClearChunks -XXallocClearChunkSize=<size>[k|K][m|M][g|G]
-XXcallProfiling
Esta opción permite el uso de perfiles de llamadas para optimizaciones de código. El perfil
registra estadísticas útiles de tiempo de ejecución específicas para la aplicación y puede, en
muchos casos, aumentar el rendimiento porque JVM puede actuar sobre esas estadísticas.
Nota: esta opción es compatible con JRockit JVM R27.3.0 y la versión posterior.
Puede convertirse en predeterminado en futuras versiones.
Uso:
Esta opción está deshabilitada por defecto. Debes habilitarlo para usarlo.
-XXdisableFatSpin
Esta opción deshabilita el código de giro de bloqueo de grasa en Java, permitiendo que los hilos
que bloquean el intento de adquirir un bloqueo de grasa se duerman directamente.
Los objetos en Java se convierten en un bloqueo tan pronto como cualquier hilo entra en un
bloque sincronizado en ese objeto. Todos los bloqueos se mantienen (es decir, permanecen
bloqueados) hasta que se liberan por el hilo de bloqueo. Si el bloqueo no se va a liberar muy
rápido, se puede inflar a un "bloqueo grueso". El "giro" se produce cuando un hilo que quiere un
bloqueo específico comprueba continuamente ese bloqueo para ver si aún está en uso. Bucle
apretado ya que hace el cheque. Girar contra un bloqueo de grasa es generalmente beneficioso,
https://riptutorial.com/es/home 127
aunque, en algunos casos, puede ser costoso y puede afectar el rendimiento. -XXdisableFatSpin
permite desactivar el giro contra un bloqueo grueso y eliminar el impacto potencial de
rendimiento.
Uso:
-XXdisableFatSpin
Esta opción deshabilita los cambios de estrategia del recolector de basura. Esta opción no afecta
a las heurísticas de compactación ni a las de tamaño de vivero. Por defecto, las heurísticas de
recolección de basura están habilitadas.
Uso:
-XXdisableFatSpin
-XXdumpSize
Esta opción hace que se genere un archivo de volcado y le permite especificar el tamaño relativo
de ese archivo (es decir, pequeño, mediano o grande).
Uso:
-XXdumpsize:<size>
<tamaño> Descripción
Hace que se genere un volcado normal en todas las plataformas. Este archivo
normal de volcado incluye toda la memoria excepto el montón java. Este es el valor
predeterminado para JRockit JVM 1.4.2 y versiones posteriores.
Incluye todo lo que está en la memoria, incluido el montón de Java. Esta opción
large
hace que -XXdumpSize sea equivalente a -XXdumpFullState .
-XXexitOnOutOfMemory
Esta opción hace que JRockit JVM salga en la primera aparición de un error de falta de memoria.
https://riptutorial.com/es/home 128
Se puede usar si prefiere reiniciar una instancia de JRockit JVM en lugar de eliminar los errores
de memoria. Ingrese este comando al inicio para forzar a JRockit JVM a salir en la primera vez
que ocurra un error de falta de memoria.
Uso:
-XXexitOnOutOfMemory
https://riptutorial.com/es/home 129
Capítulo 19: BigDecimal
Introducción
La clase BigDecimal proporciona operaciones para aritmética (sumar, restar, multiplicar, dividir),
manipulación de escala, redondeo, comparación, hash y conversión de formato. El BigDecimal
representa números decimales firmados de precisión arbitraria e inmutables. Esta clase se
utilizará en una necesidad de cálculo de alta precisión.
Examples
Los objetos BigDecimal son inmutables.
Si desea calcular con BigDecimal, tiene que usar el valor devuelto porque los objetos BigDecimal
son inmutables:
Comparando BigDecimals
Comúnmente no se debe utilizar la equals método ya que considera dos BigDecimals iguales sólo
si son iguales en valor y también de la escala:
Este ejemplo muestra cómo realizar operaciones matemáticas básicas con BigDecimals.
1.Adición
https://riptutorial.com/es/home 130
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");
//Equivalent to result = a + b
BigDecimal result = a.add(b);
System.out.println(result);
Resultado: 12
2.Subtraction
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");
//Equivalent to result = a - b
BigDecimal result = a.subtract(b);
System.out.println(result);
Resultado: -2
3.Multiplicacion
Al multiplicar dos BigDecimal s, el resultado tendrá una escala igual a la suma de las escalas de
los operandos.
//Equivalent to result = a * b
BigDecimal result = a.multiply(b);
System.out.println(result);
Resultado: 36.89931
Para cambiar la escala del resultado, utilice el método de multiplicación sobrecargada que permite
pasar MathContext , un objeto que describe las reglas para los operadores, en particular la
precisión y el modo de redondeo del resultado. Para obtener más información sobre los modos de
redondeo disponibles, consulte la documentación de Oracle.
//Equivalent to result = a * b
BigDecimal result = a.multiply(b, returnRules);
System.out.println(result);
Resultado: 36.90
https://riptutorial.com/es/home 131
4.Division
La división es un poco más complicada que las otras operaciones aritméticas, por ejemplo,
considere el siguiente ejemplo:
Esto funcionaría perfectamente bien cuando el resultado fuera un decimal de terminación, por
ejemplo, si quisiera dividir 5 por 2, pero para aquellos números que al dividir darían un resultado
no final, obtendríamos una ArithmeticException . En el escenario del mundo real, uno no puede
predecir los valores que se encontrarían durante la división, por lo que necesitamos especificar la
Escala y el Modo de redondeo para la división BigDecimal. Para obtener más información sobre
la escala y el modo de redondeo, consulte la documentación de Oracle .
Resultado: 0.7142857143
//Equivalent to result = a % b
BigDecimal result = a.remainder(b);
System.out.println(result);
Resultado: 5
6. Poder
https://riptutorial.com/es/home 132
BigDecimal a = new BigDecimal("5");
Resultado: 9765625
7.Max
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");
Resultado: 7
8.Min
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");
Resultado: 5
Resultado: 52.3449843776
https://riptutorial.com/es/home 133
System.out.println(result);
Resultado: 5234498.43776
Existen muchas más opciones y una combinación de parámetros para los ejemplos mencionados
anteriormente (por ejemplo, hay 6 variaciones del método de división), este conjunto no es una
lista exhaustiva y cubre algunos ejemplos básicos.
import java.math.BigDecimal;
Para un saldo inicial de 10000.00, después de 1000 operaciones por 1.99, esperamos que el
saldo sea 8010.00. El uso del tipo de coma flotante nos da una respuesta en torno al 8009.77, lo
que es inaceptablemente impreciso en el caso de los cálculos monetarios. Usar BigDecimal nos
https://riptutorial.com/es/home 134
da el resultado adecuado.
BigDecimal.valueOf ()
La clase BigDecimal contiene un caché interno de los números utilizados con frecuencia, por
ejemplo, de 0 a 10. Los métodos BigDecimal.valueOf () se proporcionan con preferencia a los
constructores con parámetros de tipo similar, es decir, en el ejemplo siguiente se prefiere a b.
BigDecimal proporciona propiedades estáticas para los números cero, uno y diez. Es una buena
práctica usar estos en lugar de usar los números reales:
• BigDecimal.ZERO
• BigDecimal.ONE
• BigDecimal.TEN
Al usar las propiedades estáticas, evitas una creación de instancias innecesaria, también tienes
un literal en tu código en lugar de un 'número mágico'.
//Bad example:
BigDecimal bad0 = new BigDecimal(0);
BigDecimal bad1 = new BigDecimal(1);
BigDecimal bad10 = new BigDecimal(10);
//Good Example:
BigDecimal good0 = BigDecimal.ZERO;
BigDecimal good1 = BigDecimal.ONE;
BigDecimal good10 = BigDecimal.TEN;
https://riptutorial.com/es/home 135
Capítulo 20: BigInteger
Introducción
La clase BigInteger se usa para operaciones matemáticas que involucran enteros grandes con
magnitudes demasiado grandes para tipos de datos primitivos. Por ejemplo, 100 factorial es 158
dígitos, mucho más grande de lo que puede representar un long . BigInteger proporciona
análogos a todos los operadores enteros primitivos de Java y todos los métodos relevantes de
java.lang.Math , así como algunas otras operaciones.
Sintaxis
• BigInteger variable_name = new BigInteger ("12345678901234567890"); // un entero
decimal como una cadena
• BigInteger variable_name = new BigInteger
("1010101101010101010100110001100111010110001111100001011010010", 2) // un
entero binario como una cadena
• BigInteger variable_name = new BigInteger ("ab54a98ceb1f0800", 16) // un entero
hexadecimal como una cadena
• BigInteger variable_name = new BigInteger (64, new Random ()); // un generador de
números pseudoaleatorios que suministra 64 bits para construir un entero
• BigInteger variable_name = new BigInteger (new byte [] {0, -85, 84, -87, -116, -21, 31, 10, -
46}); // firmó la representación complementaria de dos de un entero (big endian)
• BigInteger variable_name = new BigInteger (1, nuevo byte [] {- 85, 84, -87, -116, -21, 31, 10,
-46}); // representación de complemento de dos sin signo de un entero positivo (big endian)
Observaciones
BigIntegeres inmutable. Por lo tanto no puedes cambiar su estado. Por ejemplo, lo siguiente no
funcionará ya que la sum no se actualizará debido a la inmutabilidad.
sum = sum.add(BigInteger.valueOf(i));
Java SE 8
https://riptutorial.com/es/home 136
BigInteger puede tener más de 2 mil millones de bits!
Examples
Inicialización
o, para enteros:
que ampliarán el intValue número entero de largo, utilizando la extensión bit de signo para los
valores negativos, por lo que los valores negativos permanecerán negativo.
Java también admite la conversión directa de bytes a una instancia de BigInteger . Actualmente
solo se puede usar la codificación big endian firmada y sin firmar:
Esto generará una instancia de BigInteger con valor -128 ya que el primer bit se interpreta como
el bit de signo.
https://riptutorial.com/es/home 137
BigInteger valueFromUnsignedBytes = new BigInteger(sign, unsignedBytes);
Esto generará una instancia de BigInteger con valor 128, ya que los bytes se interpretan como un
número sin firma y el signo se establece explícitamente en 1, un número positivo.
También hay BigInteger.TWO (valor de "2"), pero no puedes usarlo en tu código porque es private .
Comparando BigIntegers
Puede comparar BigIntegers igual que compara String u otros objetos en Java.
Por ejemplo:
if(one.equals(two)){
System.out.println("Equal");
}
else{
System.out.println("Not Equal");
}
Salida:
Not Equal
Nota:
if (firstBigInteger == secondBigInteger) {
// Only checks for reference equality, not content equality!
}
https://riptutorial.com/es/home 138
También puede comparar su BigInteger con valores constantes como 0,1,10.
por ejemplo:
También puede comparar dos BigIntegers usando el compareTo() , como sigue: compareTo()
devuelve 3 valores.
if(reallyBig.compareTo(reallyBig1) == 0){
//code when both are equal.
}
else if(reallyBig.compareTo(reallyBig1) == 1){
//code when reallyBig is greater than reallyBig1.
}
else if(reallyBig.compareTo(reallyBig1) == -1){
//code when reallyBig is less than reallyBig1.
}
BigInteger se encuentra en un objeto inmutable, por lo que debe asignar los resultados de
cualquier operación matemática a una nueva instancia de BigInteger.
Adición: 10 + 10 = 20
salida: 20
Sustracción: 10 - 9 = 1
salida: 1
https://riptutorial.com/es/home 139
División: 10/5 = 2
salida: 2
División: 17/4 = 4
salida: 4
Multiplicación: 10 * 5 = 50
salida: 50
Potencia: 10 ^ 3 = 1000
salida: 1000
Resto: 10% 6 = 4
salida: 4
https://riptutorial.com/es/home 140
System.out.println(value1.gcd(value2));
Salida: 6
System.out.println(value1.max(value2));
Salida: 11
System.out.println(value1.min(value2));
Salida: 10
BigInteger admite las operaciones lógicas binarias que también están disponibles para los tipos
de Number . Al igual que con todas las operaciones, se implementan llamando a un método.
Binario o
val1.or(val2);
Binario y
val1.and(val2);
Xor binario:
https://riptutorial.com/es/home 141
val1.xor(val2);
Giro a la derecha:
Shift izquierdo:
val1.not();
Salida: 5
NAND (y no): *
val1.andNot(val2);
Salida: 7
La clase BigInteger tiene un constructor dedicado a generar BigIntegers aleatorios, dada una
instancia de java.util.Random y un int que especifica cuántos bits tendrá el BigInteger . Su uso es
bastante simple: cuando se llama al constructor BigInteger(int, Random) siguiente manera:
luego terminarás con un BigInteger cuyo valor está entre 0 (inclusive) y 2 bitCount (exclusivo).
Esto también significa que el new BigInteger(2147483647, sourceOfRandomness) puede devolver todo
BigInteger positivo dado suficiente tiempo.
https://riptutorial.com/es/home 142
¿Cuál será la sourceOfRandomness La sourceOfRandomness depende de usted. Por ejemplo, un new
Random() es suficientemente bueno en la mayoría de los casos:
Si está dispuesto a renunciar a la velocidad para obtener números aleatorios de mayor calidad,
puede usar un new SecureRandom () lugar:
import java.security.SecureRandom;
¡Incluso puede implementar un algoritmo sobre la marcha con una clase anónima! Tenga en
cuenta que el despliegue de su propio algoritmo RNG lo terminará con una aleatoriedad de
baja calidad , por lo que siempre asegúrese de usar un algoritmo que se demuestre que sea
decente a menos que desee que los BigInteger resultantes sean predecibles.
@Override
protected int next(int bits) {
seed = ((22695477 * seed) + 1) & 2147483647; // Values shamelessly stolen from
Wikipedia
return seed;
}
});
https://riptutorial.com/es/home 143
Capítulo 21: ByteBuffer
Introducción
La clase ByteBuffer se introdujo en Java 1.4 para facilitar el trabajo en datos binarios. Es
especialmente adecuado para usar con datos de tipo primitivo. Permite la creación, pero también
la manipulación posterior de un byte[] s en un nivel de abstracción superior
Sintaxis
• byte [] arr = new byte [1000];
• ByteBuffer buffer = ByteBuffer.wrap (arr);
• ByteBuffer buffer = ByteBuffer.allocate (1024);
• ByteBuffer buffer = ByteBuffer.allocateDirect (1024);
• byte b = buffer.get ();
• byte b = buffer.get (10);
• corto s = buffer.getShort (10);
• buffer.put ((byte) 120);
• buffer.putChar ('a');
Examples
Uso básico - Creación de un ByteBuffer
Hay dos formas de crear un ByteBuffer , donde uno puede subdividirse de nuevo.
Esta sería una posibilidad para el código que maneja las interacciones de redes de bajo nivel.
Si no tiene un byte[] ya existente byte[] , puede crear un ByteBuffer sobre una matriz que está
asignada específicamente para el búfer de esta manera:
Si la ruta del código es extremadamente crítica para el rendimiento y necesita acceso directo a
la memoria del sistema , ByteBuffer puede incluso asignar búferes directos utilizando
#allocateDirect()
https://riptutorial.com/es/home 144
Uso básico - Escribir datos en el búfer
Dado un ByteBuffer ejemplo uno puede escribir datos de tipo primitivo a él utilizando relativa y
absoluta put . La sorprendente diferencia es que al poner los datos utilizando el método relativo ,
se realiza un seguimiento del índice en el que se insertan los datos, mientras que el método
absoluto siempre requiere proporcionar un índice para put los datos.
buffer.putInt(0xCAFEBABE).putChar('c').putFloat(0.25).putLong(0xDEADBEEFCAFEBABE);
que es equivalente a:
buffer.putInt(0xCAFEBABE);
buffer.putChar('c');
buffer.putFloat(0.25);
buffer.putLong(0xDEADBEEFCAFEBABE);
Tenga en cuenta que el método que opera en byte s no tiene un nombre especial. Además, tenga
en cuenta que también es válido pasar tanto un ByteBuffer como un byte[] para put . Aparte de
eso, todos los tipos primitivos tienen métodos de put especializados.
Una nota adicional: el índice dado cuando se usa put* absoluto put* siempre se cuenta en byte .
Esta operación asignará 16 bytes de memoria. El contenido de los buffers directos puede residir
fuera del montón de recolección de basura normal.
directBuffer.isDirect(); // true
https://riptutorial.com/es/home 145
UnsupportedOperationException . Por lo tanto, es una buena práctica comprobar si nuestro
ByteBuffer lo tiene (matriz de bytes) antes de intentar acceder a él:
byte[] arrayOfBytes;
if(buffer.hasArray()) {
arrayOfBytes = buffer.array();
}
Otro uso del buffer de bytes directo es interoperar a través de JNI. Como un búfer de bytes directo
no usa un byte[] , sino un bloque de memoria real, es posible acceder a esa memoria
directamente a través de un puntero en el código nativo. Esto puede ahorrarle un poco de
problemas y gastos generales al calcular entre Java y la representación nativa de los datos.
La interfaz JNI define varias funciones para manejar buffers de bytes directos: Soporte NIO .
https://riptutorial.com/es/home 146
Capítulo 22: Calendario y sus subclases
Observaciones
A partir de Java 8, Calendar y sus subclases han sido reemplazados por el paquete java.time y sus
subpaquetes. Deberían ser preferibles, a menos que una API heredada requiera Calendario.
Examples
Creando objetos de calendario
Calendar objetos del Calendar se pueden crear usando getInstance() o usando el constructor
GregorianCalendar .
Es importante tener en cuenta que los meses en el Calendar están basados en cero, lo que
significa que ENERO se representa con un valor int 0. Para proporcionar un mejor código,
siempre use las constantes del Calendar , como el Calendar.JANUARY . ENERO para evitar
malentendidos.
Nota : utilice siempre las constantes del mes: la representación numérica es engañosa , por
ejemplo, Calendar.JANUARY tiene el valor 0
add() y roll() se pueden usar para aumentar / disminuir los campos del Calendar .
El método add() afecta a todos los campos y se comporta de manera efectiva si se agregaran o
restaran fechas reales del calendario
calendar.add(Calendar.MONTH, -6);
La operación anterior elimina seis meses del calendario y nos lleva al 30 de septiembre de 2015.
Para cambiar un campo en particular sin afectar a los otros campos, use roll() .
calendar.roll(Calendar.MONTH, -6);
La operación anterior elimina seis meses del mes actual, por lo que el mes se identifica como
https://riptutorial.com/es/home 147
septiembre. Ningún otro campo ha sido ajustado; El año no ha cambiado con esta operación.
Encontrando AM / PM
Restando calendarios
Para obtener una diferencia entre dos Calendar , use el método getTimeInMillis() :
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c2.set(Calendar.DATE, c2.get(Calendar.DATE) + 1);
https://riptutorial.com/es/home 148
Capítulo 23: Características de Java SE 7
Introducción
En este tema, encontrará un resumen de las nuevas características agregadas al lenguaje de
programación Java en Java SE 7. Hay muchas otras características nuevas en otros campos
como JDBC y Java Virtual Machine (JVM) que no se cubrirán. en este tema.
Observaciones
Mejoras en Java SE 7
Examples
Nuevas características del lenguaje de programación Java SE 7.
• Literales binarios : los tipos integrales (byte, short, int y long) también se pueden expresar
utilizando el sistema de números binarios. Para especificar un literal binario, agregue el
prefijo 0b o 0B al número.
• Cadenas en declaraciones de switch : puede usar un objeto String en la expresión de una
declaración de switch
• La declaración try-with-resources : La declaración try-with-resources es una declaración try
que declara uno o más recursos. Un recurso es como un objeto que debe cerrarse después
de que el programa haya terminado con él. La declaración try-with-resources asegura que
cada recurso se cierre al final de la declaración. Cualquier objeto que implemente
java.lang.AutoCloseable, que incluye todos los objetos que implementan java.io.Closeable,
puede usarse como un recurso.
• Captura de múltiples tipos de excepciones y reingreso de excepciones con la verificación de
tipos mejorada : un solo bloque de captura puede manejar más de un tipo de excepción.
Esta característica puede reducir la duplicación de código y disminuir la tentación de atrapar
una excepción demasiado amplia.
• Subrayados en literales numéricos : cualquier número de guiones bajos (_) puede aparecer
en cualquier lugar entre los dígitos en un literal numérico. Esta función le permite, por
ejemplo, separar grupos de dígitos en literales numéricos, lo que puede mejorar la
legibilidad de su código.
• Inferencia de tipos para la creación de instancias genéricas : puede reemplazar los
argumentos de tipo requeridos para invocar al constructor de una clase genérica con un
conjunto vacío de parámetros de tipo (<>) siempre que el compilador pueda inferir los
argumentos de tipo del contexto. Este par de soportes angulares se llama informalmente el
diamante.
• Advertencias y errores mejorados del compilador cuando se usan parámetros formales no
confiables con métodos de Varargs
Literales binarios
https://riptutorial.com/es/home 149
// An 8-bit 'byte' value:
byte aByte = (byte)0b00100001;
El ejemplo lee la primera línea de un archivo. Utiliza una instancia de BufferedReader para leer
datos del archivo. BufferedReader es un recurso que debe cerrarse una vez que el programa haya
terminado con él:
El siguiente ejemplo muestra otras formas en que puede usar el guión bajo en literales numéricos:
Puede colocar guiones bajos solo entre dígitos; No puedes colocar guiones bajos en los
siguientes lugares:
https://riptutorial.com/es/home 150
• En posiciones donde se espera una cadena de dígitos
Puedes usar
en lugar de
list.addAll(new ArrayList<>());
porque no se puede compilar. Tenga en cuenta que el diamante a menudo funciona en las
llamadas de método; sin embargo, se sugiere que use el diamante principalmente para
declaraciones de variables.
https://riptutorial.com/es/home 151
https://riptutorial.com/es/java/topic/8272/caracteristicas-de-java-se-7
https://riptutorial.com/es/home 152
Capítulo 24: Características de Java SE 8
Introducción
En este tema, encontrará un resumen de las nuevas características agregadas al lenguaje de
programación Java en Java SE 8. Hay muchas otras características nuevas en otros campos,
como JDBC y Java Virtual Machine (JVM) que no se cubrirán en este tema.
Observaciones
Referencia: Mejoras en Java SE 8.
Examples
Nuevas características del lenguaje de programación Java SE 8.
https://riptutorial.com/es/home 153
clase Executable y, por lo tanto, heredan el método Executable.getParameters ) Sin embargo,
los archivos .class no almacenan nombres de parámetros formales de forma
predeterminada. Para almacenar nombres de parámetros formales en un archivo .class
particular, y así habilitar la API de Reflection para recuperar nombres de parámetros
formales, compile el archivo de origen con la opción -parameters del compilador javac.
• Date-time-api - Se agregó una nueva api de tiempo en java.time . Si se usa esto, no es
necesario que designe zona horaria.
https://riptutorial.com/es/home 154
Capítulo 25: Cargadores de clases
Observaciones
Un cargador de clases es una clase cuyo propósito principal es mediar la ubicación y carga de las
clases utilizadas por una aplicación. Un cargador de clases también puede encontrar y cargar
recursos .
Las clases estándar del cargador de clases pueden cargar clases y recursos de directorios en el
sistema de archivos y de archivos JAR y ZIP. También pueden descargar y almacenar en caché
los archivos JAR y ZIP desde un servidor remoto.
Los cargadores de clases normalmente están encadenados, de modo que la JVM intentará cargar
las clases de las bibliotecas de clases estándar con preferencia a las fuentes proporcionadas por
la aplicación. Los cargadores de clases personalizados permiten que el programador altere esto.
También puede hacer cosas como descifrar archivos de bytecode y modificación de bytecode.
Examples
Instalar y usar un cargador de clases
Este ejemplo básico muestra cómo una aplicación puede instanciar un cargador de clases y
usarlo para cargar dinámicamente una clase.
El cargador de clases creado en este ejemplo tendrá el cargador de clases predeterminado como
principal, y primero intentará encontrar cualquier clase en el cargador de clases principal antes de
buscar en "extra.jar". Si la clase solicitada ya se ha cargado, la llamada findClass devolverá la
referencia a la clase cargada anteriormente.
La llamada a findClass puede fallar de varias maneras. Los más comunes son:
https://riptutorial.com/es/home 155
• loadClass(String, boolean) : sobrecargue este método para implementar un modelo de
delegación alternativo.
• findResource y findResources : sobrecargue estos métodos para personalizar la carga de
recursos.
Los métodos defineClass que son responsables de cargar realmente la clase desde una matriz de
bytes son final para evitar la sobrecarga. Cualquier comportamiento personalizado debe
realizarse antes de llamar a defineClass .
Aquí hay un sencillo que carga una clase específica de una matriz de bytes:
@Override
protected Class findClass(String classname) throws ClassNotFoundException {
if (classname.equals(this.classname)) {
return defineClass(classname, classfile, 0, classfile.length);
} else {
throw new ClassNotFoundException(classname);
}
}
}
Dado que solo hemos anulado el método findClass , este cargador de clases personalizado se
comportará de la siguiente manera cuando se llame a loadClass .
1. El método loadClass del cargador de clases llama a findLoadedClass para ver si este cargador
de clases ya ha cargado una clase con este nombre. Si eso tiene éxito, el objeto Class
resultante se devuelve al solicitante.
2. El método loadClass luego delega al cargador de clases principal llamando a su llamada
loadClass . Si el padre puede manejar la solicitud, devolverá un objeto de Class que luego se
devolverá al solicitante.
3. Si el cargador de clases principal no puede cargar la clase, findClass luego llama a nuestro
método findClass , pasando el nombre de la clase a cargar.
4. Si el nombre solicitado coincide con this.classname , llamamos a defineClass para cargar la
clase real de la this.classfile bytes this.classfile . El objeto de Class resultante se
devuelve.
5. Si el nombre no coincide, lanzamos la ClassNotFoundException .
Para cargar una clase primero necesitamos definirla. La clase está definida por el ClassLoader .
Solo hay un problema, Oracle no escribió el código del ClassLoader con esta característica
disponible. Para definir la clase, necesitaremos acceder a un método llamado defineClass() que
https://riptutorial.com/es/home 156
es un método privado del ClassLoader .
Para acceder a él, lo que haremos es crear una nueva clase, ByteClassLoader , y extenderla a
ClassLoader . Ahora que hemos extendido nuestra clase a ClassLoader , podemos acceder a los
métodos privados de ClassLoader . Para hacer que defineClass() esté disponible, crearemos un
nuevo método que actuará como un espejo para el método defineClass() privado. Para llamar al
método privado necesitaremos el nombre de la clase, name , los bytes de clase, classBytes , offset
del primer byte, que será 0 porque classBytes datos 'comienza en classBytes[0] , y offset del último
byte, que será classBytes.lenght porque representa el tamaño de los datos, que será el último
desplazamiento.
Digamos que tenemos una clase llamada MyClass en el paquete stackoverflow ...
Para llamar al método, necesitamos los bytes de la clase, así que creamos un objeto Path que
representa la ruta de nuestra clase usando el método Paths.get() y pasando la ruta de la clase
binaria como un argumento. Ahora, podemos obtener los bytes de la clase con
Files.readAllBytes(path) . Así que creamos una instancia de ByteClassLoader y usamos el método
que creamos, defineClass() . Ya tenemos los bytes de clase, pero para llamar a nuestro método
también necesitamos el nombre de clase que viene dado por el nombre del paquete (punto) el
nombre canónico de clase, en este caso stackoverflow.MyClass .
Para cargar la clase, solo llamamos a loadClass() y pasamos el nombre de la clase. Este método
puede lanzar una ClassNotFoundException por lo que necesitamos usar un bloque cat de prueba
try{
loader.loadClass("stackoverflow.MyClass");
} catch(ClassNotFoundException e){
e.printStackTrace();
}
https://riptutorial.com/es/home 157
Capítulo 26: Cifrado RSA
Examples
Un ejemplo que utiliza un sistema criptográfico híbrido que consiste en OAEP
y GCM
El siguiente ejemplo encripta los datos utilizando un sistema criptográfico híbrido que consiste en
AES GCM y OAEP, utilizando sus tamaños de parámetros predeterminados y un tamaño de clave
AES de 128 bits.
OAEP es menos vulnerable al relleno de los ataques de Oracle que el relleno PKCS # 1 v1.5.
GCM también está protegido contra ataques oracle de relleno.
Notas:
• Para utilizar correctamente este código, debe proporcionar una clave RSA de al menos
2048 bits; cuanto más grande, mejor (pero más lento, especialmente durante el descifrado);
• Para utilizar AES-256, primero debe instalar los archivos de políticas de criptografía ilimitada
;
• En lugar de crear su propio protocolo, es posible que desee utilizar un formato de
contenedor como la Sintaxis de mensajes criptográficos (CMS / PKCS # 7) o PGP en su
lugar.
/**
* Encrypts the data using a hybrid crypto-system which uses GCM to encrypt the data and OAEP
to encrypt the AES key.
* The key size of the AES encryption will be 128 bit.
* All the default parameter choices are used for OAEP and GCM.
*
* @param publicKey the RSA public key used to wrap the AES key
* @param plaintext the plaintext to be encrypted, not altered
https://riptutorial.com/es/home 158
* @return the ciphertext
* @throws InvalidKeyException if the key is not an RSA public key
* @throws NullPointerException if the plaintext is null
*/
public static byte[] encryptData(PublicKey publicKey, byte[] plaintext)
throws InvalidKeyException, NullPointerException {
Cipher oaep;
try {
// SHA-1 is the default and not vulnerable in this setting
// use OAEPParameterSpec to configure more than just the hash
oaep = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for RSA cipher (mandatory algorithm for
runtimes)", e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for OAEP padding (present in the standard Java
runtime sinze XX)", e);
}
oaep.init(Cipher.WRAP_MODE, publicKey);
KeyGenerator aesKeyGenerator;
try {
aesKeyGenerator = KeyGenerator.getInstance("AES");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for AES key generator (mandatory algorithm for
runtimes)", e);
}
// for AES-192 and 256 make sure you've got the rights (install the
// Unlimited Crypto Policy files)
aesKeyGenerator.init(128);
SecretKey aesKey = aesKeyGenerator.generateKey();
byte[] wrappedKey;
try {
wrappedKey = oaep.wrap(aesKey);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(
"AES key should always fit OAEP with normal sized RSA key", e);
}
Cipher aesGCM;
try {
aesGCM = Cipher.getInstance("AES/GCM/Nopadding");
// we can get away with a zero nonce since the key is randomly generated
https://riptutorial.com/es/home 159
// 128 bits is the recommended (maximum) value for the tag size
// 12 bytes (96 bits) is the default nonce size for GCM mode encryption
GCMParameterSpec staticParameterSpec = new GCMParameterSpec(128, new byte[12]);
aesGCM.init(Cipher.ENCRYPT_MODE, aesKey, staticParameterSpec);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for AES cipher (mandatory algorithm for
runtimes)", e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for GCM (present in the standard Java runtime
sinze XX)", e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(
"IvParameterSpec not accepted by this implementation of GCM", e);
}
// --- create a buffer of the right size for our own protocol ---
// - element 1: make sure that we know the size of the wrapped key
ciphertextBuffer.putShort((short) wrappedKey.length);
return ciphertextBuffer.array();
}
Por supuesto, el cifrado no es muy útil sin descifrado. Tenga en cuenta que esto devolverá
información mínima si el descifrado falla.
/**
* Decrypts the data using a hybrid crypto-system which uses GCM to encrypt
* the data and OAEP to encrypt the AES key. All the default parameter
* choices are used for OAEP and GCM.
*
* @param privateKey
* the RSA private key used to unwrap the AES key
* @param ciphertext
* the ciphertext to be encrypted, not altered
* @return the plaintext
* @throws InvalidKeyException
* if the key is not an RSA private key
* @throws NullPointerException
* if the ciphertext is null
* @throws IllegalArgumentException
* with the message "Invalid ciphertext" if the ciphertext is invalid (minimize
https://riptutorial.com/es/home 160
information leakage)
*/
public static byte[] decryptData(PrivateKey privateKey, byte[] ciphertext)
throws InvalidKeyException, NullPointerException {
Cipher oaep;
try {
// SHA-1 is the default and not vulnerable in this setting
// use OAEPParameterSpec to configure more than just the hash
oaep = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for RSA cipher (mandatory algorithm for
runtimes)",
e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for OAEP padding (present in the standard Java
runtime sinze XX)",
e);
}
oaep.init(Cipher.UNWRAP_MODE, privateKey);
// sanity check #1
if (ciphertextBuffer.remaining() < 2) {
throw new IllegalArgumentException("Invalid ciphertext");
}
// - element 1: the length of the encapsulated key
int wrappedKeySize = ciphertextBuffer.getShort() & 0xFFFF;
// sanity check #2
if (ciphertextBuffer.remaining() < wrappedKeySize + 128 / Byte.SIZE) {
throw new IllegalArgumentException("Invalid ciphertext");
}
https://riptutorial.com/es/home 161
Cipher aesGCM;
try {
aesGCM = Cipher.getInstance("AES/GCM/Nopadding");
// we can get away with a zero nonce since the key is randomly
// generated
// 128 bits is the recommended (maximum) value for the tag size
// 12 bytes (96 bits) is the default nonce size for GCM mode
// encryption
GCMParameterSpec staticParameterSpec = new GCMParameterSpec(128,
new byte[12]);
aesGCM.init(Cipher.DECRYPT_MODE, aesKey, staticParameterSpec);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for AES cipher (mandatory algorithm for
runtimes)",
e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for GCM (present in the standard Java runtime
sinze XX)",
e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(
"IvParameterSpec not accepted by this implementation of GCM",
e);
}
// --- create a buffer of the right size for our own protocol ---
return plaintextBuffer.array();
}
https://riptutorial.com/es/home 162
Capítulo 27: Clase - Reflexión de Java
Introducción
La clase java.lang.Class proporciona muchos métodos que pueden usarse para obtener
metadatos, examinar y cambiar el comportamiento del tiempo de ejecución de una clase.
Donde se usa
IDE (entorno de desarrollo integrado), por ejemplo, Eclipse, MyEclipse, NetBeans, etc.
Herramientas de prueba de depurador, etc.
Examples
Método getClass () de la clase Object.
class Simple { }
class Test {
void printName(Object obj){
Class c = obj.getClass();
System.out.println(c.getName());
}
public static void main(String args[]){
Simple s = new Simple();
https://riptutorial.com/es/home 163
Capítulo 28: Clase de fecha
Sintaxis
• Date object = new Date();
• Date object = new Date(long date);
Parámetros
Parámetro Explicación
Sin Crea un nuevo objeto Date utilizando el tiempo de asignación (al milisegundo
parametro más cercano)
Observaciones
Representación
Por lo tanto, si todo lo que desea hacer en su código es una hora específica, puede crear una
clase de Fecha y almacenarla, etc. Si desea imprimir una versión legible por humanos de esa
fecha, sin embargo, cree una clase de Calendario. y use su formato para producir horas, minutos,
segundos, días, zonas horarias, etc. Recuerde que un milisegundo específico se muestra como
horas diferentes en diferentes zonas horarias; Normalmente, usted desea mostrar uno en la zona
horaria "local", pero los métodos de formato deben tener en cuenta que es posible que desee
mostrarlo para otro.
También tenga en cuenta que los relojes utilizados por las JVM no suelen tener una precisión de
milisegundos; el reloj solo puede "marcar" cada 10 milisegundos y, por lo tanto, si sincroniza las
cosas, no puede confiar en medirlas con precisión a ese nivel.
Declaración de importación
import java.util.Date;
Precaución
https://riptutorial.com/es/home 164
Date instancias de Date son mutables, por lo que su uso puede dificultar la escritura de código
seguro para subprocesos o puede proporcionar accidentalmente acceso de escritura al estado
interno. Por ejemplo, en la siguiente clase, el método getDate() permite a la persona que llama
modificar la fecha de la transacción:
La solución es devolver una copia del campo de date o usar las nuevas API en java.time
introducidas en Java 8.
La mayoría de los métodos de construcción en la clase Date han quedado en desuso y no deben
usarse. En casi todos los casos, es recomendable utilizar la clase Calendar para las operaciones
de fecha.
Java 8
Java 8 introduce una nueva API de fecha y hora en el paquete java.time , que incluye LocalDate y
LocalTime . Las clases en el paquete java.time proporcionan una API revisada que es más fácil
de usar. Si está escribiendo en Java 8, le recomendamos encarecidamente que utilice esta nueva
API. Consulte Fechas y hora (java.time. *) .
Examples
Creando objetos de fecha
Aquí, este objeto Date contiene la fecha y hora actuales en que se creó este objeto.
Date objetos de Date se crean mejor a través de una instancia de Calendar , ya que el uso de los
constructores de datos está obsoleto y no se recomienda. Para hacerlo, necesitamos obtener una
instancia de la clase Calendar del método de fábrica. Luego podemos establecer el año, mes y día
del mes utilizando números o, en el caso de las constantes de los meses que se proporcionan en
la clase Calendario, para mejorar la legibilidad y reducir los errores.
https://riptutorial.com/es/home 165
System.out.println(myBirthDatenTime); // Mon Dec 31 08:32:35 IST 1990
Junto con la fecha, también podemos pasar el tiempo en el orden de horas, minutos y segundos.
//Before example
System.out.printf("Is %1$tF before %2$tF? %3$b%n", today, birthdate,
Boolean.valueOf(today.before(birthdate)));
System.out.printf("Is %1$tF before %1$tF? %3$b%n", today, today,
Boolean.valueOf(today.before(today)));
System.out.printf("Is %2$tF before %1$tF? %3$b%n", today, birthdate,
Boolean.valueOf(birthdate.before(today)));
//After example
System.out.printf("Is %1$tF after %2$tF? %3$b%n", today, birthdate,
Boolean.valueOf(today.after(birthdate)));
System.out.printf("Is %1$tF after %1$tF? %3$b%n", today, birthdate,
Boolean.valueOf(today.after(today)));
System.out.printf("Is %2$tF after %1$tF? %3$b%n", today, birthdate,
Boolean.valueOf(birthdate.after(today)));
//Compare example
System.out.printf("Compare %1$tF to %2$tF: %3$d%n", today, birthdate,
Integer.valueOf(today.compareTo(birthdate)));
System.out.printf("Compare %1$tF to %1$tF: %3$d%n", today, birthdate,
Integer.valueOf(today.compareTo(today)));
System.out.printf("Compare %2$tF to %1$tF: %3$d%n", today, birthdate,
Integer.valueOf(birthdate.compareTo(today)));
//Equal example
System.out.printf("Is %1$tF equal to %2$tF? %3$b%n", today, birthdate,
Boolean.valueOf(today.equals(birthdate)));
System.out.printf("Is %1$tF equal to %2$tF? %3$b%n", birthdate, samebirthdate,
Boolean.valueOf(birthdate.equals(samebirthdate)));
System.out.printf(
"Because birthdate.getTime() -> %1$d is different from samebirthdate.getTime() ->
%2$d, there are millisecondes!%n",
https://riptutorial.com/es/home 166
Long.valueOf(birthdate.getTime()), Long.valueOf(samebirthdate.getTime()));
Java SE 8
//Hours, minutes, second and nanoOfsecond can also be configured with an other class
LocalDateTime
//LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
//isBefore example
System.out.printf("Is %1$tF before %2$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(now.isBefore(birthdate2)));
System.out.printf("Is %1$tF before %1$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(now.isBefore(now)));
System.out.printf("Is %2$tF before %1$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(birthdate2.isBefore(now)));
//isAfter example
System.out.printf("Is %1$tF after %2$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(now.isAfter(birthdate2)));
System.out.printf("Is %1$tF after %1$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(now.isAfter(now)));
System.out.printf("Is %2$tF after %1$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(birthdate2.isAfter(now)));
//compareTo example
System.out.printf("Compare %1$tF to %2$tF %3$d%n", now, birthdate2,
Integer.valueOf(now.compareTo(birthdate2)));
System.out.printf("Compare %1$tF to %1$tF %3$d%n", now, birthdate2,
Integer.valueOf(now.compareTo(now)));
System.out.printf("Compare %2$tF to %1$tF %3$d%n", now, birthdate2,
Integer.valueOf(birthdate2.compareTo(now)));
//equals example
System.out.printf("Is %1$tF equal to %2$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(now.equals(birthdate2)));
System.out.printf("Is %1$tF to %2$tF? %3$b%n", birthdate2, birthdate3,
Boolean.valueOf(birthdate2.equals(birthdate3)));
https://riptutorial.com/es/home 167
//isEqual example
System.out.printf("Is %1$tF equal to %2$tF? %3$b%n", now, birthdate2,
Boolean.valueOf(now.isEqual(birthdate2)));
System.out.printf("Is %1$tF to %2$tF? %3$b%n", birthdate2, birthdate3,
Boolean.valueOf(birthdate2.isEqual(birthdate3)));
after, before , compareTo y equals métodos comparan los valores devueltos por getTime () método
para cada fecha.
equals resultados equals pueden ser sorprendentes como se muestra en el ejemplo porque los
valores, como los milisegundos, no se inicializan con el mismo valor si no se dan explícitamente.
Desde Java 8
Con Java 8, está disponible un nuevo Objeto para trabajar con Fecha java.time.LocalDate .
LocalDate implementa ChronoLocalDate , la representación abstracta de una fecha donde la
cronología, o sistema de calendario, es conectable.
Debido a que la mayoría de las aplicaciones deben usar LocalDate , ChronoLocalDate no se incluye
en los ejemplos. Lectura adicional aquí .
https://riptutorial.com/es/home 168
• isAfter (ChronoLocalDate other)
• isBefore (ChronoLocalDate other)
• isEqual (ChronoLocalDate otro)
• compareTo (ChronoLocalDate otro)
• es igual a (objeto obj)
En el caso del parámetro LocalDate , isAfter , isBefore , isEqual , equals y compareTo ahora use este
método:
En el caso de una instancia de otra clase de ChronoLocalDate las fechas se comparan utilizando el
Epoch Day la Epoch Day . El recuento del día de la época es un recuento incremental simple de días
donde el día 0 es 1970-01-01 (ISO).
format()de la clase SimpleDateFormat ayuda a convertir un objeto Date en cierto objeto String
formato utilizando la cadena de patrón suministrada.
dateFormat.applyPattern("dd-MM-yyyy");
System.out.println(dateFormat.format(today)); //25-02-2016
Nota: Aquí mm (letra minúscula m) denota minutos y MM (mayúscula M) denota mes. Preste mucha
atención al formatear los años: el capital "Y" ( Y ) indica la "semana del año", mientras que la
minúscula "y" ( y ) indica el año.
https://riptutorial.com/es/home 169
parse() de la clase SimpleDateFormat ayuda a convertir un patrón de String en un objeto Date .
Hay 4 estilos diferentes para el formato de texto, SHORT , MEDIUM (este es el valor predeterminado),
LONG y FULL , todos los cuales dependen de la configuración regional. Si no se especifica una
configuración regional, se utiliza la configuración regional predeterminada del sistema.
// print it
System.out.println(formattedDate);
Este método se puede usar para convertir una representación de cadena formateada de una
https://riptutorial.com/es/home 170
fecha en un objeto Date .
/**
* Parses the date using the given format.
*
* @param formattedDate the formatted date string
* @param dateFormat the date format which was used to create the string.
* @return the date
*/
public static Date parseDate(String formattedDate, String dateFormat) {
Date date = null;
SimpleDateFormat objDf = new SimpleDateFormat(dateFormat);
try {
date = objDf.parse(formattedDate);
} catch (ParseException e) {
// Do what ever needs to be done with exception.
}
return date;
}
Si bien la clase de fecha de Java tiene varios constructores, notará que la mayoría está en
desuso. La única forma aceptable de crear una instancia de Fecha directamente es usando el
constructor vacío o pasando un largo (número de milisegundos desde el tiempo base estándar).
Tampoco son útiles a menos que esté buscando la fecha actual o tenga otra instancia de Date ya
disponible.
Para crear una nueva fecha, necesitará una instancia de Calendario. Desde allí puede establecer
la instancia de Calendario en la fecha que necesite.
Calendar c = Calendar.getInstance();
Esto devuelve un nuevo conjunto de instancias de Calendario a la hora actual. El calendario tiene
muchos métodos para mutar su fecha y hora o establecerlo de forma absoluta. En este caso, lo
estableceremos en una fecha específica.
c.set(1974, 6, 2, 8, 0, 0);
Date d = c.getTime();
El método getTime devuelve la instancia de fecha que necesitamos. Tenga en cuenta que los
métodos de configuración del calendario solo establecen uno o más campos, no los configuran
todos. Es decir, si establece el año, los otros campos permanecerán sin cambios.
TRAMPA
En muchos casos, este fragmento de código cumple su propósito, pero tenga en cuenta que dos
partes importantes de la fecha / hora no están definidas.
https://riptutorial.com/es/home 171
• los milisegundos no se establecen en cero, pero se llenan desde el reloj del sistema en el
momento en que se crea la instancia de Calendario.
Los objetos Date y LocalDate no se pueden convertir exactamente entre sí ya que un objeto Date
representa un día y una hora específicos, mientras que un objeto LocalDate no contiene
información de hora o zona horaria. Sin embargo, puede ser útil convertir entre los dos si solo te
importa la información de la fecha real y no la información de la hora.
Crea un LocalDateTime
// Date to LocalDate
LocalDate localDate = date.toInstant().atZone(defaultZoneId).toLocalDate();
// LocalDate to Date
Date.from(localDate.atStartOfDay(defaultZoneId).toInstant());
https://riptutorial.com/es/home 172
// Date to LocalDateTime
LocalDateTime localDateTime = date.toInstant().atZone(defaultZoneId).toLocalDateTime();
// LocalDateTime to Date
Date out = Date.from(localDateTime.atZone(defaultZoneId).toInstant());
Sin embargo, es posible mostrar la fecha representada por el punto en el tiempo descrito por el
objeto Date en una zona horaria diferente utilizando, por ejemplo, java.text.SimpleDateFormat :
Salida:
java.util.Date to java.sql.Date conversión suele ser necesaria cuando un objeto Date debe
escribirse en una base de datos.
Ejemplo
https://riptutorial.com/es/home 173
public static void main(String args[])
{
java.util.Date utilDate = new java.util.Date();
System.out.println("java.util.Date is : " + utilDate);
java.sql.Date sqlDate = convert(utilDate);
System.out.println("java.sql.Date is : " + sqlDate);
DateFormat df = new SimpleDateFormat("dd/MM/YYYY - hh:mm:ss");
System.out.println("dateFormated date is : " + df.format(utilDate));
}
Salida
Hora local
Para usar solo la parte de tiempo de una fecha use LocalTime. Puede crear una instancia de un
objeto LocalTime en un par de maneras
LocalTime también tiene un método toString incorporado que muestra el formato muy bien.
System.out.println(time);
También puede obtener, sumar y restar horas, minutos, segundos y nanosegundos del objeto
LocalTime, es decir,
time.plusMinutes(1);
time.getMinutes();
time.minusMinutes(1);
https://riptutorial.com/es/home 174
esta clase funciona muy bien dentro de una clase de temporizador para simular un reloj de
alarma.
https://riptutorial.com/es/home 175
Capítulo 29: Clase de objetos Métodos y
constructor
Introducción
Esta página de documentación sirve para mostrar detalles con ejemplos sobre constructores de
clases Java y sobre Métodos de clases de objetos que se heredan automáticamente de la
Superclase Object de cualquier clase recién creada.
Sintaxis
• Clase nativa final pública <?> getClass ()
• pública final vacío nativo notificar ()
• vacío nativo final público notificar a todos ()
• la espera de final nativa pública pública (tiempo de espera largo) lanza InterruptedException
• pública final void wait () lanza InterruptedException
• la espera de final público (tiempo de espera largo, int nanos) lanza la excepción
interrumpida
• código nativo int local ()
• booleanos públicos iguales (objeto obj)
• Cadena pública a la cadena ()
• El objeto nativo protegido clone () lanza la excepción CloneNotSupportedException
• vacío vacío finalizado () lanza Throwable
Examples
método toString ()
El método toString() se usa para crear una representación de String de un objeto utilizando el
contenido del objeto. Este método debe ser anulado al escribir su clase. toString() se llama
implícitamente cuando un objeto se concatena a una cadena como en "hello " + anObject .
Considera lo siguiente:
@Override
public String toString() {
return firstName + " " + lastName;
https://riptutorial.com/es/home 176
}
Aquí toString() de la clase Object se reemplaza en la clase User para proporcionar datos
significativos sobre el objeto al imprimirlo.
Cuando se utiliza println() , el método toString() del objeto se llama implícitamente. Por lo tanto,
estas declaraciones hacen lo mismo:
método igual ()
TL; DR
equals() es un método usado para comparar dos objetos para la igualdad. La implementación
predeterminada del método equals() en la clase Object devuelve true si y solo si ambas
referencias apuntan a la misma instancia. Por lo tanto, se comporta igual que la comparación por
== .
https://riptutorial.com/es/home 177
}
}
Aunque foo1 y foo2 se crean con los mismos campos, apuntan a dos objetos diferentes en la
memoria. La implementación por defecto de equals() por lo tanto, se evalúa como false .
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
@Override
public int hashCode() {
int hash = 1;
hash = 31 * hash + this.field1;
hash = 31 * hash + this.field2;
hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
return hash;
}
Aquí el método equals() anulado decide que los objetos son iguales si sus campos son iguales.
Observe que el método hashCode() también se sobrescribió. El contrato para ese método
establece que cuando dos objetos son iguales, sus valores hash también deben ser iguales. Es
por eso que uno casi siempre debe reemplazar hashCode() y equals() juntos.
Preste especial atención al tipo de argumento del método equals . Es el Object obj , no Foo obj . Si
https://riptutorial.com/es/home 178
coloca este último en su método, eso no es una anulación del método equals .
Al escribir su propia clase, tendrá que escribir una lógica similar cuando se reemplaza a equals() y
hashCode() . La mayoría de los IDE pueden generar esto automáticamente por ti.
Se puede encontrar un ejemplo de una implementación equals() en la clase String , que forma
parte de la API de Java central. En lugar de comparar punteros, la clase String compara el
contenido de String .
Java SE 7
Java 1.7 introdujo la clase java.util.Objects que proporciona un método conveniente, equals , que
compara dos referencias potencialmente null , por lo que puede usarse para simplificar
implementaciones del método equals .
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Comparación de clases
Dado que el método equals puede ejecutarse contra cualquier objeto, una de las primeras cosas
que el método hace a menudo (después de verificar si es null ) es verificar si la clase del objeto
que se está comparando coincide con la clase actual.
@Override
public boolean equals(Object obj) {
//...check for null
if (getClass() != obj.getClass()) {
return false;
}
//...compare fields
}
Esto se hace normalmente como se muestra arriba comparando los objetos de clase. Sin
embargo, eso puede fallar en algunos casos especiales que pueden no ser obvios. Por ejemplo,
algunos marcos generan proxies dinámicos de clases y estos proxies dinámicos son en realidad
una clase diferente. Aquí hay un ejemplo usando JPA.
https://riptutorial.com/es/home 179
//as mergedInstance is a proxy (subclass) of Foo
}
@Override
public final boolean equals(Object obj) {
if (!(obj instanceof Foo)) {
return false;
}
//...compare fields
}
Sin embargo, hay algunos escollos que se deben evitar al usar instanceof . Como Foo podría
tener otras subclases y esas subclases podrían reemplazar a equals() , podría entrar en un caso
en el que un Foo es igual a una FooSubclass pero la FooSubclass Foo no es igual a Foo .
Esto viola las propiedades de simetría y transitividad y, por lo tanto, es una implementación no
válida del método equals() . Como resultado, cuando se utiliza instanceof , una buena práctica es
hacer que el método equals() final (como en el ejemplo anterior). Esto asegurará que ninguna
anulación de subclase sea equals() y viole las suposiciones clave.
método hashCode ()
Cuando una clase de Java anula el método equals , también debería anular el método hashCode .
Como se define en el contrato del método :
• Cada vez que se invoca en el mismo objeto más de una vez durante una
ejecución de una aplicación Java, el método hashCode debe devolver
constantemente el mismo número entero, siempre que no se modifique la
información utilizada en comparaciones iguales en el objeto. No es necesario
que este número entero permanezca consistente de una ejecución de una
aplicación a otra ejecución de la misma aplicación.
• Si dos objetos son iguales según el método equals(Object) , entonces llamar al
método hashCode en cada uno de los dos objetos debe producir el mismo
resultado entero.
• No es necesario que si dos objetos son desiguales según el método
equals(Object) , llamar al método hashCode en cada uno de los dos objetos debe
producir resultados enteros distintos. Sin embargo, el programador debe tener en
cuenta que producir resultados enteros distintos para objetos desiguales puede
mejorar el rendimiento de las tablas hash.
Los códigos hash se utilizan en implementaciones de hash como HashMap , HashTable y HashSet . El
resultado de la función hashCode determina el grupo en el que se colocará un objeto. Estas
https://riptutorial.com/es/home 180
implementaciones de hash son más eficientes si la implementación de hashCode proporcionada es
buena. Una propiedad importante de una buena implementación de hashCode es que la distribución
de los valores de hashCode es uniforme. En otras palabras, existe una pequeña probabilidad de
que numerosas instancias se almacenen en el mismo cubo.
Un algoritmo para calcular un valor de código hash puede ser similar al siguiente:
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
@Override
public int hashCode() {
int hash = 1;
hash = 31 * hash + field1;
hash = 31 * hash + field2;
hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
return hash;
}
}
En Java 1.2 y superior, en lugar de desarrollar un algoritmo para calcular un código hash, se
puede generar uno utilizando java.util.Arrays#hashCode proporcionando un objeto o una matriz de
primitivas que contiene los valores de campo:
@Override
public int hashCode() {
return Arrays.hashCode(new Object[] {field1, field2, field3});
}
Java SE 7
https://riptutorial.com/es/home 181
Java 1.7 introdujo la clase java.util.Objects que proporciona un método conveniente,
hash(Object... objects) , que calcula un código hash basado en los valores de los objetos que se
le suministran. Este método funciona igual que java.util.Arrays#hashCode .
@Override
public int hashCode() {
return Objects.hash(field1, field2, field3);
}
Nota: este enfoque es ineficiente y produce objetos de basura cada vez que se llama a su método
hashCode() personalizado:
// Other methods
@Override
public boolean equals(Object obj) {
// ...
}
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
h = Arrays.hashCode(array);
hash = h;
}
return h;
}
}
https://riptutorial.com/es/home 182
sobrecarga de un campo adicional para almacenar en caché el código hash. Si esto se amortiza
como una optimización del rendimiento dependerá de la frecuencia con la que se halle (busque)
un objeto determinado y otros factores.
También notará que si el verdadero código hash de un ImmutableArray es cero (una posibilidad en
2 32 ), el caché no es efectivo.
Finalmente, este enfoque es mucho más difícil de implementar correctamente si el objeto que
estamos haciendo hash es mutable. Sin embargo, hay mayores preocupaciones si los códigos
hash cambian; Consulte el contrato anterior.
wait() y notify() trabajan en tándem: cuando un subproceso llama a wait() en un objeto, ese
subproceso se bloqueará hasta que otro subproceso llame a notify() o notifyAll() en ese mismo
objeto.
package com.example.examples.object;
import java.util.concurrent.atomic.AtomicBoolean;
https://riptutorial.com/es/home 183
} catch (InterruptedException e) {
System.err.println("Thread B was interrupted from waiting");
}
}
while (!aHasFinishedWaiting.get()) {
synchronized (obj) {
// notify ONE thread which has called obj.wait()
obj.notify();
}
}
}
};
threadA.start();
threadB.start();
threadA.join();
threadB.join();
System.out.println("Finished!");
}
}
método getClass ()
El método getClass() se puede usar para encontrar el tipo de clase de tiempo de ejecución de un
objeto. Vea el ejemplo a continuación:
https://riptutorial.com/es/home 184
public class User {
El método getClass() devolverá el tipo de clase más específico, por lo que cuando se llama a
getClass() en anotherSpecificUser , el valor devuelto es la class SpecificUser porque es más bajo
en el árbol de herencia que el User .
El tipo estático real devuelto por una llamada a getClass es Class<? extends T> donde T es el tipo
estático del objeto en el que se llama a getClass .
método clone ()
El método clone() se utiliza para crear y devolver una copia de un objeto. Este método discutible
debe evitarse ya que es problemático y se debe utilizar un constructor de copia o algún otro
método para copiar en favor de clone() .
Para que el método se use, todas las clases que llaman al método deben implementar la interfaz
Cloneable .
https://riptutorial.com/es/home 185
La interfaz Cloneable en sí misma es solo una interfaz de etiqueta utilizada para cambiar el
comportamiento del método native clone() que verifica si la clase de objetos llamantes
implementa Cloneable . Si la persona que llama no implementa esta interfaz, se
CloneNotSupportedException una CloneNotSupportedException .
Para que un clon sea correcto, debe ser independiente del objeto desde el cual se está clonando,
por lo tanto, puede ser necesario modificar el objeto antes de que se devuelva. Esto significa
crear esencialmente una "copia profunda" copiando también cualquiera de los objetos mutables
que conforman la estructura interna del objeto que se está clonando. Si esto no se implementa
correctamente, el objeto clonado no será independiente y tendrá las mismas referencias a los
objetos mutables que el objeto desde el que se clonó. Esto resultaría en un comportamiento
inconsistente ya que cualquier cambio en aquellos en uno afectaría al otro.
} catch (CloneNotSupportedException e) {
// in case any of the cloned mutable fields do not implement Cloneable
throw new AssertionError(e);
}
}
}
finalizar () método
Este es un método protegido y no estático de la clase Object . Este método se utiliza para realizar
algunas operaciones finales o limpiar operaciones en un objeto antes de que se elimine de la
memoria.
https://riptutorial.com/es/home 186
Según el documento, este método es llamado por el recolector de basura en un objeto
cuando la recolección de basura determina que no hay más referencias al objeto.
Pero no hay garantías de que se llame al método finalize() si el objeto aún es accesible o si no
se ejecuta ningún recolector de basura cuando el objeto es elegible. Es por eso que es mejor no
confiar en este método.
En las bibliotecas principales de Java, se pueden encontrar algunos ejemplos de uso, por
ejemplo, en FileInputStream.java :
En este caso, es la última oportunidad de cerrar el recurso si ese recurso no se ha cerrado antes.
Los finalizadores no están destinados a liberar recursos (por ejemplo, cerrar archivos). Se llama al
recolector de basura cuando (si!) El sistema se queda con poco espacio de almacenamiento. No
se puede confiar en que se llame cuando el sistema se esté quedando sin los manejadores de
archivos o, por cualquier otro motivo.
El caso de uso previsto para los finalizadores es para un objeto que está a punto de ser
reclamado para notificar a otro objeto sobre su inminente destino. Ahora existe un mejor
mecanismo para ese propósito: la clase java.lang.ref.WeakReference<T> . Si crees que necesitas
escribir un método finalize() , entonces deberías investigar si puedes resolver el mismo
problema usando WeakReference . Si eso no resuelve su problema, es posible que deba volver a
pensar su diseño en un nivel más profundo.
Para leer más aquí, hay un artículo sobre el método finalize() del libro "Effective Java" de
Joshua Bloch.
Constructor de objetos
Todos los constructores en Java deben hacer una llamada al constructor de Object . Esto se hace
con la llamada super() . Esta tiene que ser la primera línea en un constructor. La razón de esto es
para que el objeto se pueda crear realmente en el montón antes de que se realice una
inicialización adicional.
https://riptutorial.com/es/home 187
con llamada explícita a super() constructor
public MyClass() {
super();
}
}
public MyClass() {
// empty
}
}
Es posible llamar a otros constructores como la primera instrucción de un constructor. Como tanto
la llamada explícita a un súper constructor como la llamada a otro constructor tienen que ser las
dos primeras instrucciones, se excluyen mutuamente.
doSomethingWith(size);
this(initialValues.size());
addInitialValues(initialValues);
}
}
https://riptutorial.com/es/home 188
Dado el ejemplo anterior, uno puede llamar a new MyClass("argument") o new MyClass("argument", 0)
. En otras palabras, al igual que la sobrecarga de métodos , simplemente llame al constructor con
los parámetros que son necesarios para su constructor elegido.
Nada más de lo que sucedería en una subclase que tiene un constructor vacío predeterminado
(menos la llamada a super() ).
La creación real de objetos se reduce a la JVM. Cada constructor en Java aparece como un
método especial llamado <init> que es responsable de la inicialización de la instancia. El
compilador suministra este método <init> y debido a que <init> no es un identificador válido en
Java, no se puede usar directamente en el lenguaje.
La JVM invocará el método <init> utilizando la instrucción especial invokespecial y solo puede
invocarse en instancias de clase sin inicializar.
Para obtener más información, consulte la especificación JVM y la especificación del lenguaje
Java:
https://riptutorial.com/es/home 189
Capítulo 30: Clase de propiedades
Introducción
El objeto de propiedades contiene un par de clave y valor tanto como una cadena. La clase
java.util.Properties es la subclase de Hashtable.
Sintaxis
• En un archivo de propiedades:
• clave = valor
• #comentario
Observaciones
Un objeto de propiedades es un mapa cuyas claves y valores son cadenas por convención.
Aunque los métodos de Map se pueden usar para acceder a los datos, los métodos getProperty ,
setProperty y stringPropertyNames más seguros para el uso de tipos se usan en su lugar.
Las propiedades se almacenan con frecuencia en archivos de propiedades Java, que son
archivos de texto simples. Su formato está documentado a fondo en el método Properties.load .
En resumen:
• Cada par clave / valor es una línea de texto con espacios en blanco, es igual a ( = ), o colon
( : ) entre la llave y el valor. Los iguales o dos puntos pueden tener cualquier cantidad de
espacios en blanco antes y después, que se ignora.
• Los espacios en blanco iniciales siempre se ignoran, los espacios en blanco finales se
incluyen siempre.
• Se puede usar una barra invertida para escapar de cualquier carácter (excepto en
minúsculas u ).
• Una barra invertida al final de la línea indica que la siguiente línea es una continuación de la
línea actual. Sin embargo, al igual que con todas las líneas, los espacios en blanco iniciales
en la línea de continuación se ignoran.
• Al igual que en el código fuente de Java, \u seguido de cuatro dígitos hexadecimales
representa un carácter UTF-16.
https://riptutorial.com/es/home 190
La mayoría de los marcos, incluidas las instalaciones propias de Java SE como
java.util.ResourceBundle, cargan archivos de propiedades como InputStreams. Al cargar un
archivo de propiedades desde un InputStream, ese archivo solo puede contener caracteres ISO
8859-1 (es decir, caracteres en el rango de 0 a 255). Cualquier otro personaje debe ser
representado como \u escapa. Sin embargo, puede escribir un archivo de texto en cualquier
codificación y usar la herramienta native2ascii (que viene con cada JDK) para hacer ese escape
por usted.
Si va a cargar un archivo de propiedades con su propio código, que puede ser en cualquier
codificación, siempre y cuando se crea un lector (como un InputStreamReader ) basado en el
correspondiente conjunto de caracteres . Luego puede cargar el archivo usando load (Reader) en
lugar del método de carga heredado (InputStream).
También puede almacenar propiedades en un archivo XML simple, lo que permite que el propio
archivo defina la codificación. Dicho archivo se puede cargar con el método loadFromXML . La
DTD que describe la estructura de dichos archivos XML se encuentra en
http://java.sun.com/dtd/properties.dtd .
Examples
Cargando propiedades
Eche un vistazo de cerca a estos dos archivos de propiedades que parecen ser completamente
idénticos:
https://riptutorial.com/es/home 191
excepto que en realidad no son idénticos:
Dado que el espacio en blanco se conserva, el valor de lastName sería "Smith" en el primer caso y
"Smith " en el segundo.
Muy raramente, esto es lo que los usuarios esperan y uno y solo puede especular por qué este es
el comportamiento predeterminado de la clase Properties . Sin embargo, es fácil crear una versión
mejorada de Properties que solucione este problema. La siguiente clase, TrimmedProperties ,
hace justamente eso. Es un reemplazo directo para la clase de propiedades estándar.
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Map.Entry;
import java.util.Properties;
/**
* Properties class where values are trimmed for trailing whitespace if the
* properties are loaded from a file.
*
* <p>
* In the standard {@link java.util.Properties Properties} class trailing
* whitespace is always preserved. When loading properties from a file such
* trailing whitespace is almost always <i>unintentional</i>. This class fixes
* this problem. The trimming of trailing whitespace only takes place if the
* source of input is a file and only where the input is line oriented (meaning
* that for example loading from XML file is <i>not</i> changed by this class).
* For this reason this class is almost in all cases a safe drop-in replacement
* for the standard <tt>Properties</tt>
* class.
*
* <p>
* Whitespace is defined here as any of space (U+0020) or tab (U+0009).
* *
*/
public class TrimmedProperties extends Properties {
/**
* Reads a property list (key and element pairs) from the input byte stream.
*
* <p>Behaves exactly as {@link java.util.Properties#load(java.io.InputStream) }
* with the exception that trailing whitespace is trimmed from property values
https://riptutorial.com/es/home 192
* if <tt>inStream</tt> is an instance of <tt>FileInputStream</tt>.
*
* @see java.util.Properties#load(java.io.InputStream)
* @param inStream the input stream.
* @throws IOException if an error occurred when reading from the input stream.
*/
@Override
public void load(InputStream inStream) throws IOException {
if (inStream instanceof FileInputStream) {
// First read into temporary props using the standard way
Properties tempProps = new Properties();
tempProps.load(inStream);
// Now trim and put into target
trimAndLoad(tempProps);
} else {
super.load(inStream);
}
}
/**
* Reads a property list (key and element pairs) from the input character stream in a
simple line-oriented format.
*
* <p>Behaves exactly as {@link java.util.Properties#load(java.io.Reader)}
* with the exception that trailing whitespace is trimmed on property values
* if <tt>reader</tt> is an instance of <tt>FileReader</tt>.
*
* @see java.util.Properties#load(java.io.Reader) }
* @param reader the input character stream.
* @throws IOException if an error occurred when reading from the input stream.
*/
@Override
public void load(Reader reader) throws IOException {
if (reader instanceof FileReader) {
// First read into temporary props using the standard way
Properties tempProps = new Properties();
tempProps.load(reader);
// Now trim and put into target
trimAndLoad(tempProps);
} else {
super.load(reader);
}
}
/**
* Trims trailing space or tabs from a string.
*
* @param str
* @return
*/
public static String trimTrailing(String str) {
https://riptutorial.com/es/home 193
if (str != null) {
// read str from tail until char is no longer whitespace
for (int i = str.length() - 1; i >= 0; i--) {
if ((str.charAt(i) != ' ') && (str.charAt(i) != '\t')) {
return str.substring(0, i + 1);
}
}
}
return str;
}
}
La forma en que almacena los archivos de propiedades como archivos XML es muy similar a la
forma en que los almacenaría como archivos .properties . Solo en lugar de usar store()
storeToXML() .
https://riptutorial.com/es/home 194
Ahora, para cargar este archivo como una properties , debe llamar a loadFromXML() lugar de a
load() que usaría con los archivos .propeties normales.
age=23
color=green
name=Steve
https://riptutorial.com/es/home 195
Capítulo 31: Clase EnumSet
Introducción
La clase Java EnumSet es la implementación especializada de conjuntos para usar con tipos de
enumeración. Hereda la clase AbstractSet e implementa la interfaz Set.
Examples
Ejemplo de conjunto de enumeración
import java.util.*;
enum days {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
public class EnumSetExample {
public static void main(String[] args) {
Set<days> set = EnumSet.of(days.TUESDAY, days.WEDNESDAY);
// Traversing elements
Iterator<days> iter = set.iterator();
while (iter.hasNext())
System.out.println(iter.next());
}
}
https://riptutorial.com/es/home 196
Capítulo 32: Clase inmutable
Introducción
Los objetos inmutables son instancias cuyo estado no cambia después de que se haya
inicializado. Por ejemplo, String es una clase inmutable y, una vez instanciada, su valor nunca
cambia.
Observaciones
Algunas clases inmutables en Java:
1. java.lang.String
2. Las clases de envoltorio para los tipos primitivos: java.lang.Integer, java.lang.Byte,
java.lang.Character, java.lang.Short, java.lang.Boolean, java.lang.Long, java.lang.Double,
java.lang.Float
3. La mayoría de las clases de enumeración son inmutables, pero esto, de hecho, depende del
caso concreto.
4. java.math.BigInteger y java.math.BigDecimal (al menos objetos de esas clases en sí)
5. java.io.File. Tenga en cuenta que esto representa un objeto externo a la VM (un archivo en
el sistema local), que puede o no existir, y tiene algunos métodos para modificar y consultar
el estado de este objeto externo. Pero el objeto File en sí permanece inmutable.
Examples
Reglas para definir clases inmutables.
Las siguientes reglas definen una estrategia simple para crear objetos inmutables.
https://riptutorial.com/es/home 197
public final class Color {
final private int red;
final private int green;
final private int blue;
En este caso, la clase Point es mutable y algunos usuarios pueden modificar el estado del objeto
de esta clase.
class Point {
private int x, y;
//...
https://riptutorial.com/es/home 198
public ImmutableCircle(Point center, double radius) {
// we create new object here because it shouldn't be changed
this.center = new Point(center.getX(), center.getY());
this.radius = radius;
}
Al tener un objeto inmutable, uno puede asegurarse de que todos los subprocesos que miran el
objeto verán el mismo estado, ya que el estado de un objeto inmutable no cambiará.
https://riptutorial.com/es/home 199
Capítulo 33: Clase interna local
Introducción
Una clase, es decir, creada dentro de un método, se llama clase interna local en java. Si desea
invocar los métodos de la clase interna local, debe crear una instancia de esta clase dentro del
método.
Examples
Clase interna local
https://riptutorial.com/es/home 200
Capítulo 34: Clases anidadas e internas
Introducción
Usando Java, los desarrolladores tienen la capacidad de definir una clase dentro de otra clase.
Tal clase se llama una clase anidada . Las clases anidadas se denominan clases internas si se
declararon como no estáticas; de lo contrario, simplemente se denominan clases anidadas
estáticas. Esta página es para documentar y proporcionar detalles con ejemplos sobre cómo usar
clases anidadas e internas de Java.
Sintaxis
• clase pública OuterClass {clase pública InnerClass {}} // las clases internas también pueden
ser privadas
• clase pública OuterClass {clase estática pública StaticNestedClass {}} // Las clases anidadas
estáticas también pueden ser privadas
• método de anulación público () {clase privada LocalClass {}} // Las clases locales son
siempre privadas
• SomeClass anonymousClassInstance = new SomeClass () {}; // Las clases internas
anónimas no pueden ser nombradas, por lo tanto el acceso es discutible. Si 'SomeClass ()'
es abstracto, el cuerpo debe implementar todos los métodos abstractos.
• SomeInterface anonymousClassInstance = new SomeInterface () {}; // El cuerpo debe
implementar todos los métodos de interfaz.
Observaciones
Terminologia y clasificacion
La especificación de lenguaje Java (JLS) clasifica los diferentes tipos de clases de Java de la
siguiente manera:
Una clase de nivel superior es una clase que no es una clase anidada.
Una clase anidada es cualquier clase cuya declaración ocurre dentro del cuerpo de
otra clase o interfaz.
Una clase interna es una clase anidada que no se declara explícita o implícitamente
como estática.
Una clase interna puede ser una clase miembro no estática , una clase local o una
clase anónima . Una clase miembro de una interfaz es implícitamente estática, por lo
que nunca se considera una clase interna.
En la práctica, los programadores se refieren a una clase de nivel superior que contiene una clase
interna como la "clase externa". Además, hay una tendencia a usar "clase anidada" para referirse
https://riptutorial.com/es/home 201
solo a clases anidadas estáticas (explícita o implícitamente).
Tenga en cuenta que existe una relación estrecha entre las clases internas anónimas y las
lambdas, pero las lambdas son clases.
Diferencias semanticas
• Las clases de nivel superior son el "caso base". Son visibles a otras partes de un programa
sujeto a reglas de visibilidad normales basadas en la semántica del modificador de acceso.
Si no son abstractos, se pueden crear instancias de cualquier código en el que los
constructores relevantes sean visibles según los modificadores de acceso.
• Las clases anidadas estáticas siguen las mismas reglas de acceso e instanciación que las
clases de nivel superior, con dos excepciones:
○ Una clase anidada se puede declarar como private , lo que la hace inaccesible fuera
de su clase de nivel superior.
○ Una clase anidada tiene acceso a los miembros private de la clase adjunta de nivel
superior y toda su clase probada.
Esto hace que las clases anidadas estáticas sean útiles cuando necesita representar
múltiples "tipos de entidades" dentro de un límite de abstracción estricto; por ejemplo,
cuando las clases anidadas se utilizan para ocultar "detalles de implementación".
El hecho de que una instancia de clase interna pueda referirse a variables en una instancia
de clase adjunta tiene implicaciones para la creación de instancias. Específicamente, se
debe proporcionar una instancia adjunta, ya sea implícita o explícitamente, cuando se crea
una instancia de una clase interna.
Examples
Una pila simple usando una clase anidada
https://riptutorial.com/es/home 202
// Each instance of this inner class functions as one link in the
// Overall stack that it helps to represent
private static class IntStackNode {
//prints: 0, 1, 2, 3, 4,
for(int i = 0; i < 5; i++) {
System.out.print(s.pop() + ", ");
}
}
}
Al crear una clase anidada, tiene la opción de tener esa clase estática anidada:
O no estático:
https://riptutorial.com/es/home 203
private class NestedClass {
En su núcleo, las clases anidadas estáticas no tienen una instancia circundante de la clase
externa, mientras que las clases anidadas no estáticas sí las tienen. Esto afecta a dónde y
cuándo se permite a una instancia crear una clase anidada, y a qué instancias de esas clases
anidadas se les permite acceder. Añadiendo al ejemplo anterior:
private StaticNestedClass() {
innerField = aField; //Illegal, can't access aField from static context
aMethod(); //Illegal, can't call aMethod from static context
}
private NestedClass() {
innerField = aField; //Legal
aMethod(); //Legal
}
}
https://riptutorial.com/es/home 204
OuterClass2 instance.
//As this is a static context, there is no
surrounding OuterClass2 instance
}
}
Como regla general, haga que sus clases anidadas sean estáticas a menos que necesite acceder
a los campos y métodos de la clase externa. Al igual que hacer que sus campos sean privados, a
menos que los necesite, esto disminuye la visibilidad disponible para la clase anidada (al no
permitir el acceso a una instancia externa), lo que reduce la posibilidad de error.
Una explicación completa de los modificadores de acceso en Java se puede encontrar aquí .
¿Pero cómo interactúan con las clases internas?
public , como de costumbre, da acceso sin restricciones a cualquier ámbito capaz de acceder al
tipo.
public int x = 5;
tanto protected como el modificador predeterminado (de nada) se comportan como se espera
también, de la misma manera que lo hacen para las clases no anidadas.
https://riptutorial.com/es/home 205
private int x;
private void anInnerMethod() {}
}
La Clase Interna en sí misma puede tener una visibilidad que no sea public . Al marcarlo como
private u otro modificador de acceso restringido, otras clases (externas) no podrán importar y
asignar el tipo. Sin embargo, aún pueden obtener referencias a objetos de ese tipo.
Una clase interna anónima es una forma de clase interna que se declara y crea una instancia con
una sola declaración. Como consecuencia, no hay un nombre para la clase que pueda usarse en
otra parte del programa; Es decir, es anónimo.
Las clases anónimas se utilizan normalmente en situaciones en las que es necesario poder crear
una clase de peso ligero que se pase como parámetro. Esto normalmente se hace con una
interfaz. Por ejemplo:
https://riptutorial.com/es/home 206
Esta clase anónima define un objeto Comparator<String> ( CASE_INSENSITIVE ) que compara dos
cadenas ignorando las diferencias en el caso.
Otras interfaces que se implementan e Runnable frecuencia usando clases anónimas son Runnable
y Callable . Por ejemplo:
Las clases internas anónimas también pueden basarse en clases. En este caso, la clase anónima
extends implícitamente la clase existente. Si la clase que se está extendiendo es abstracta,
entonces la clase anónima debe implementar todos los métodos abstractos. También puede
anular métodos no abstractos.
Constructores
Una clase anónima no puede tener un constructor explícito. En su lugar, se define un constructor
implícito que usa super(...) para pasar cualquier parámetro a un constructor en la clase que se
está extendiendo. Por ejemplo:
Naturalmente, esto no funciona cuando se extiende una interfaz. Cuando creas una clase
anónima desde una interfaz, la clase superclase es java.lang.Object que solo tiene un constructor
sin argumentos.
Una clase escrita dentro de un método llamado método clase interna local . En ese caso, el
alcance de la clase interna está restringido dentro del método.
Una clase interna de método local puede instanciarse solo dentro del método donde se define la
clase interna.
https://riptutorial.com/es/home 207
El ejemplo de usar el método local de clase interna:
https://riptutorial.com/es/home 208
public void method() {
System.out.println("My counter: " + counter);
System.out.println("Outer counter: " + OuterClass.this.counter);
// updating my counter
counter = OuterClass.this.counter;
}
}
}
También se puede crear una clase interna que sea visible para cualquier clase externa a partir de
esta clase.
La clase interna depende de la clase externa y requiere una referencia a una instancia de ella.
Para crear una instancia de la clase interna, el new operador solo necesita ser llamado en una
instancia de la clase externa.
class OuterClass {
class InnerClass {
}
}
class OutsideClass {
OuterClass.InnerClass createInner() {
return outer.new InnerClass();
}
}
https://riptutorial.com/es/home 209
Capítulo 35: Clases y objetos
Introducción
Los objetos tienen estados y comportamientos. Ejemplo: Un perro tiene estados (color, nombre,
raza y comportamientos): menear la cola, ladrar, comer. Un objeto es una instancia de una clase.
Clase: una clase se puede definir como una plantilla / modelo que describe el comportamiento /
estado que admite el objeto de su tipo.
Sintaxis
• clase Ejemplo {} // clase palabra clave, nombre, cuerpo
Examples
Clase posible más simple
class TrivialClass {}
Una clase consta de un mínimo de la palabra clave de class , un nombre y un cuerpo, que pueden
estar vacíos.
class ObjectMemberVsStaticMember {
void increment() {
staticCounter ++;
memberCounter++;
}
}
https://riptutorial.com/es/home 210
o1.increment();
o2.increment();
o2.increment();
System.out.println("ObjectMemberVsStaticMember.staticCounter = " +
ObjectMemberVsStaticMember.staticCounter);
o1 static counter 3
o1 member counter 1
o2 static counter 3
o2 member counter 2
ObjectMemberVsStaticMember.staticCounter = 3
Nota: No debe llamar a miembros static en objetos, sino en clases. Si bien no hace una
diferencia para la JVM, los lectores humanos lo apreciarán.
static miembros static son parte de la clase y existen solo una vez por clase. Los miembros no
static existen en las instancias, hay una copia independiente para cada instancia. Esto también
significa que necesita acceder a un objeto de esa clase para acceder a sus miembros.
Métodos de sobrecarga
A veces, se debe escribir la misma funcionalidad para diferentes tipos de entradas. En ese
momento, uno puede usar el mismo nombre de método con un conjunto diferente de parámetros.
Cada conjunto diferente de parámetros se conoce como una firma de método. Como se ve en el
ejemplo, un solo método puede tener varias firmas.
https://riptutorial.com/es/home 211
public static void main(String[] args) {
Displayer displayer = new Displayer();
displayer.displayName("Ram"); //prints "Name is: Ram"
displayer.displayName("Jon", "Skeet"); //prints "Name is: Jon Skeet"
}
}
La ventaja es que se llama a la misma funcionalidad con dos números diferentes de entradas. Al
invocar el método de acuerdo con la entrada que estamos pasando, (en este caso, un valor de
cadena o dos valores de cadena) se ejecuta el método correspondiente.
Nota: los métodos no pueden sobrecargarse cambiando solo el tipo de retorno ( int method() se
considera el mismo que String method() y lanzará una RuntimeException si se intenta). Si cambia el
tipo de retorno, también debe cambiar los parámetros para sobrecargar.
Los objetos vienen en su propia clase, por lo que un ejemplo simple sería un automóvil
(explicaciones detalladas a continuación):
public Car(){
milesPerGallon = 0;
name = "";
color = "";
numGallonsInTank = 0;
}
https://riptutorial.com/es/home 212
//Cars need to drive
public void drive(int distanceInMiles){
//get miles left in car
int miles = numGallonsInTank * milesPerGallon;
Los objetos son instancias de su clase. Entonces, la forma en que crearía un objeto sería
llamando a la clase Car de una de las dos formas en su clase principal (método principal en
Java u onCreate en Android).
Opción 1
La opción 1 es donde esencialmente le dice al programa todo sobre el Coche al crear el objeto.
https://riptutorial.com/es/home 213
Cambiar cualquier propiedad del automóvil requeriría llamar a uno de los métodos, como el
método repaintCar . Ejemplo:
newCar.repaintCar("Blue");
Nota: asegúrese de pasar el tipo de datos correcto al método. En el ejemplo anterior, también
puede pasar una variable al método repaintCar siempre que el tipo de datos sea correcto .
La opción 1 es la mejor opción cuando tiene todos los datos del objeto en el momento de la
creación.
opcion 2
La opción 2 obtiene el mismo efecto pero requiere más trabajo para crear un objeto
correctamente. Quiero recordar a este Constructor en la clase de Automóviles:
Tenga en cuenta que no tiene que pasar ningún parámetro al objeto para crearlo. Esto es muy útil
para cuando no tiene todos los aspectos del objeto pero necesita usar las partes que tiene. Esto
establece datos genéricos en cada una de las variables de instancia del objeto, de modo que, si
solicita un dato que no existe, no se generan errores.
Nota: No olvide que debe configurar las partes del objeto más adelante con las que no lo haya
inicializado. Por ejemplo,
Este es un error común entre los objetos que no están inicializados con todos sus datos. Se
evitaron los errores porque hay un Constructor que permite que se cree un objeto de Coche vacío
con variables de apoyo ( public Car(){} ), pero ninguna parte de myCar fue realmente
personalizada. Ejemplo correcto de crear un objeto de coche:
https://riptutorial.com/es/home 214
myCar.paintCar("Purple");
myCar.setGallonsInTank(10);
myCar.setMPG(30);
Constructores
Los constructores son métodos especiales nombrados después de la clase y sin un tipo de
retorno, y se utilizan para construir objetos. Los constructores, como los métodos, pueden tomar
parámetros de entrada. Los constructores se utilizan para inicializar objetos. Las clases
abstractas también pueden tener constructores.
Es importante entender que los constructores son diferentes de los métodos de varias maneras:
1. Los constructores solo pueden tomar los modificadores public , private y protected , y no
pueden ser declarados abstract , final , static o synchronized .
3. Los constructores DEBEN tener el mismo nombre que el nombre de la clase. En el ejemplo
de Hello , el nombre del constructor del objeto Hello es el mismo que el nombre de la clase.
4. La palabra clave this tiene un uso adicional dentro de los constructores. this.method(...)
llama a un método en la instancia actual, mientras que this(...) refiere a otro constructor en
la clase actual con diferentes firmas.
A los constructores también se les puede llamar por herencia usando la palabra clave super .
public SuperManClass(){
// some implementation
}
// ... methods
}
https://riptutorial.com/es/home 215
public class BatmanClass extends SupermanClass{
public BatmanClass(){
super();
}
//... methods...
}
Para inicializar campos static final que requieren el uso de más de una expresión, se puede
usar un inicializador static para asignar el valor. El siguiente ejemplo inicializa un conjunto no
modificable de String s:
static {
Set<String> set = new HashSet<>();
set.add("Hello");
set.add("World");
set.add("foo");
set.add("bar");
set.add("42");
WORDS = Collections.unmodifiableSet(set);
}
}
El método de anulación y sobrecarga son dos formas de polimorfismo soportado por Java.
Método de sobrecarga
La sobrecarga de métodos (también conocida como Polimorfismo estático) es una forma en que
puede tener dos (o más) métodos (funciones) con el mismo nombre en una sola clase. Sí, es tan
simple como eso.
https://riptutorial.com/es/home 216
}
}
De esta manera, el usuario puede llamar al mismo método para el área dependiendo del tipo de
forma que tenga.
Pero la pregunta real ahora es, ¿cómo distinguirá el compilador Java qué cuerpo del método se
ejecutará?
Bueno, Java ha dejado claro que aunque los nombres de los métodos ( area() en nuestro caso)
pueden ser iguales, el método de los argumentos debe ser diferente.
Dicho esto, no podemos agregar otro método para calcular el área de un cuadrado como este:
public Double area(Long side) porque, en este caso, entrará en conflicto con el método del círculo
del área y causará ambigüedad para el compilador Java.
Bueno, eso se debe a que los métodos sobrecargados que se van a invocar se deciden en el
momento de la compilación, según el número real de argumentos y los tipos de tiempo de
compilación de los argumentos.
Método Anulando
Bueno, el método de anulación (sí, supongo que es correcto, también se conoce como
https://riptutorial.com/es/home 217
polimorfismo dinámico) es un tema algo más interesante y complejo.
Así que tenemos una clase llamada Forma y tiene un método llamado área que probablemente
devolverá el área de la forma.
// See this annotation @Override, it is telling that this method is from parent
// class Shape and is overridden here
@Override
public Double area(){
return 3.14 * radius * radius;
}
}
// See this annotation @Override, it is telling that this method is from parent
// class Shape and is overridden here
@Override
public Double area(){
return length * breadth;
}
}
Entonces, ahora las dos clases de sus hijos tienen el cuerpo del método actualizado
proporcionado por la clase principal ( Shape ). Ahora la pregunta es ¿cómo ver el resultado?
Bueno, psvm la vieja psvm .
https://riptutorial.com/es/home 218
// Drumbeats ......
//This should print 78.5
System.out.println("Shape of circle : "+circle.area());
}
}
¡Guauu! no es genial? Dos objetos del mismo tipo que llaman a los mismos métodos y devuelven
valores diferentes. Mi amigo, ese es el poder del polimorfismo dinámico.
Aquí hay una tabla para comparar mejor las diferencias entre estos dos:
https://riptutorial.com/es/home 219
Capítulo 36: Clonación de objetos
Observaciones
La clonación puede ser complicada, especialmente cuando los campos del objeto contienen otros
objetos. Hay situaciones en las que desea realizar una copia profunda , en lugar de copiar solo
los valores de campo (es decir, referencias a los otros objetos).
La conclusión es que la copia está rota , y debe pensarlo dos veces antes de implementar la
interfaz Cloneable y anular el método de clone . El método de clone se declara en la clase Object y
no en la interfaz Cloneable , por lo que Cloneable no funciona como interfaz porque carece de un
método de clone público. El resultado es que el contrato para usar el clone está escasamente
documentado y se aplica de manera débil. Por ejemplo, una clase que anula la clone veces
depende de todas sus clases primarias y también anula la clone . No están obligados a hacerlo, y
si no lo hacen, su código puede generar excepciones.
Examples
Clonación utilizando un constructor de copia.
// copy constructor
// copies the fields of other into the new object
public Sheep(Sheep other) {
this.name = other.name;
this.weight = other.weight;
}
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// clone the sheep
Sheep dolly = new Sheep(sheep); // dolly.name is "Dolly" and dolly.weight is 20
https://riptutorial.com/es/home 220
Clonación implementando la interfaz clonable
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// clone the sheep
Sheep dolly = (Sheep) sheep.clone(); // dolly.name is "Dolly" and dolly.weight is 20
import java.util.List;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
https://riptutorial.com/es/home 221
}
import java.util.Arrays;
import java.util.List;
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// create children
Sheep child1 = new Sheep("Child1", 4);
Sheep child2 = new Sheep("Child2", 5);
sheep.setChildren(Arrays.asList(child1, child2));
Para copiar objetos anidados, se debe realizar una copia profunda , como se muestra en este
ejemplo.
import java.util.ArrayList;
import java.util.List;
@Override
public Object clone() throws CloneNotSupportedException {
Sheep clone = (Sheep) super.clone();
if (children != null) {
// make a deep copy of the children
List<Sheep> cloneChildren = new ArrayList<>(children.size());
for (Sheep child : children) {
cloneChildren.add((Sheep) child.clone());
}
https://riptutorial.com/es/home 222
clone.setChildren(cloneChildren);
}
return clone;
}
import java.util.Arrays;
import java.util.List;
// create a sheep
Sheep sheep = new Sheep("Dolly", 20);
// create children
Sheep child1 = new Sheep("Child1", 4);
Sheep child2 = new Sheep("Child2", 5);
sheep.setChildren(Arrays.asList(child1, child2));
https://riptutorial.com/es/home 223
Capítulo 37: Codificación de caracteres
Examples
Leyendo texto de un archivo codificado en UTF-8
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
String line;
while ((line = reader.readLine()) != null) {
System.out.print(line);
}
}
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
https://riptutorial.com/es/home 224
wr.write("Cyrillic symbol Ы");
}
}
}
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
System.out.println(Arrays.toString(textInUtf8));
}
}
https://riptutorial.com/es/home 225
Capítulo 38: Código oficial de Oracle
estándar
Introducción
La guía de estilo oficial de Oracle para el lenguaje de programación Java es un estándar seguido
por los desarrolladores de Oracle y se recomienda que sea seguido por cualquier otro
desarrollador de Java. Cubre nombres de archivos, organización de archivos, sangría,
comentarios, declaraciones, declaraciones, espacios en blanco, convenciones de nomenclatura,
prácticas de programación e incluye un ejemplo de código.
Observaciones
• Los ejemplos anteriores siguen estrictamente la nueva guía de estilo oficial de Oracle. En
otras palabras, no están constituidos subjetivamente por los autores de esta página.
• La guía de estilo oficial se ha escrito cuidadosamente para que sea compatible con la guía
de estilo original y con la mayoría de los códigos en libertad.
• La guía oficial de estilo ha sido pares revisado por, entre otros, Brian Goetz (lenguaje Java
Architect) y Mark Reinhold (Arquitecto Jefe de la Plataforma Java).
• Los ejemplos no son normativos; Si bien pretenden ilustrar la forma correcta de formatear el
código, puede haber otras formas de formatear el código correctamente. Este es un
principio general: puede haber varias formas de formatear el código, todas de acuerdo con
las pautas oficiales.
Examples
Convenciones de nombres
Nombres de paquetes
• Los nombres de los paquetes deben estar en minúsculas sin guiones bajos u otros
caracteres especiales.
• Los nombres de los paquetes comienzan con la parte de autoridad anulada de la dirección
web de la empresa del desarrollador. Esta parte puede ser seguida por una subestructura
de paquete dependiente de la estructura del proyecto / programa.
• No utilice la forma plural. Siga la convención de la API estándar que utiliza, por ejemplo,
java.lang.annotation y no java.lang.annotations .
• Ejemplos: com.yourcompany.widget.button , com.yourcompany.core.api
https://riptutorial.com/es/home 226
Clase, Interfaz y Nombres Enum
• Los nombres de clase y enumeración deben ser nombres.
• Los nombres de las interfaces normalmente deben ser sustantivos o adjetivos que terminen
con ... capaces.
• Use mayúsculas y minúsculas con la primera letra de cada palabra en mayúsculas (es decir,
CamelCase ).
• Empareja la expresión regular ^[AZ][a-zA-Z0-9]*$ .
• Use palabras completas y evite usar abreviaturas a menos que la abreviatura se use más
ampliamente que la forma larga.
• Formatee una abreviatura como una palabra si es parte de un nombre de clase más largo.
• Ejemplos: ArrayList , BigInteger , ArrayIndexOutOfBoundsException , Iterable .
Variables
Los nombres de las variables deben estar en mayúsculas y minúsculas con la primera letra en
minúscula
Variables de tipo
Para casos simples donde hay pocas variables de tipo involucradas, use una sola letra
mayúscula.
https://riptutorial.com/es/home 227
Constantes
Las constantes (campos static final cuyo contenido es inmutable, por reglas de idioma o por
convención) deben nombrarse con todas las letras mayúsculas y el subrayado ( _ ) para separar
las palabras.
• Todas las líneas deben terminarse con un carácter de avance de línea (LF, valor ASCII 10)
y no, por ejemplo, CR o CR + LF.
• El nombre de un archivo de origen debe ser igual al nombre de la clase que contiene,
seguido de la extensión .java , incluso para los archivos que solo contienen una clase
privada de paquete. Esto no se aplica a los archivos que no contienen ninguna declaración
de clase, como package-info.java .
Caracteres especiales
• Aparte de LF, el único carácter de espacio en blanco permitido es el espacio (valor ASCII
32). Tenga en cuenta que esto implica que otros caracteres de espacios en blanco (en, por
ejemplo, literales de cadenas y caracteres) deben escribirse en forma de escape.
• En caso de que sea necesario ir en contra de las reglas anteriores por el bien de la prueba,
la prueba debe generar la entrada requerida programáticamente.
https://riptutorial.com/es/home 228
package com.example.my.package;
Declaraciones de importación
Importaciones de comodines
• En general, las importaciones de comodines no deben utilizarse.
• Cuando se importa una gran cantidad de clases estrechamente relacionadas (como la
implementación de un visitante en un árbol con docenas de clases distintas de "nodos"), se
puede usar una importación de comodines.
• En cualquier caso, no se debe utilizar más de una importación de comodines por archivo.
Estructura de clase
https://riptutorial.com/es/home 229
Los miembros de la clase deben ordenarse de la siguiente manera:
class Example {
private int i;
Example(int i) {
this.i = i;
}
@Override
public String toString() {
return "An example [" + i + "]";
}
Modificadores
class ExampleClass {
// Access modifiers first (don't do for instance "static public")
public static void main(String[] args) {
System.out.println("Hello World");
}
}
https://riptutorial.com/es/home 230
interface ExampleInterface {
// Avoid 'public' and 'abstract' since they are implicit
void sayHello();
}
• Los modificadores no deben escribirse cuando están implícitos. Por ejemplo, los métodos de
interfaz no deben declararse public ni abstract , y las enums e interfaces anidadas no deben
declararse estáticas.
• Los parámetros del método y las variables locales no deben declararse final menos que
mejore la legibilidad o documente una decisión de diseño real.
• Los campos deben declararse final menos que haya una razón convincente para hacerlos
mutables.
Sangría
switch (var) {
case TWO:
setChoice("two");
break;
case THREE:
setChoice("three");
break;
default:
throw new IllegalArgumentException();
}
Consulte las instrucciones de ajuste para obtener instrucciones sobre cómo sangrar líneas de
continuación.
Envolver declaraciones
https://riptutorial.com/es/home 231
• El código fuente y los comentarios generalmente no deben exceder los 80 caracteres por
línea y rara vez, si alguna vez, exceden los 100 caracteres por línea, incluida la sangría.
El límite de caracteres se debe juzgar caso por caso. Lo que realmente importa es la
"densidad" semántica y la legibilidad de la línea. Hacer líneas gratuitamente largas las hace
difíciles de leer; de manera similar, hacer "intentos heroicos" para encajarlos en 80
columnas también puede hacer que sean difíciles de leer. La flexibilidad descrita aquí
apunta a permitir a los desarrolladores evitar estos extremos, no maximizar el uso del
monitor de bienes raíces.
// Wrapping preferable
String pretty = Stream.of(args)
.map(Argument::prettyPrint)
.collectors(joining(", "));
• Se prefiere envolver en un nivel sintáctico más alto que envolver en un nivel sintáctico más
bajo.
• Una línea de continuación debe estar sangrada de una de las siguientes cuatro formas
https://riptutorial.com/es/home 232
Set<Number> aSet,
double aDouble) {
…
}
Expresiones de envoltura
Espacio en blanco
https://riptutorial.com/es/home 233
○ Declaraciones de clase
○ Constructores
○ Métodos
○ Inicializadores estáticos
○ Inicializadores de instancia
○ declaraciones de importación
○ campos
○ declaraciones
• Múltiples líneas en blanco consecutivas solo deben usarse para separar grupos de
miembros relacionados y no como el espaciado entre miembros estándar.
Declaraciones Variables
• Una variable por declaración (y como máximo una declaración por línea)
• Los corchetes de las matrices deben estar en el tipo ( String[] args ) y no en la variable (
String args[] ).
• Declare una variable local justo antes de usarla por primera vez e inicialícela lo más cerca
posible de la declaración.
Anotaciones
Las anotaciones de la declaración deben colocarse en una línea separada de la declaración que
se está anotando.
@SuppressWarnings("unchecked")
public T[] toArray(T[] typeHolder) {
...
}
https://riptutorial.com/es/home 234
Sin embargo, pocas anotaciones o anotaciones cortas que anotan un método de una sola línea se
pueden colocar en la misma línea que el método si mejora la legibilidad. Por ejemplo, uno puede
escribir:
Por cuestiones de coherencia y legibilidad, todas las anotaciones deben colocarse en la misma
línea o cada anotación debe colocarse en una línea separada.
// Bad.
@Deprecated @SafeVarargs
@CustomAnnotation
public final Tuple<T> extend(T... elements) {
...
}
// Even worse.
@Deprecated @SafeVarargs
@CustomAnnotation public final Tuple<T> extend(T... elements) {
...
}
// Good.
@Deprecated
@SafeVarargs
@CustomAnnotation
public final Tuple<T> extend(T... elements) {
...
}
// Good.
@Deprecated @SafeVarargs @CustomAnnotation
public final Tuple<T> extend(T... elements) {
...
}
Expresiones lambda
• Las lambdas de expresión se prefieren a las lambdas de bloque de una sola línea.
• Las referencias a los métodos generalmente deben preferirse a las expresiones lambda.
• Para referencias de métodos de instancia unida, o métodos con una aridad mayor que uno,
una expresión lambda puede ser más fácil de entender y, por lo tanto, preferible.
Especialmente si el comportamiento del método no está claro en el contexto.
https://riptutorial.com/es/home 235
• Los tipos de parámetros deben omitirse a menos que mejoren la legibilidad.
• Si una expresión lambda se extiende sobre más de unas pocas líneas, considere crear un
método.
Paréntesis redundantes
// Don't do this
return (flag ? "yes" : "no");
• Se pueden usar paréntesis de agrupación redundantes (es decir, paréntesis que no afectan
la evaluación) si mejoran la legibilidad.
• Los paréntesis de agrupación redundantes normalmente se deben omitir en expresiones
más cortas que involucren operadores comunes, pero se deben incluir en expresiones más
largas o que involucren operadores cuya prioridad y asociatividad no estén claras sin
paréntesis. Las expresiones ternarias con condiciones no triviales pertenecen a esta última.
• La expresión completa que sigue a una palabra clave de return no debe estar entre
paréntesis.
Literales
long l = 5432L;
int i = 0x123 + 0xABC;
byte b = 0b1010;
float f1 = 1 / 5432f;
float f2 = 0.123e4f;
double d1 = 1 / 5432d; // or 1 / 5432.0
double d2 = 0x1.3p2;
Tirantes
class Example {
void method(boolean error) {
if (error) {
Log.error("Error occurred!");
System.out.println("Error!");
} else { // Use braces since the other block uses braces.
System.out.println("No error");
}
}
}
• Las llaves de apertura deben colocarse en el final de la línea actual en lugar de en una línea
por sí sola.
https://riptutorial.com/es/home 236
• Debería haber una nueva línea delante de una abrazadera de cierre, a menos que el bloque
esté vacío (vea las formas cortas a continuación)
• Los frenos se recomiendan incluso cuando el lenguaje los hace opcionales, como los
cuerpos de bucle y de una sola línea.
○ Si un bloque abarca más de una línea (incluidos los comentarios) debe tener llaves.
○ Si uno de los bloques en una sentencia if / else tiene llaves, el otro bloque también
debe hacerlo.
○ Si el bloque es el último en un bloque adjunto, debe tener llaves.
• La palabra clave else , catch y while en do…while bucles van en la misma línea que la llave de
cierre del bloque anterior.
Formas cortas
enum Response { YES, NO, MAYBE }
public boolean isReference() { return true; }
https://riptutorial.com/es/home 237
Capítulo 39: Colas y deques
Examples
El uso de la PriorityQueue
PriorityQueue es una estructura de datos. Al igual que SortedSet , PriorityQueue también clasifica
sus elementos según sus prioridades. Los elementos, que tienen una prioridad más alta, vienen
primero. El tipo de PriorityQueue debe implementar comparable interfaz comparable o de comparator ,
cuyos métodos deciden las prioridades de los elementos de la estructura de datos.
//The PriorityQueue sorts the elements by using compareTo method of the Integer Class
//The head of this queue is the least element with respect to the specified ordering
System.out.println( queue ); //The Output: [1, 2, 3, 9, 3, 8]
queue.remove();
System.out.println( queue ); //The Output: [2, 3, 3, 9, 8]
queue.remove();
System.out.println( queue ); //The Output: [3, 8, 3, 9]
queue.remove();
System.out.println( queue ); //The Output: [3, 8, 9]
queue.remove();
System.out.println( queue ); //The Output: [8, 9]
queue.remove();
System.out.println( queue ); //The Output: [9]
queue.remove();
System.out.println( queue ); //The Output: []
En el siguiente ejemplo, con el método offer() , los elementos se insertan en LinkedList . Esta
operación de inserción se llama enqueue . En el while bucle a continuación, los elementos se
eliminan de la Queue sobre la base de FIFO. Esta operación se llama dequeue .
https://riptutorial.com/es/home 238
while ( !queue.isEmpty() ) {
System.out.println( queue.poll() );
}
first element
second element
third element
fourth element
fifth element
Pilas
API de pila
Java contiene una API de pila con los siguientes métodos
Ejemplo
import java.util.*;
st.push(10);
System.out.println("10 was pushed to the stack");
System.out.println("stack: " + st);
st.push(15);
System.out.println("15 was pushed to the stack");
System.out.println("stack: " + st);
https://riptutorial.com/es/home 239
st.push(80);
System.out.println("80 was pushed to the stack");
System.out.println("stack: " + st);
st.pop();
System.out.println("80 was popped from the stack");
System.out.println("stack: " + st);
st.pop();
System.out.println("15 was popped from the stack");
System.out.println("stack: " + st);
st.pop();
System.out.println("10 was popped from the stack");
System.out.println("stack: " + st);
if(st.isEmpty())
{
System.out.println("empty stack");
}
}
}
Esto devuelve:
stack: []
10 was pushed to the stack
stack: [10]
15 was pushed to the stack
stack: [10, 15]
80 was pushed to the stack
stack: [10, 15, 80]
80 was popped from the stack
stack: [10, 15]
15 was popped from the stack
stack: [10]
10 was popped from the stack
stack: []
empty stack
BlockingQueue
Un BlockingQueue es una interfaz, que es una cola que se bloquea cuando intenta salir de la cola
y la cola está vacía, o si intenta poner en cola elementos en ella y la cola ya está llena. Se
bloquea un subproceso que intenta salir de una cola vacía hasta que otro subproceso inserta un
elemento en la cola. Un subproceso que intenta poner en cola un elemento en una cola completa
se bloquea hasta que algún otro subproceso haga espacio en la cola, ya sea retirando uno o más
elementos o eliminando la cola por completo.
Los métodos de BlockingQueue vienen en cuatro formas, con diferentes formas de manejar las
operaciones que no pueden satisfacerse inmediatamente, pero que pueden satisfacerse en algún
momento en el futuro: uno lanza una excepción, el segundo devuelve un valor especial (ya sea
nulo o falso, dependiendo de la operación), el tercero bloquea el subproceso actual
indefinidamente hasta que la operación pueda tener éxito, y el cuarto bloquea solo un límite de
tiempo máximo dado antes de rendirse.
https://riptutorial.com/es/home 240
Operación Lanza la excepción Valor especial Bloques Se acabó el tiempo
Insertar añadir() oferta (e) poner (e) oferta (e, tiempo, unidad)
BlockingQueue<String> bQueue = new ArrayBlockingQueue<String>(2);
Una cola ilimitada es aquella que se inicializa sin capacidad, de hecho, de forma predeterminada,
se inicializa con Integer.MAX_VALUE.
1. ArrayBlockingQueue
2. LinkedBlockingQueue
3. PriorityBlockingQueue
Esto imprimirá:
Interfaz de cola
Lo esencial
Una Queue es una colección para contener elementos antes del procesamiento. Las colas
normalmente, pero no necesariamente, ordenan los elementos de una manera FIFO (primero en
https://riptutorial.com/es/home 241
entrar, primero en salir).
El encabezado de la cola es el elemento que se eliminaría con una llamada para eliminar o
sondear. En una cola FIFO, todos los elementos nuevos se insertan en la cola de la cola.
La interfaz de cola
E remove();
E poll();
E element();
E peek();
}
Deque
Un Deque es una "cola de doble finalización", lo que significa que se pueden agregar elementos en
la parte delantera o en la cola de la cola. La cola solo puede agregar elementos a la cola de una
cola.
Dequehereda la interfaz de la Queue , lo que significa que los métodos regulares permanecen, sin
embargo, la interfaz de Deque ofrece métodos adicionales para ser más flexible con una cola. Los
métodos adicionales realmente hablan por sí mismos si sabes cómo funciona una cola, ya que
esos métodos están destinados a agregar más flexibilidad:
https://riptutorial.com/es/home 242
Método Breve descripción
Por supuesto las mismas opciones para offer , poll y peek están disponibles, sin embargo, no
funcionan con excepciones, sino más bien con los valores especiales. No tiene sentido mostrar lo
que hacen aquí.
Puede echar un vistazo al elemento que se encuentra al principio de la cola sin sacar el elemento
de la cola. Esto se hace a través del método element() . También puede usar los getFirst() y
getLast() , que devuelven el primer y último elemento en el Deque . Aquí es cómo se ve:
Removiendo elementos
Para eliminar elementos de un deque, debe llamar a los métodos remove() , removeFirst() y
removeLast() . Aquí están algunos ejemplos:
https://riptutorial.com/es/home 243
Capítulo 40: Colecciones
Introducción
El marco de colecciones en java.util proporciona una serie de clases genéricas para conjuntos
de datos con una funcionalidad que no pueden ser proporcionadas por matrices regulares.
Observaciones
Las colecciones son objetos que pueden almacenar colecciones de otros objetos dentro de ellos.
Puede especificar el tipo de datos almacenados en una colección usando Genéricos .
Java SE 1.4
Java 1.4.2 y versiones anteriores no son compatibles con los genéricos. Como tal, no puede
especificar los parámetros de tipo que contiene una colección. Además de no tener seguridad de
tipo, también debe usar moldes para recuperar el tipo correcto de una colección.
Además de la Collection<E> , hay varios tipos principales de colecciones, algunas de las cuales
tienen subtipos.
Java SE 5
Java SE 6
https://riptutorial.com/es/home 244
• NavigableSet<E> es un Set<E> con métodos de navegación especiales integrados.
• NavigableMap<K,V> es un Map<K,V> con métodos de navegación especiales integrados.
• Deque<E> es una Queue<E> que puede leerse desde cualquier extremo.
Tenga en cuenta que los elementos anteriores son todas las interfaces. Para utilizarlos, debe
encontrar las clases de implementación adecuadas, como ArrayList , HashSet , HashMap o
PriorityQueue .
Cada tipo de colección tiene implementaciones múltiples que tienen diferentes métricas de
rendimiento y casos de uso.
Tenga en cuenta que el principio de sustitución de Liskov se aplica a los subtipos de colección. Es
decir, se puede pasar un SortedSet<E> a una función que espera un Set<E> . También es útil leer
sobre Parámetros delimitados en la sección Genéricos para obtener más información sobre cómo
usar colecciones con herencia de clase.
Si desea crear sus propias colecciones, puede ser más fácil heredar una de las clases abstractas
(como AbstractList ) en lugar de implementar la interfaz.
Java SE 1.2
Antes de la versión 1.2, tenías que usar las siguientes clases / interfaces en su lugar:
• lugar de ArrayList
Vector
• Dictionary lugar de Map . Tenga en cuenta que el diccionario también es una clase abstracta
en lugar de una interfaz.
• Hashtable lugar de HashMap
Examples
Declarar una ArrayList y agregar objetos
Java SE 5
Java SE 7
aListOfFruits.add("Melon");
https://riptutorial.com/es/home 245
aListOfFruits.add("Strawberry");
También podemos agregar varios elementos con el método addAll(Collection<? extends E> c)
Colecciones estandar
Marco de Colecciones Java
Una forma sencilla de construir una List partir de valores de datos individuales es usar el método
de Arrays.asList java.utils.Arrays :
Todas las implementaciones de colección estándar proporcionan constructores que toman otra
colección como un argumento que agrega todos los elementos a la nueva colección en el
momento de la construcción:
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
...
List<String> list1 = Lists.newArrayList("ab", "bc", "cd");
List<String> list2 = Lists.newArrayList(data);
https://riptutorial.com/es/home 246
Set<String> set4 = Sets.newHashSet(data);
SortedSet<String> set5 = Sets.newTreeSet("bc", "cd", "ab", "bc", "cd");
Mapeo de Colecciones
Marco de Colecciones Java
De manera similar, para los mapas, dado un Map<String, Object> map se puede construir un nuevo
mapa con todos los elementos de la siguiente manera:
import org.apache.commons.lang3.ArrayUtils;
...
// Taken from org.apache.commons.lang.ArrayUtils#toMap JavaDoc
Cada elemento de la matriz debe ser Map.Entry o Array, que contenga al menos dos elementos,
donde el primer elemento se utiliza como clave y el segundo como valor.
import com.google.common.collect.Maps;
...
void howToCreateMapsMethod(Function<? super K,V> valueFunction,
Iterable<K> keys1,
Set<K> keys2,
SortedSet<K> keys3) {
ImmutableMap<K, V> map1 = toMap(keys1, valueFunction); // Immutable copy
Map<K, V> map2 = asMap(keys2, valueFunction); // Live Map view
SortedMap<K, V> map3 = toMap(keys3, valueFunction); // Live Map view
}
Java SE 8
Utilizando Stream ,
https://riptutorial.com/es/home 247
Stream.of("xyz", "abc").collect(Collectors.toList());
Arrays.stream("xyz", "abc").collect(Collectors.toList());
Unir listas
Se pueden utilizar las siguientes formas para unir listas sin modificar la (s) lista (s) de origen.
ListUtils.union(listOne,listTwo);
Java SE 8
Es difícil eliminar elementos de una lista mientras se encuentra dentro de un bucle, esto se debe
al hecho de que el índice y la longitud de la lista se modifican.
Dada la siguiente lista, aquí hay algunos ejemplos que darán un resultado inesperado y otros que
darán el resultado correcto.
https://riptutorial.com/es/home 248
INCORRECTO
Extracción de iteración de for declaración Omite "Banana":
El ejemplo de código solo imprimirá Apple y Strawberry . Banana se omite porque se mueve al índice
0 vez Apple se elimina, pero, al mismo tiempo i se incrementa a 1 .
Emite: java.util.ConcurrentModificationException
CORRECTO
Eliminando en bucle while usando un Iterator
La interfaz Iterator tiene un método remove() incorporado solo para este caso. Sin embargo, este
método está marcado como "opcional" en la documentación y podría generar una
UnsupportedOperationException .
https://riptutorial.com/es/home 249
compatible con este iterador
Por lo tanto, es recomendable consultar la documentación para asegurarse de que esta operación
sea compatible (en la práctica, a menos que la recopilación sea una inmutable obtenida a través
de una biblioteca de terceros o el uso de uno de los métodos Collections.unmodifiable...() , la
operación es casi siempre soportada).
Un modCount es una variable int que cuenta el número de veces que esta lista ha sido modificada
estructuralmente. Un cambio estructural significa esencialmente una operación add() o remove()
que se invoca en el objeto Collection (los cambios realizados por Iterator no se cuentan).
Cuando se crea el Iterator , almacena este modCount y en cada iteración de la List comprueba si
el modCount actual es el mismo que cuando se creó el Iterator . Si hay un cambio en el valor de
modCount , lanza una ConcurrentModificationException .
Por lo tanto, para la lista declarada anteriormente, una operación como la siguiente no arrojará
ninguna excepción:
Pero agregar un nuevo elemento a la List después de inicializar un Iterator lanzará una
ConcurrentModificationException :
Esto no se salta nada. La desventaja de este enfoque es que la salida es inversa. Sin embargo,
en la mayoría de los casos, elimina elementos que no importan. Nunca debes hacer esto con
LinkedList .
https://riptutorial.com/es/home 250
Iterando hacia adelante, ajustando el índice de bucle.
Esta solución permite al desarrollador verificar si los elementos correctos se eliminan de forma
más limpia.
Java SE 8
En Java 8 son posibles las siguientes alternativas. Estos son más limpios y más directos si la
eliminación no tiene que suceder en un bucle.
List<String> filteredList =
fruits.stream().filter(p -> !"Apple".equals(p)).collect(Collectors.toList());
Tenga en cuenta que a diferencia de todos los otros ejemplos aquí, este ejemplo produce una
nueva instancia de List y mantiene la List original sin cambios.
Utilizando removeIf
Ahorra la sobrecarga de construir un flujo si todo lo que se necesita es eliminar un conjunto de
elementos.
https://riptutorial.com/es/home 251
fruits.removeIf(p -> "Apple".equals(p));
Colección no modificable
A veces no es una buena práctica exponer una colección interna, ya que puede provocar una
vulnerabilidad de código malicioso debido a su característica mutable. Para proporcionar
colecciones de "solo lectura", java proporciona sus versiones no modificables.
Una colección no modificable es a menudo una copia de una colección modificable que garantiza
que la colección en sí no puede ser alterada. Los intentos de modificarlo darán como resultado
una excepción UnsupportedOperationException.
Es importante notar que los objetos que están presentes dentro de la colección todavía pueden
ser alterados.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.List;
salida:
https://riptutorial.com/es/home 252
Iterando sobre la lista
List<String> names = new ArrayList<>(Arrays.asList("Clementine", "Duran", "Mike"));
Java SE 8
names.forEach(System.out::println);
names.parallelStream().forEach(System.out::println);
Java SE 5
Java SE 5
Java SE 1.2
//Iterates list in backward direction once reaches the last element from above iterator in
forward direction
while(listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
Java SE 8
names.forEach(System.out::println);
Java SE 5
https://riptutorial.com/es/home 253
for (Iterator<String> iterator = names.iterator(); iterator.hasNext(); ) {
System.out.println(iterator.next());
}
Java SE 5
Java SE 8
names.forEach((key, value) -> System.out.println("Key: " + key + " Value: " + value));
Java SE 5
Java SE 5
https://riptutorial.com/es/home 254
A veces es apropiado utilizar una colección vacía inmutable. La clase Collections proporciona
métodos para obtener dichas colecciones de una manera eficiente:
Estos métodos son genéricos y convertirán automáticamente la colección devuelta al tipo al que
está asignado. Es decir, se puede asignar una invocación de, por ejemplo, emptyList() a cualquier
tipo de List y de la misma manera para emptySet() y emptyMap() .
Las colecciones devueltas por estos métodos son inmutables, ya que lanzarán la
UnsupportedOperationException si intenta llamar a métodos que cambiarían su contenido ( add , put ,
etc.). Estas colecciones son útiles principalmente como sustitutos de resultados de métodos
vacíos u otros valores predeterminados, en lugar de usar null o crear objetos con new .
Las colecciones en Java solo funcionan para objetos. Es decir, no hay Map<int, int> en Java. En
su lugar, los valores primitivos deben encuadrarse en objetos, como en el Map<Integer, Integer> .
Java auto-boxing permitirá el uso transparente de estas colecciones:
Existen varias bibliotecas con colecciones optimizadas para tipos de datos primitivos (que
requieren solo ~ 16 bytes por entrada con una carga del 50%, es decir, 4 veces menos memoria,
y un nivel de direccionamiento indirecto menos), que pueden proporcionar beneficios sustanciales
de rendimiento cuando se utilizan grandes colecciones de primitivos Valores en Java.
Más arriba noté un ejemplo para eliminar elementos de una lista dentro de un bucle y pensé en
otro ejemplo que podría ser útil esta vez usando la interfaz del Iterator .
Esta es una demostración de un truco que puede ser útil cuando se trata de elementos duplicados
en listas de las que desea deshacerse.
Nota: Esto solo se agrega a la eliminación de elementos de una lista dentro de un ejemplo de
bucle :
https://riptutorial.com/es/home 255
Así que definamos nuestras listas como de costumbre.
El siguiente método toma dos objetos de la Colección y realiza la magia de eliminar los elementos
de nuestra removeNameList que coinciden con los elementos de nameList .
Lista de matrices antes de eliminar nombres: James Smith Sonny Huckle Berry Finn
Allan
Lista de matrices después de eliminar nombres: James Smith Finn Allan
Un uso simple y simple para colecciones que puede ser útil para eliminar elementos que se
repiten en las listas.
Creando su propia estructura de Iterable para usar con Iterator o para cada
bucle.
Para asegurarnos de que nuestra colección pueda iterarse utilizando iterador o para cada bucle,
debemos seguir los siguientes pasos:
A continuación, agregué una implementación de lista vinculada genérica simple que utiliza las
entidades anteriores para hacer que la lista vinculada sea iterable.
https://riptutorial.com/es/home 256
package org.algorithms.linkedlist;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class LinkedList<T> implements Iterable<T> {
Node<T> head, current;
private static class Node<T> {
T data;
Node<T> next;
Node(T data) {
this.data = data;
}
}
public LinkedList(T data) {
head = new Node<>(data);
}
public Iterator<T> iterator() {
return new LinkedListIterator();
}
private class LinkedListIterator implements Iterator<T> {
Node<T> node = head;
@Override
public boolean hasNext() {
return node != null;
}
@Override
public T next() {
if (!hasNext())
throw new NoSuchElementException();
Node<T> prevNode = node;
node = node.next;
return prevNode.data;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Removal logic not implemented.");
}
}
public void add(T data) {
Node current = head;
while (current.next != null)
current = current.next;
current.next = new Node<>(data);
}
}
class App {
https://riptutorial.com/es/home 257
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>(1);
list.add(2);
list.add(4);
list.add(3);
//Test #1
System.out.println("using Iterator:");
Iterator<Integer> itr = list.iterator();
while (itr.hasNext()) {
Integer i = itr.next();
System.out.print(i + " ");
}
//Test #2
System.out.println("\n\nusing for-each:");
for (Integer data : list) {
System.out.print(data + " ");
}
}
}
Salida
using Iterator:
1 2 4 3
using for-each:
1 2 4 3
Esto se ejecutará en Java 7+. Puede hacer que se ejecute en Java 5 y Java 6 también
sustituyendo:
con
Esta excepción se produce cuando se modifica una colección al iterar sobre ella utilizando
métodos distintos a los proporcionados por el objeto iterador. Por ejemplo, tenemos una lista de
sombreros y queremos eliminar todos aquellos que tienen orejeras:
https://riptutorial.com/es/home 258
}
}
Sub Colecciones
Ejemplo:
Salida:
Antes de Sublist [Hello1, Hello2]
Después de cambios de lista [Hello1, Hello3, Hello2]
https://riptutorial.com/es/home 259
Set set = new TreeSet();
Set set1 = set.subSet(fromIndex,toIndex);
Si fromKey es mayor que toKey o si este mapa en sí tiene un rango restringido, y fromKey o
toKey se encuentra fuera de los límites del rango, arroja IllegalArgumentException.
Todas las colecciones admiten colecciones respaldadas significa que los cambios realizados en la
sub colección tendrán el mismo cambio en la colección principal.
https://riptutorial.com/es/home 260
Capítulo 41: Colecciones alternativas
Observaciones
Este tema sobre las colecciones de Java de guava, apache, eclipse: Multiset, Bag, Multimap, utils
funciona desde esta biblioteca y así sucesivamente.
Examples
Apache HashBag, Guava HashMultiset y Eclipse HashBag
Una Bolsa / ultiset almacena cada objeto en la colección junto con un conteo de ocurrencias. Los
métodos adicionales en la interfaz permiten agregar o eliminar varias copias de un objeto a la vez.
JDK analógico es HashMap <T, Integer>, cuando los valores son el número de copias de esta
clave.
Colecciones Apache
Tipo Guayaba Colecciones GS JDK
Commons
Orden no
HashMultiset HashBag HashBag HashMa
definida
Orden de
LinkedHashMultiset - - LinkedH
insercion
Variante
ConcurrentHashMultiset Bolsa sincronizada Bolsa sincronizada Collecti
concurrente
Concurrentes
- SynchronizedSortedBag SynchronizedSortedBag Collecti
y ordenados
Colección
ImmutableMultiset UnmodifiableBag UnmodifiableBag Collecti
inmutable
Inmutable y Collecti
InmutableSortedMultiset UnmodifiableSortedBag UnmodifiableSortedBag
ordenado. )
Ejemplos :
https://riptutorial.com/es/home 261
// Create Multiset
Bag bag = SynchronizedSortedBag.synchronizedBag(new
TreeBag(Arrays.asList(INPUT_TEXT.split(" "))));
https://riptutorial.com/es/home 262
Multiset<String> multiset = LinkedHashMultiset.create(Arrays.asList(INPUT_TEXT.split("
")));
Más ejemplos:
I. Colección Apache:
III. Guayaba
Este multimapa permite duplicar pares clave-valor. Los análogos de JDK son HashMap <K, List>,
HashMap <K, Set> y así sucesivamente.
https://riptutorial.com/es/home 263
Orden Orden Tecla Valor
Duplicar Guayaba apache
de llaves del valor analógica analógico
no Orden de Lista de
sí HashMap ArrayListMultimap MultiValu
definida insercion arreglo
MultiValu
no no multiValu
no HashMap HashSet HashMultimap HashMap<K
definida definida
HashSet.c
Multimaps.
no MultiValu
newMultimap(
ordenado no HashMap TreeSet HashMap, Supplier
new HashM
definida TreeSet.c
<TreeSet>)
MultiValu
Orden de Orden de Lista de multiValu
sí LinkedHashMap LinkedListMultimap
insercion insercion arreglo LinkedHa
(), ArrayL
MultiValu
Orden de Orden de multiValu
no LinkedHashMap LinkedHashSet LinkedHashMultimap LinkedHas
insercion insercion
LinkedHas
MultiValu
multiValu
ordenado ordenado no TreeMap TreeSet TreeMultimap TreeMap<K
Set>(),Tr
Tarea : Analizar "¡Hola mundo! ¡Hola a todos! ¡Hola mundo!" cadena para separar palabras e
imprimir todos los índices de cada palabra usando MultiMap (por ejemplo, Hello = [0, 2], World! =
[1, 5] y así sucesivamente)
1. MultiValueMap de Apache
// Fill Multimap
int i = 0;
for(String word: words) {
multiMap.put(word, i);
i++;
}
https://riptutorial.com/es/home 264
orders
// Create Multiset
MutableBiMap<String, String> biMap = new HashBiMap(englishWords.length);
// Create English-Polish dictionary
int i = 0;
for(String englishWord: englishWords) {
biMap.put(englishWord, russianWords[i]);
i++;
}
3. HashMultiMap de guayaba
// Fill Multimap
int i = 0;
for(String word: words) {
multiMap.put(word, i);
i++;
https://riptutorial.com/es/home 265
}
Más ejemplos:
I. Colección Apache:
1. MultiValueMap
2. MultiValueMapLinked
3. MultiValueMapTree
1. FastListMultimap
2. HashBagMultimap
3. TreeSortedSetMultimap
4. UnifiedSetMultimap
III. Guayaba
1. HashMultiMap
2. LinkedHashMultimap
3. LinkedListMultimap
4. TreeMultimap
5. ArrayListMultimap
1. Crear lista
https://riptutorial.com/es/home 266
Descripción JDK guayaba gs-colecciones
Crear lista
new ArrayList<> () Lists.newArrayList() FastList.newList()
vacía
Crear lista a
Arrays.asList("1", "2", FastList.newListWith("1",
partir de "3")
Lists.newArrayList("1", "2", "3")
"2", "3")
valores.
Crear lista
con
new ArrayList<>(100) Lists.newArrayListWithCapacity(100) FastList.newList(100)
capacidad =
100
Crear una
lista de new
Lists.newArrayList(collection) FastList.newList(collecti
cualquier ArrayList<>(collection)
colección
Crear lista
desde
- Lists.newArrayList(iterable) FastList.newList(iterable
cualquier
iterable.
Crear lista
- Lists.newArrayList(iterator) -
de iterador
Crear lista
Arrays.asList(array) Lists.newArrayList(array) FastList.newListWith(arra
de la matriz
Crear lista
FastList.newWithNValues(1
usando la - - () -> "1")
fábrica
Ejemplos:
System.out.println("createArrayList start");
// Create empty list
List<String> emptyGuava = Lists.newArrayList(); // using guava
List<String> emptyJDK = new ArrayList<>(); // using JDK
MutableList<String> emptyGS = FastList.newList(); // using gs
https://riptutorial.com/es/home 267
// Create list with some elements
List<String> withElements = Lists.newArrayList("alpha", "beta", "gamma"); // using guava
List<String> withElementsJDK = Arrays.asList("alpha", "beta", "gamma"); // using JDK
MutableList<String> withElementsGS = FastList.newListWith("alpha", "beta", "gamma"); //
using gs
System.out.println(withElements);
System.out.println(withElementsJDK);
System.out.println(withElementsGS);
System.out.println(fromIterable);
System.out.println(fromIterableJDK);
System.out.println(fromIterableGS);
/* Attention: JDK create list only from Collection, but guava and gs can create list from
Iterable and Collection */
System.out.println("createArrayList end");
2 Crear Set
Descripción JDK guayaba gs-colecciones
Crear
conjunto new HashSet<>() Sets.newHashSet() UnifiedSet.newSet()
vacío
Conjunto de new
HashSet<>(Arrays.asList("alpha", Sets.newHashSet("alpha", UnifiedSet.newSetWith("a
valores a "beta", "gamma") "beta", "gamma")
partir de. "beta", "gamma") )
https://riptutorial.com/es/home 268
Descripción JDK guayaba gs-colecciones
Crear
conjunto a
partir de new HashSet<>(collection) Sets.newHashSet(collection) UnifiedSet.newSet(collec
cualquier
colección.
Crear set
desde
- Sets.newHashSet(iterable) UnifiedSet.newSet(iterab
cualquier
iterable.
Crear
conjunto
desde - Sets.newHashSet(iterator) -
cualquier
iterador
Crear
new
conjunto HashSet<>(Arrays.asList(array))
Sets.newHashSet(array) UnifiedSet.newSetWith(ar
desde Array
Ejemplos:
System.out.println("createHashSet start");
// Create empty set
Set<String> emptyGuava = Sets.newHashSet(); // using guava
Set<String> emptyJDK = new HashSet<>(); // using JDK
Set<String> emptyGS = UnifiedSet.newSet(); // using gs
System.out.println(withElements);
System.out.println(withElementsJDK);
System.out.println(withElementsGS);
https://riptutorial.com/es/home 269
Set<String> fromIterableGS = UnifiedSet.newSet(collection); // using gs
System.out.println(fromIterable);
System.out.println(fromIterableJDK);
System.out.println(fromIterableGS);
/* Attention: JDK create set only from Collection, but guava and gs can create set from
Iterable and Collection */
System.out.println("createHashSet end");
3 Crear Mapa
Descripción JDK guayaba gs-colecciones
Crear mapa
con new
Maps.newHashMapWithExpectedSize(100) UnifiedMap.newMap(130)
capacidad = HashMap<>(130)
130
Crear mapa
new
desde otro HashMap<>(map)
Maps.newHashMap(map) UnifiedMap.newMap(map)
mapa
Crear mapa
UnifiedMap.newWithKeysValues("1",
desde las - - "a", "2", "b")
teclas
Ejemplos:
System.out.println("createHashMap start");
// Create empty map
Map<String, String> emptyGuava = Maps.newHashMap(); // using guava
Map<String, String> emptyJDK = new HashMap<>(); // using JDK
Map<String, String> emptyGS = UnifiedMap.newMap(); // using gs
https://riptutorial.com/es/home 270
Map<String, String> approx100GS = UnifiedMap.newMap(130); // using gs
System.out.println(withMap);
System.out.println(withMapJDK);
System.out.println(withMapGS);
System.out.println("createHashMap end");
1. ColecciónComparar
2. ColecciónBúsqueda
3. JavaTransform
https://riptutorial.com/es/home 271
Capítulo 42: Colecciones concurrentes
Introducción
Una colección concurrente es una [colección] [1] que permite el acceso por más de un hilo al
mismo tiempo. Normalmente, diferentes hilos pueden recorrer el contenido de la colección y
agregar o eliminar elementos. La colección es responsable de garantizar que la colección no se
corrompa. [1]:
http://stackoverflow.com/documentation/java/90/collections#t=201612221936497298484
Examples
Colecciones a prueba de hilos
De forma predeterminada, los distintos tipos de Colección no son seguros para subprocesos.
Sin embargo, es bastante fácil hacer una colección segura para subprocesos.
Cuando realice una colección segura para subprocesos, nunca debe acceder a ella a través de la
colección original, solo a través de la envoltura segura para hilos.
Java SE 5
Colecciones concurrentes
Las colecciones concurrentes son una generalización de las colecciones seguras para
subprocesos, que permiten un uso más amplio en un entorno concurrente.
Si bien las colecciones seguras para subprocesos tienen la adición o eliminación segura de
elementos de varios subprocesos, no necesariamente tienen una iteración segura en el mismo
contexto (es posible que uno no pueda recorrer la colección en un subproceso en una secuencia,
mientras que otro lo modifica agregando quitando elementos).
https://riptutorial.com/es/home 272
Como la iteración suele ser la implementación básica de varios métodos masivos en colecciones,
como addAll , removeAll , o también la copia de colecciones (a través de un constructor u otros
medios), clasificación, ... el caso de uso de colecciones concurrentes es en realidad bastante
grande.
https://riptutorial.com/es/home 273
}
Uno debe revisar los javadocs para ver si una colección es concurrente o no. Los atributos del
iterador devueltos por el método iterator() ("falla rápidamente", "débilmente consistente", ...) es
el atributo más importante que debe buscarse.
Las colecciones sincronizadas de los métodos de utilidad de Collections son seguras para
subprocesos para la adición / eliminación de elementos, pero no la iteración (a menos que la
colección subyacente que se le pasa ya lo sea).
else
{
https://riptutorial.com/es/home 274
//'value' reference is mapped to key = 1.
}
}
}
https://riptutorial.com/es/home 275
Capítulo 43: Comandos de tiempo de
ejecución
Examples
Añadiendo ganchos de apagado
https://riptutorial.com/es/home 276
Capítulo 44: Comparable y comparador
Sintaxis
• clase pública implementa MyClass Comparable <MyClass >
• la clase pública MyComparator implementa Comparator <SomeOtherClass >
• public int compareTo (MyClass other)
• public int compare (SomeOtherClass o1, SomeOtherClass o2)
Observaciones
Al implementar un compareTo(..) que depende de un double , no haga lo siguiente:
El truncamiento causado por (int) cast causará que el método a veces devuelva incorrectamente
0 lugar de un número positivo o negativo, y por lo tanto puede llevar a errores de comparación y
clasificación.
Una versión no genérica de Comparable<T> , simplemente Comparable , ha existido desde Java 1.2 .
Además de interactuar con el código heredado, siempre es mejor implementar la versión genérica
Comparable<T> , ya que no requiere conversión en la comparación.
Es muy estándar que una clase sea comparable a sí misma, como en:
Un Comparator<T> todavía se puede usar en instancias de una clase si esa clase implementa
Comparable<T> . En este caso, se utilizará la lógica del Comparator ; El orden natural especificado
por la implementación Comparable será ignorado.
Examples
https://riptutorial.com/es/home 277
Ordenar una lista usando Comparable o un comparador
Digamos que estamos trabajando en una clase que representa a una persona por su nombre y
apellido. Hemos creado una clase básica para hacer esto e implementado los métodos equals y
hashCode adecuados.
@Override
public boolean equals(Object o) {
if (! (o instanceof Person)) return false;
Person p = (Person)o;
return firstName.equals(p.firstName) && lastName.equals(p.lastName);
}
@Override
public int hashCode() {
return Objects.hash(firstName, lastName);
}
}
Ahora nos gustaría ordenar una lista de objetos Person por su nombre, como en el siguiente
escenario:
https://riptutorial.com/es/home 278
Si le pidieran que clasificara la siguiente lista: 1,3,5,4,2 , no tendría ningún problema en decir que
la respuesta es 1,2,3,4,5 . Esto se debe a que los enteros (tanto en Java como
matemáticamente) tienen un orden natural , un orden de comparación estándar predeterminado.
Para dar a nuestra clase Person un orden natural, implementamos la Comparable<Person> , que
requiere la implementación del método compareTo(Person p):
@Override
public boolean equals(Object o) {
if (! (o instanceof Person)) return false;
Person p = (Person)o;
return firstName.equals(p.firstName) && lastName.equals(p.lastName);
}
@Override
public int hashCode() {
return Objects.hash(firstName, lastName);
}
@Override
public int compareTo(Person other) {
// If this' lastName and other's lastName are not comparably equivalent,
// Compare this to other by comparing their last names.
// Otherwise, compare this to other by comparing their first names
int lastNameCompare = lastName.compareTo(other.lastName);
if (lastNameCompare != 0) {
return lastNameCompare;
} else {
return firstName.compareTo(other.firstName);
}
}
}
https://riptutorial.com/es/home 279
new Person("Bob", "Dole"),
new Person("Ronald", "McDonald"),
new Person("Alice", "McDonald"),
new Person("Jill", "Doe"));
Collections.sort(people); //Now functions correctly
//Assume the first version of Person (that does not implement Comparable) is used here
public static void main(String[] args) {
List<Person> people = Arrays.asList(new Person("John", "Doe"),
new Person("Bob", "Dole"),
new Person("Ronald", "McDonald"),
new Person("Alice", "McDonald"),
new Person("Jill", "Doe"));
Collections.sort(people); //Illegal, Person doesn't implement Comparable.
Collections.sort(people, new PersonComparator()); //Legal
Los comparadores también se pueden crear / usar como una clase interna anónima
//Assume the first version of Person (that does not implement Comparable) is used here
public static void main(String[] args) {
List<Person> people = Arrays.asList(new Person("John", "Doe"),
new Person("Bob", "Dole"),
new Person("Ronald", "McDonald"),
new Person("Alice", "McDonald"),
new Person("Jill", "Doe"));
Collections.sort(people); //Illegal, Person doesn't implement Comparable.
https://riptutorial.com/es/home 280
//people is now sorted by last name, then first name:
// --> Jill Doe, John Doe, Bob Dole, Alice McDonald, Ronald McDonald
//Anonymous Class
Collections.sort(people, new Comparator<Person>() { //Legal
public int compare(Person p1, Person p2) {
//Method code...
}
});
}
Java SE 8
//Lambda
Collections.sort(people, (p1, p2) -> { //Legal
//Method code....
});
Collections.sort(people, Comparator.comparing(Person::getLastName)
.thenComparing(Person::getFirstName));
https://riptutorial.com/es/home 281
}
Estos dos métodos hacen esencialmente lo mismo, con una pequeña diferencia: compareTo
compara this con other , mientras que compare compara t1 con t2 , sin preocuparse en absoluto
por this .
Aparte de esa diferencia, los dos métodos tienen requisitos similares. Específicamente (para
compareTo), compara este objeto con el objeto especificado para orden. Devuelve un entero
negativo, cero o un entero positivo, ya que este objeto es menor, igual o mayor que el objeto
especificado. Así, para la comparación de a y b :
• Uno que toma una List<T> como parámetro donde T debe implementar Comparable y anular
el compareTo() que determina el orden de clasificación.
• Uno que toma una Lista y un Comparador como los argumentos, donde el Comparador
determina el orden de clasificación.
https://riptutorial.com/es/home 282
@Override
public int compareTo(Person o) {
return this.getAge() - o.getAge();
}
@Override
public String toString() {
return this.getAge()+"-"+this.getName();
}
Aquí es cómo usaría la clase anterior para ordenar una Lista en el orden natural de sus
elementos, definido por la anulación del método compareTo() :
//-- usage
List<Person> pList = new ArrayList<Person>();
Person p = new Person();
p.setName("A");
p.setAge(10);
pList.add(p);
p = new Person();
p.setName("Z");
p.setAge(20);
pList.add(p);
p = new Person();
p.setName("D");
p.setAge(30);
pList.add(p);
System.out.println(pList);
Aquí es cómo usaría un Comparador en línea anónimo para ordenar una Lista que no implementa
Comparable, o en este caso, para ordenar una Lista en un orden diferente al orden natural:
//-- explicit sorting, define sort on another property here goes with name
Collections.sort(pList, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getName().compareTo(o2.getName());
}
});
System.out.println(pList);
Java SE 8
https://riptutorial.com/es/home 283
Map<String, Integer> numberOfEmployees = new HashMap<>();
numberOfEmployees.put("executives", 10);
numberOfEmployees.put("human ressources", 32);
numberOfEmployees.put("accounting", 12);
numberOfEmployees.put("IT", 100);
Java SE 8
Comparator.comparing(Person::getName)
Esto crea un comparador para la clase Person que usa este nombre de persona como fuente de
comparación. También es posible usar la versión del método para comparar long, int y double.
Por ejemplo:
Comparator.comparingInt(Person::getAge)
Orden invertida
Para crear un comparador que imponga el orden inverso, use el método reversed() :
Comparator.comparing(Person::getName).reversed()
Cadena de comparadores
Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName)
Esto creará un comparador que se compara con el apellido y luego con el nombre. Puedes
encadenar tantos comparadores como quieras.
https://riptutorial.com/es/home 284
Capítulo 45: Comparación de C ++
Introducción
Java y C ++ son lenguajes similares. Este tema sirve como una guía de referencia rápida para los
ingenieros de Java y C ++.
Observaciones
class Outer {
class Inner {
public:
Inner(Outer* o) :outer(o) {}
private:
Outer* outer;
};
};
Java
Clase anidada [no estática] (clase interna o clase miembro)
class OuterClass {
...
class InnerClass {
...
}
}
https://riptutorial.com/es/home 285
C ++
Clase anidada estática
class Outer {
class Inner {
...
};
};
Java
Clase anidada estática (también conocida como clase de miembro estática) [ref]
class OuterClass {
...
static class StaticNestedClass {
...
}
}
C ++
Clase local [ref]
void fun() {
class Test {
/* members of Test class */
};
}
Java
Clase local [ref]
class Test {
void f() {
new Thread(new Runnable() {
public void run() {
doSomethingBackgroundish();
}
}).start();
https://riptutorial.com/es/home 286
}
}
Anulando vs Sobrecarga
Los siguientes puntos de Anulación frente a Sobrecarga se aplican tanto a C ++ como a Java:
Polimorfismo
El polimorfismo es la capacidad de los objetos de diferentes clases relacionadas por herencia
para responder de manera diferente a la misma llamada de método. Aquí hay un ejemplo:
En C ++, el polimorfismo es habilitado por métodos virtuales. En Java, los métodos son virtuales
por defecto.
Limpieza de objetos
En C ++, es una buena idea declarar un destructor como virtual para garantizar que se llamará al
destructor de la subclase si se elimina el puntero de la clase base.
https://riptutorial.com/es/home 287
}
}
Método abstracto
declarado sin método virtual puro método abstracto
virtual void eat(void) = 0; abstract void draw();
implementación
Modificadores de accesibilidad
Modificador C ++ Java
Público - accesible
sin notas especiales sin notas especiales
por todos
Protegido -
También accesible dentro
accesible por también accesible por amigos
del mismo paquete
subclases
Privado - accesible
también accesible por amigos sin notas especiales
por los miembros
https://riptutorial.com/es/home 288
Modificador C ++ Java
paquete.
Ejemplo de C ++ Friend
class Node {
private:
int key; Node *next;
// LinkedList::search() can access "key" & "next"
friend int LinkedList::search();
};
Si bien C ++ siempre ha sido susceptible al problema diamante, Java fue susceptible hasta Java
8. Originalmente, Java no admitía herencia múltiple, pero con la llegada de los métodos de
interfaz predeterminados, las clases Java no pueden heredar la "implementación" de más de una
clase. .
clase java.lang.Object
En Java, todas las clases heredan, ya sea implícita o explícitamente, de la clase Object. Cualquier
referencia de Java se puede convertir al tipo de objeto.
https://riptutorial.com/es/home 289
Tipos enteros
Tipo C ++ Tipo de
Bits Min Max
(en LLP64 o LP64) Java
Examples
Miembros de la clase estática
Ejemplo de C ++
// define in header
class Singleton {
public:
static Singleton *getInstance();
private:
Singleton() {}
static Singleton *instance;
};
https://riptutorial.com/es/home 290
// initialize in .cpp
Singleton* Singleton::instance = 0;
Ejemplo de Java
private Singleton() {}
class Outer {
class Inner {
public:
Inner(Outer* o) :outer(o) {}
private:
Outer* outer;
};
};
Java
Clase anidada [no estática] (clase interna o clase miembro)
class OuterClass {
...
class InnerClass {
...
}
}
https://riptutorial.com/es/home 291
Definido estáticamente dentro de otra clase
C ++
Clase anidada estática
class Outer {
class Inner {
...
};
};
Java
Clase anidada estática (también conocida como clase de miembro estática) [ref]
class OuterClass {
...
static class StaticNestedClass {
...
}
}
C ++
Clase local [ref]
void fun() {
class Test {
/* members of Test class */
};
}
Java
Clase local [ref]
class Test {
void f() {
new Thread(new Runnable() {
public void run() {
doSomethingBackgroundish();
https://riptutorial.com/es/home 292
}
}).start();
}
}
Muchos argumentan que Java SÓLO es paso por valor, pero tiene más matices que eso.
Compare los siguientes ejemplos de C ++ y Java para ver los muchos sabores de paso por valor
(también conocido como copia) y paso por referencia (también conocido como alias).
// passes a pointer
static void passByPointer(PassIt* ptr) {
ptr->i = 33;
ptr = 0; // better to use nullptr instead if '0'
}
https://riptutorial.com/es/home 293
// passes an alias (aka reference)
public static void passByAlias(PassIt ref) {
ref.i = 44;
}
Herencia vs Composición
C ++ y Java son lenguajes orientados a objetos, por lo que el siguiente diagrama se aplica a
ambos.
Ejemplo de C ++
// explicit type case required
Child *pChild = (Child *) &parent;
Ejemplo de Java
if(mySubClass instanceof SubClass) {
SubClass mySubClass = (SubClass)someBaseClass;
mySubClass.nonInheritedMethod();
}
Método abstracto
declarado sin implementación
C ++
método virtual puro
https://riptutorial.com/es/home 294
virtual void eat(void) = 0;
Java
método abstracto
Clase abstracta
no puede ser instanciado
C ++
no puede ser instanciado; tiene al menos 1 método virtual puro
Java
no puede ser instanciado; puede tener métodos no abstractos
Interfaz
campos sin instancia
C ++
nada comparable a Java
Java
muy similar a la clase abstracta, pero 1) admite herencia múltiple; 2) campos sin instancia
interface TestInterface {}
https://riptutorial.com/es/home 295
Capítulo 46: Compilador de Java - 'javac'
Observaciones
El comando javac se utiliza para compilar archivos fuente de Java a archivos de código de bytes.
Los archivos de bytecode son independientes de la plataforma. Esto significa que puede compilar
su código en un tipo de hardware y sistema operativo, y luego ejecutar el código en cualquier otra
plataforma que admita Java.
El comando javac se incluye en las distribuciones del Kit de desarrollo de Java (JDK).
Nota: javac compilador javac no debe confundirse con el compilador Just in Time (JIT) que
compila los códigos de bytes en código nativo.
Examples
El comando 'javac' - empezando
Ejemplo simple
Suponiendo que el "HelloWorld.java" contiene la siguiente fuente de Java:
(Para obtener una explicación del código anterior, consulte Cómo comenzar con el lenguaje Java
).
$ javac HelloWorld.java
Esto produce un archivo llamado "HelloWorld.class", que luego podemos ejecutar de la siguiente
manera:
https://riptutorial.com/es/home 296
$ java HelloWorld
Hello world!
package com.example;
Este archivo de código fuente necesita almacenarse en un árbol de directorios cuya estructura
corresponde a la denominación del paquete.
$ javac com/example/HelloWorld.java
https://riptutorial.com/es/home 297
----com
|
----example
|
----HelloWorld.java
----HelloWorld.class
$ java com.example.HelloWorld
Hello world!
1. La estructura del directorio debe coincidir con la estructura del nombre del paquete.
2. Cuando ejecuta la clase, se debe proporcionar el nombre completo de la clase; es decir,
"com.example.HelloWorld" no "HelloWorld".
3. No es necesario compilar y ejecutar código Java desde el directorio actual. Solo lo estamos
haciendo aquí para ilustrar.
$ javac *.java
$ javac com/example/*.java
$ javac */**/*.java #Only works on Zsh or with globstar enabled on your shell
Esto compilará todos los archivos fuente de Java en el directorio actual, en el directorio "com /
example", y recursivamente en directorios secundarios respectivamente. Una tercera alternativa
es proporcionar una lista de nombres de archivos de origen (y opciones del compilador) como un
archivo. Por ejemplo:
$ javac @sourcefiles
Foo.java
Bar.java
com/example/HelloWorld.java
Nota: compilar código como este es apropiado para proyectos pequeños de una sola persona y
para programas únicos. Más allá de eso, es recomendable seleccionar y utilizar una herramienta
https://riptutorial.com/es/home 298
de compilación Java. Alternativamente, la mayoría de los programadores usan un IDE de Java
(por ejemplo, NetBeans , eclipse , IntelliJ IDEA ) que ofrece un compilador integrado y la
construcción incremental de "proyectos".
Una lista más completa de las opciones del compilador se describirá en un ejemplo separado.
Referencias
La referencia definitiva para el comando javac es la página de manual de Oracle para javac .
Con muy pocas excepciones (por ejemplo, la palabra clave enum , los cambios en algunas clases
"internas", etc.), estos cambios son compatibles con versiones anteriores.
https://riptutorial.com/es/home 299
public class OldSyntax {
private static int enum; // invalid in Java 5 or later
}
También puede compilar con un compilador de Java más nuevo, pero los hay complicados. En
primer lugar, hay algunas condiciones previas importantes que deben cumplirse:
• El código que está compilando no debe usar construcciones del lenguaje Java que no
estaban disponibles en la versión de Java que está seleccionando.
• El código no debe depender de clases Java estándar, campos, métodos, etc. que no
estuvieran disponibles en las plataformas anteriores.
• Las bibliotecas de terceros de las que depende el código también deben construirse para la
plataforma más antigua y estar disponibles en tiempo de compilación y tiempo de ejecución.
Dado que se cumplen las condiciones previas, puede volver a compilar el código para una
plataforma anterior utilizando la opción -target . Por ejemplo,
compilará la clase anterior para producir códigos de bytes que sean compatibles con Java 1.4 o
posterior JVM. (De hecho, el -source opción implica una compatibles -target , por lo javac -source
1.4 ... tendría el mismo efecto. La relación entre -source y -target se describe en la
documentación de Oracle.)
Una vez dicho esto, si usted utiliza simplemente -target o -source , usted seguirá siendo
compilando contra las bibliotecas de clases estándar proporcionados por JDK del compilador. Si
no tiene cuidado, puede terminar con clases con la versión correcta de bytecode, pero con
dependencias en las API que no están disponibles. La solución es usar la opción -bootclasspath .
Por ejemplo:
https://riptutorial.com/es/home 300
java----javac-
https://riptutorial.com/es/home 301
Capítulo 47: CompletableFuture
Introducción
CompletableFuture es una clase agregada a Java SE 8 que implementa la interfaz Future de Java
SE 5. Además de admitir la interfaz Future, agrega muchos métodos que permiten la devolución
de llamadas asíncronas cuando se completa el futuro.
Examples
Convertir el método de bloqueo a asíncrono.
El siguiente método tomará uno o dos segundos, dependiendo de su conexión para recuperar una
página web y contar la longitud del texto. Cualquiera que sea el hilo que llame, se bloqueará
durante ese período de tiempo. También vuelve a lanzar una excepción que es útil más adelante.
Para usar la función de forma asíncrona, se debe usar uno de los métodos que aceptan una
lamda para que se llame con el resultado del proveedor cuando se complete, como por ejemplo,
Aceptar. También es importante usar excepcionalmente o manejar un método para registrar
cualquier excepción que pueda haber ocurrido.
https://riptutorial.com/es/home 302
asyncGetWebPageLength("https://stackoverflow.com/")
.thenAccept(l -> {
System.out.println("Stack Overflow returned " + l);
})
.exceptionally((Throwable throwable) -> {
Logger.getLogger("myclass").log(Level.SEVERE, "", throwable);
return null;
});
// Let's just say each 200 grams is a new dollar on your shipping costs
int shippingCosts = weightInGrams / 200;
try {
Thread.sleep(2000L); // Now let's simulate some waiting time...
} catch(InterruptedException e) { /* We can safely ignore that */ }
https://riptutorial.com/es/home 303
Capítulo 48: Conjuntos
Examples
Declarando un HashSet con valores
Utilizando guayaba:
Utilizando Streams:
Generalmente, los conjuntos son un tipo de colección que almacena valores únicos. La unicidad
está determinada por los métodos equals() y hashCode() .
https://riptutorial.com/es/home 304
LinkedHashSet - Orden de inserción
Java SE 7
Java SE 7
Java SE 7
Inicialización
Por ejemplo:
HashSet:
Aquí T puede ser String , Integer o cualquier otro objeto . HashSet permite una búsqueda rápida
de O (1) pero no ordena los datos agregados y pierde el orden de inserción de los elementos.
https://riptutorial.com/es/home 305
TreeSet:
Almacena los datos de forma ordenada, sacrificando cierta velocidad para las operaciones
básicas que toman O (lg (n)). No mantiene el orden de inserción de los artículos.
LinkedHashSet:
Es una implementación de lista enlazada de HashSet Una vez puede iterar sobre los elementos en
el orden en que se agregaron. La clasificación no está prevista para su contenido. O (1) se
proporcionan operaciones básicas, sin embargo, hay un costo más alto que HashSet para
mantener la lista de vínculos de respaldo.
Fundamentos de set
¿Qué es un conjunto?
Un conjunto es una estructura de datos que contiene un conjunto de elementos con una
propiedad importante que no hay dos elementos iguales en el conjunto.
Tipos de juego:
1. HashSet: un conjunto respaldado por una tabla hash (en realidad una instancia de
HashMap)
2. HashSet vinculado: un conjunto respaldado por una tabla de hash y una lista enlazada,
con un orden de iteración predecible
3. TreeSet: Una implementación de NavigableSet basada en un TreeMap.
Creando un conjunto
set = [12,13]
https://riptutorial.com/es/home 306
Eliminar todos los elementos de un conjunto.
set = []
Salida: False
isEmpty() método isEmpty() se puede usar para verificar si un conjunto está vacío.
Salida: Verdadero
Salida: 0
https://riptutorial.com/es/home 307
Usando Java 8 Steam API
Supongamos que tiene elements una colección y desea crear otra colección que contenga los
mismos elementos pero con todos los duplicados eliminados :
Ejemplo :
Salida :
https://riptutorial.com/es/home 308
Capítulo 49: Constructores
Introducción
Aunque no es obligatorio, los constructores en Java son métodos reconocidos por el compilador
para instanciar valores específicos para la clase que pueden ser esenciales para el rol del objeto.
Este tema demuestra el uso adecuado de los constructores de clases Java.
Observaciones
La especificación del lenguaje Java habla en detalle sobre la naturaleza exacta de la semántica
del constructor. Se pueden encontrar en JLS §8.8
Examples
Constructor predeterminado
El "predeterminado" para los constructores es que no tienen ningún argumento. En caso de que
no especifique ningún constructor, el compilador generará un constructor predeterminado por
usted.
Esto significa que los siguientes dos fragmentos son semánticamente equivalentes:
}
}
https://riptutorial.com/es/home 309
public class TestClass {
private String test;
public TestClass() {
}
public TestClass(String arg) {
}
}
Tenga en cuenta que el constructor generado no realiza una inicialización no estándar. Esto
significa que todos los campos de su clase tendrán su valor predeterminado, a menos que tengan
un inicializador.
public TestClass() {
testData = "Test"
}
}
Llamado así:
Una clase puede tener múltiples constructores con diferentes firmas. Para encadenar llamadas de
constructor (llamar a un constructor diferente de la misma clase al crear instancias) use this() .
https://riptutorial.com/es/home 310
public TestClass() {
this("Test"); // testData defaults to "Test"
}
}
Llamado así:
Digamos que tienes una clase para padres y una clase para niños. Para construir una instancia
de Child siempre se requiere que se ejecute algún constructor Parent desde el principio del
constructor de Child. Podemos seleccionar el constructor principal que queremos llamando
explícitamente a super(...) con los argumentos apropiados como nuestra primera declaración del
constructor secundario. Hacer esto nos ahorra tiempo al reutilizar el constructor de las clases
principales en lugar de volver a escribir el mismo código en el constructor de las clases
secundarias.
class Parent {
private String name;
private int age;
// This does not even compile, because name and age are private,
// making them invisible even to the child class.
class Child extends Parent {
public Child() {
// compiler implicitly calls super() here
name = "John";
age = 42;
}
}
class Parent {
private String name;
private int age;
public Parent(String tName, int tAge) {
name = tName;
age = tAge;
https://riptutorial.com/es/home 311
}
}
Nota: las llamadas a otro constructor (encadenamiento) o el súper constructor DEBEN ser la
primera declaración dentro del constructor.
class Parent{
public Parent(String tName, int tAge) {}
}
https://riptutorial.com/es/home 312
Capítulo 50: Convertir hacia y desde cuerdas
Examples
Convertir otros tipos de datos a String
• Puede obtener el valor de otros tipos de datos primitivos como una cadena utilizando uno de
los métodos valueOf la clase String.
Por ejemplo:
int i = 42;
String string = String.valueOf(i);
//string now equals "42”.
Este método también está sobrecargado para otros tipos de datos, como float , double ,
boolean e incluso Object .
• También puede obtener cualquier otro Objeto (cualquier instancia de cualquier clase) como
una Cadena llamando a .toString en él. Para que esto dé un resultado útil, la clase debe
anular toString() . La mayoría de las clases estándar de la biblioteca de Java lo hacen,
como Date y otras.
Por ejemplo:
También puede convertir cualquier tipo de número a Cadena con una notación corta como la que
se muestra a continuación.
int i = 10;
String str = i + "";
Para codificar una cadena en una matriz de bytes, simplemente puede usar el método
String#getBytes() , con uno de los juegos de caracteres estándar disponibles en cualquier tiempo
de ejecución de Java:
https://riptutorial.com/es/home 313
byte[] bytes = "test".getBytes(StandardCharsets.UTF_8);
y para decodificar:
Para conjuntos de caracteres menos comunes, puede indicar el conjunto de caracteres con una
cadena:
y al revés:
y al revés:
Tenga en cuenta que los caracteres y los bytes no válidos pueden ser reemplazados o omitidos
por estos métodos. Para obtener más control, por ejemplo para validar la entrada, se recomienda
utilizar las clases CharsetEncoder y CharsetDecoder .
Ocasionalmente encontrará la necesidad de codificar datos binarios como una cadena codificada
en base64 .
import javax.xml.bind.DatatypeConverter;
https://riptutorial.com/es/home 314
import java.util.Arrays;
// assert that the original data and the decoded data are equal
assert Arrays.equals(binaryData, decodedData);
Apache commons-codec
import org.apache.commons.codec.binary.Base64;
Si inspecciona este programa mientras se ejecuta, verá que someBinaryData codifica para
c29tZUJpbmFyeURhdGE= , un objeto de cadena UTF-8 muy c29tZUJpbmFyeURhdGE= .
Java SE 8
// decode a String
byte [] barr = Base64.getDecoder().decode(encoded);
Referencia
https://riptutorial.com/es/home 315
Cada clase envoltura numérica proporciona un método parseXxx que convierte una String al tipo
primitivo correspondiente. El siguiente código convierte una String en un int usando el método
Integer.parseInt :
Para convertir a una String a una instancia de una clase de envoltura numérica, puede utilizar una
sobrecarga del método valueOf clases de envoltorio:
El patrón anterior funciona para byte , short , int , long , float y double y las clases de envoltorio
correspondientes ( Byte , Short , Integer , Long , Float y Double ).
Excepciones
Una String se puede leer desde un InputStream usando el constructor de matriz de bytes.
import java.io.*;
Esto utiliza el conjunto de caracteres predeterminado del sistema, aunque se puede especificar
un conjunto de caracteres alternativo:
https://riptutorial.com/es/home 316
return new String(bytes, Charset.forName("UTF-8"));
Puede convertir una cadena numérica a varios tipos numéricos de Java de la siguiente manera:
Cadena a int:
Cadena a booleano:
Cadena a largo:
Cadena a BigInteger:
Cadena a BigDecimal:
Excepciones de conversión:
https://riptutorial.com/es/home 317
lidiar con tales excepciones.
Si desea probar que puede analizar una cadena, podría implementar un método tryParse... como
este:
https://riptutorial.com/es/home 318
Capítulo 51: Corrientes
Introducción
Un Stream representa una secuencia de elementos y admite diferentes tipos de operaciones para
realizar cálculos sobre esos elementos. Con Java 8, la interfaz de la Collection tiene dos métodos
para generar un Stream : stream() y parallelStream() . Stream operaciones de Stream son
intermedias o terminales. Las operaciones intermedias devuelven un Stream por lo que se pueden
encadenar múltiples operaciones intermedias antes de que se cierre el Stream . Las operaciones
de la terminal son nulas o devuelven un resultado no continuo.
Sintaxis
• collection.stream ()
• Arrays.stream (array)
• Stream.iterate (firstValue, currentValue -> nextValue)
• Stream.generate (() -> valor)
• Stream.of (elementOfT [, elementOfT, ...])
• Stream.empty ()
• StreamSupport.stream (iterable.spliterator (), false)
Examples
Usando Streams
Un Stream es una secuencia de elementos sobre los cuales se pueden realizar operaciones
agregadas secuenciales y paralelas. Cualquier Stream dado puede potencialmente tener una
cantidad ilimitada de datos que fluyen a través de él. Como resultado, los datos recibidos de un
Stream se procesan individualmente a medida que llegan, en lugar de realizar el procesamiento
por lotes de los datos por completo. Cuando se combinan con expresiones lambda , proporcionan
una forma concisa de realizar operaciones en secuencias de datos utilizando un enfoque
funcional.
Salida:
MANZANA
https://riptutorial.com/es/home 319
PLÁTANO
NARANJA
PERA
Las operaciones realizadas por el código anterior se pueden resumir de la siguiente manera:
2. La operación de filter() retiene solo los elementos que coinciden con un predicado dado
(los elementos que cuando son probados por el predicado devuelven verdadero). En este
caso, retiene los elementos que contienen una "a" . El predicado se da como una expresión
lambda .
3. La operación map() transforma cada elemento usando una función dada, llamada mapeador.
En este caso, cada String fruta se asigna a su versión de String mayúsculas utilizando el
método String::toUppercase .
Tenga en cuenta que la operación map() devolverá un flujo con un tipo genérico
diferente si la función de mapeo devuelve un tipo diferente a su parámetro de
entrada. Por ejemplo, en una Stream<String> llamada a .map(String::isEmpty)
devuelve un Stream<Boolean>
5. Finalmente, la forEach(action) realiza una acción que actúa en cada elemento de la Stream ,
pasándola a un Consumidor . En el ejemplo, cada elemento simplemente se imprime en la
consola. Esta operación es una operación de terminal, por lo que es imposible volver a
operar en ella.
Las operaciones (como se ve arriba) se encadenan para formar lo que se puede ver como una
consulta en los datos.
Cierre de arroyos
https://riptutorial.com/es/home 320
Tenga en cuenta que un Stream generalmente no tiene que estar cerrado. Solo se
requiere cerrar secuencias que operan en canales IO. La mayoría de Stream tipos no
operan sobre los recursos y por lo tanto no requieren de cierre.
Un ejemplo de caso de uso en el que se debería cerrar una Stream es cuando crea una Stream de
líneas desde un archivo:
La interfaz de Stream también declara el método Stream.onClose() que le permite registrar los
controladores de Runnable que se Runnable cuando se cierre el stream. Un ejemplo de caso de uso
es cuando el código que produce una transmisión necesita saber cuándo se consume para
realizar una limpieza.
Orden de procesamiento
El procesamiento de un objeto Stream puede ser secuencial o paralelo .
Ejemplo:
// sequential
long howManyOddNumbers = integerList.stream()
.filter(e -> (e % 2) == 1)
.count();
System.out.println(howManyOddNumbers); // Output: 2
Vivir en Ideone
https://riptutorial.com/es/home 321
El modo paralelo permite el uso de múltiples hilos en múltiples núcleos, pero no hay garantía del
orden en que se procesan los elementos.
Si se invocan varios métodos en una secuencia Stream , no es necesario invocar todos los
métodos. Por ejemplo, si un Stream se filtra y el número de elementos se reduce a uno, no se
producirá una llamada posterior a un método como la sort . Esto puede aumentar el rendimiento
de un Stream secuencial, una optimización que no es posible con un Stream paralelo.
Ejemplo:
// parallel
long howManyOddNumbersParallel = integerList.parallelStream()
.filter(e -> (e % 2) == 1)
.count();
System.out.println(howManyOddNumbersParallel); // Output: 2
Vivir en Ideone
System.out.println(Arrays
.asList("apple", "banana", "pear", "kiwi", "orange")
.stream()
.filter(s -> s.contains("a"))
.collect(Collectors.toList())
);
// prints: [apple, banana, pear, orange]
Se pueden crear otras instancias de recopilación, como un Set , utilizando otros métodos
integrados de Collectors . Por ejemplo, Collectors.toSet() recopila los elementos de un Stream en
un Set .
https://riptutorial.com/es/home 322
Control explícito sobre la implementación de List o Set
De acuerdo con la documentación de los Collectors#toList() y los Collectors#toSet() , no hay
garantías sobre el tipo, mutabilidad, serialización o seguridad de subprocesos de la List o el Set
devuelto.
Salida:
El mergeFunction a menudo se ve así: (s1, s2) -> s1 para retener el valor correspondiente a la
tecla repetida, o (s1, s2) -> s2 para poner un nuevo valor para la tecla repetida.
https://riptutorial.com/es/home 323
Ejemplo: de ArrayList a Map <String, List <>>
A menudo se requiere hacer un mapa de la lista de una lista primaria. Ejemplo: de un estudiante
de la lista, necesitamos hacer un mapa de la lista de temas para cada estudiante.
Salida:
{ Robert=[LITERATURE],
Sascha=[ENGLISH, MATH, SCIENCE, LITERATURE],
Davis=[MATH, SCIENCE, GEOGRAPHY] }
list.stream().forEach(student -> {
map.computeIfAbsent(student.getName(), s -> new HashMap<>())
.computeIfAbsent(student.getSubject(), s -> new ArrayList<>())
.add(student.getMarks());
});
System.out.println(map);
Salida:
https://riptutorial.com/es/home 324
{ Robert={ENGLISH=[12.0]},
Sascha={MATH=[80.0, 50.0], ENGLISH=[85.0, 12.0]},
Davis={MATH=[35.0, 37.0], SCIENCE=[12.9, 37.0]} }
Hoja de trucos
Gol Código
Mapear MyObject.getter () a
Collectors.groupingBy(MyObject::getter)
múltiples MyObjects
Corrientes infinitas
Este ejemplo genera una Stream de todos los números naturales, comenzando con el número 1.
Cada término sucesivo de la Stream es uno más alto que el anterior. Al llamar al método de límite
de este Stream , solo se consideran e imprimen los primeros cinco términos del Stream .
https://riptutorial.com/es/home 325
Salida:
1
2
3
4
5
Otra forma de generar un flujo infinito es usando el método Stream.generate . Este método lleva
una lambda de tipo Proveedor .
Corrientes de consumo
Un Stream solo se atravesará cuando haya una operación de terminal , como count() , collect() o
forEach() . De lo contrario, no se realizará ninguna operación en el Stream .
Vivir en Ideone
Esta es una secuencia de Stream con una operación de terminal válida, por lo que se produce una
salida.
Vivir en Ideone
Salida:
2
4
6
8
Una vez realizada la operación del terminal, el Stream se consume y no se puede reutilizar.
https://riptutorial.com/es/home 326
Aunque un objeto de flujo dado no puede ser reutilizado, es fácil crear un Iterable reutilizable que
delega a un flujo de flujo. Esto puede ser útil para devolver una vista modificada de un conjunto
de datos en vivo sin tener que recopilar resultados en una estructura temporal.
Salida:
foo
bar
foo
bar
Esto funciona porque Iterable declara un solo método abstracto Iterator<T> iterator() . Eso hace
que sea efectivamente una interfaz funcional, implementada por un lambda que crea una nueva
transmisión en cada llamada.
NOTA : Las comprobaciones de argumentos siempre se realizan, incluso sin una operación de
terminal :
try {
IntStream.range(1, 10).filter(null);
} catch (NullPointerException e) {
System.out.println("We got a NullPointerException as null was passed as an argument to
filter()");
}
Vivir en Ideone
Salida:
https://riptutorial.com/es/home 327
Creando un Mapa de Frecuencia
Un ejemplo clásico de este principio es usar un Map para contar las ocurrencias de elementos en
una Stream . En este ejemplo, el clasificador es simplemente la función de identidad, que devuelve
el elemento como está. La operación descendente cuenta el número de elementos iguales,
utilizando counting() .
plátano = 1
naranja = 1
manzana = 2
Corriente paralela
Nota: antes de decidir qué Stream usar, consulte ParallelStream vs Sequential Stream .
Cuando desee realizar operaciones de Stream simultánea, puede utilizar cualquiera de estas
formas.
O:
Para ejecutar las operaciones definidas para el flujo paralelo, llame a un operador de terminal:
aParallelStream.forEach(System.out::println);
Tres
Cuatro
https://riptutorial.com/es/home 328
Uno
Dos
Cinco
El orden puede cambiar ya que todos los elementos se procesan en paralelo (lo que puede hacer
que sea más rápido). Use parallelStream cuando ordene no importa.
Impacto en el rendimiento
En el caso de que se trate de redes, los Stream paralelo pueden degradar el rendimiento general
de una aplicación porque todos los Stream paralelo utilizan un conjunto común de subprocesos
para la red.
Por otro lado, los Stream paralelo pueden mejorar significativamente el rendimiento en muchos
otros casos, dependiendo del número de núcleos disponibles en la CPU en ejecución en este
momento.
Es posible que necesite convertir un Stream emite un Optional en un Stream de valores, emitiendo
solo valores del Optional existente. (es decir, sin valor null y sin tratar con Optional.empty() ).
Creando un Stream
Todos los java Collection<E> tienen métodos stream() y parallelStream() partir de los cuales se
puede construir un Stream<E> :
Se puede crear un Stream<E> partir de una matriz usando uno de dos métodos:
https://riptutorial.com/es/home 329
Stream<Integer> integerStream = Stream.of(1, 2, 3);
Tenga en cuenta que cualquier flujo primitivo se puede convertir a flujo de tipo en caja utilizando
el método en boxed :
Esto puede ser útil en algunos casos si desea recopilar datos, ya que la secuencia primitiva no
tiene ningún método de collect que tome un Collector como argumento.
// APPLE
// BANANA
// BLACKBERRY
// BLUEBERRY
https://riptutorial.com/es/home 330
Encontrar estadísticas sobre flujos numéricos
Java SE 8
Java SE 8
Notas:
Corrientes de concatenación
concat1.forEach(System.out::print);
https://riptutorial.com/es/home 331
// prints: abc123
System.out.println(concat2.collect(Collectors.joining(", ")));
// prints: a, b, c, 1, 2, 3, alpha, beta, gamma
Alternativamente, para simplificar la sintaxis concat() anidada, los Stream también se pueden
concatenar con flatMap() :
System.out.println(concat3.collect(Collectors.joining(", ")));
// prints: a, b, c, 1, 2, 3, alpha, beta, gamma
Tenga cuidado al construir Stream a partir de una concatenación repetida, ya que el acceso a un
elemento de un Stream profundamente concatenado puede dar lugar a cadenas de llamadas
profundas o incluso a una StackOverflowException .
IntStream to String
Java no tiene un flujo de caracteres , por lo que al trabajar con String y construir un Stream de
Character , una opción es obtener un IntStream de puntos de código utilizando el método
String.codePoints() . Por IntStream tanto, IntStream se puede obtener de la siguiente manera:
Es un poco más complicado hacer la conversión de otra manera, por ejemplo, IntStreamToString.
Eso se puede hacer de la siguiente manera:
https://riptutorial.com/es/home 332
data.add("Mumbai");
data.add("California");
System.out.println(data);
System.out.println(sortedData);
Salida:
También es posible usar un mecanismo de comparación diferente, ya que hay una versión sorted
sobrecargada que toma un comparador como argumento.
Puede usar Comparator.reverseOrder() para tener un comparador que impone el orden reverse al
reverse .
List<String> reverseSortedData =
data.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
Arroyos de primitivos
Java proporciona Stream especializadas para tres tipos de primitivas IntStream (para int s),
LongStream (para s long ) y DoubleStream (para s double ). Además de ser implementaciones
optimizadas para sus primitivas respectivas, también proporcionan varios métodos terminales
específicos, típicamente para operaciones matemáticas. P.ej:
Analógico para obtener una colección para un Stream por collect() se puede obtener una matriz
mediante el método Stream.toArray() :
https://riptutorial.com/es/home 333
// prints: [apple, banana, pear, orange]
System.out.println(Arrays.toString(filteredFruits));
Es posible encontrar el primer elemento de un Stream que coincida con una condición.
Para este ejemplo, encontraremos el primer Integer cuyo cuadrado es más de 50000 .
Tenga en cuenta que con un Stream infinito, Java seguirá revisando cada elemento hasta que
encuentre un resultado. Con un Stream finito, si Java se queda sin elementos pero aún no puede
encontrar un resultado, devuelve un OptionalInt vacío.
Stream de elementos generalmente no permiten el acceso al valor de índice del elemento actual.
Para iterar sobre una matriz o ArrayList mientras tiene acceso a los índices, use
IntStream.range(start, endExclusive) .
IntStream.range(0, names.length)
.mapToObj(i -> String.format("#%d %s", i + 1, names[i]))
.forEach(System.out::println);
Salida:
# 1 Jon
# 2 Darin
# 3 Bauke
# 4 Hans
# 5 Marc
Esto es muy similar a usar un bucle normal for con un contador, pero con el beneficio de la
canalización y la paralelización:
https://riptutorial.com/es/home 334
System.out.println(newName);
}
Un Stream de elementos que a su vez se pueden transmitir puede aplanarse en un solo Stream
continuo:
El mapa que contiene la Lista de elementos como valores se puede acoplar a una lista combinada
System.out.println(allValues);
// [1, 2, 3, 4, 5, 6]
https://riptutorial.com/es/home 335
Caso simple sin llaves duplicadas
Para hacer las cosas más declarativa, podemos utilizar el método estático en Function la interfaz -
Function.identity() . Podemos reemplazar este element -> element lambda element -> element con
Function.identity() .
• devuelve el valor anterior, de modo que el primer valor de la secuencia tenga prioridad,
• devuelve el nuevo valor, de modo que el último valor de la secuencia tenga prioridad, o
• Combina los valores antiguos y nuevos.
Puede usar Collectors.groupingBy cuando necesite realizar el equivalente de una base de datos
en cascada "agrupar por" operación. Para ilustrar, lo siguiente crea un mapa en el que los
nombres de las personas se asignan a los apellidos:
https://riptutorial.com/es/home 336
.collect(
// function mapping input elements to keys
Collectors.groupingBy(Person::getName,
// function mapping input elements to values,
// how to store values
Collectors.mapping(Person::getSurname, Collectors.toList()))
);
Vivir en Ideone
A veces es útil crear Strings aleatorias, tal vez como Session-ID para un servicio web o una
contraseña inicial después del registro para una aplicación. Esto se puede lograr fácilmente
usando Stream s.
Nota : crear un SecureRandom es bastante costoso, por lo que es una buena práctica hacer esto
solo una vez y llamar a uno de sus métodos setSeed() de vez en cuando para reiniciarlo.
Al crear String aleatorias, generalmente queremos que utilicen solo ciertos caracteres (por
ejemplo, solo letras y dígitos). Por lo tanto, podemos crear un método que devuelva un valor
boolean que luego se puede usar para filtrar el Stream .
A continuación, podemos utilizar el RNG para generar una cadena aleatoria de longitud específica
que contiene el conjunto de caracteres que pasa nuestra verificación de uso Este useThisCharacter
.
//now we can use this Stream to build a String utilizing the collect method.
String randomString = randomCharStream.collect(StringBuilder::new, StringBuilder::append,
StringBuilder::append).toString();
https://riptutorial.com/es/home 337
return randomString;
}
, y especialmente los IntStream , son una forma elegante de implementar los términos de
Stream
resumen (∑). Los rangos de la Stream se pueden usar como los límites de la suma.
Por ejemplo, la aproximación de Madhava de Pi viene dada por la fórmula (Fuente: wikipedia ):
Esto se puede calcular con una precisión arbitraria. Por ejemplo, para 101 términos:
double pi = Math.sqrt(12) *
IntStream.rangeClosed(0, 100)
.mapToDouble(k -> Math.pow(-3, -1 * k) / (2 * k + 1))
.sum();
Nota: Con precisión de double , seleccionar un límite superior de 29 es suficiente para obtener un
resultado que no se puede distinguir de Math.Pi
https://riptutorial.com/es/home 338
results.add(value);
}
}
}
}
results.sort((a, b)->{
return Integer.compare(a.getOrder(), b.getOrder());
});
return results;
}
Este último método reescrito utilizando Stream s y las referencias de métodos es mucho más
legible y cada paso del proceso se comprende rápida y fácilmente. No solo es más corto, también
muestra de un vistazo qué interfaces y clases son responsables del código en cada paso:
Uso de flujos de Map.Entry para conservar los valores iniciales después del
mapeo
Cuando tiene un Stream , debe Map.Entry<K,V> pero también desea conservar los valores iniciales,
puede mapear el Stream a un Map.Entry<K,V> usando un método de utilidad como el siguiente:
public static <K, V> Function<K, Map.Entry<K, V>> entryMapper(Function<K, V> mapper){
return (k)->new AbstractMap.SimpleEntry<>(k, mapper.apply(k));
}
Luego, puede usar su convertidor para procesar los Stream tienen acceso a los valores originales y
asignados:
Set<K> mySet;
Function<K, V> transformer = SomeClass::transformerMethod;
Stream<Map.Entry<K, V>> entryStream = mySet.stream()
.map(entryMapper(transformer));
A continuación, puede continuar procesando esa Stream forma normal. Esto evita la sobrecarga de
crear una colección intermedia.
https://riptutorial.com/es/home 339
Operaciones intermedias:
Una operación intermedia siempre es perezosa , como un simple Stream.map . No se invoca hasta
que la secuencia se consume realmente. Esto se puede verificar fácilmente:
Las operaciones intermedias son los bloques de construcción comunes de una secuencia,
encadenados después de la fuente y generalmente son seguidos por una operación de terminal
que dispara la cadena de la corriente.
Terminal de Operaciones
Las operaciones de terminal son las que activan el consumo de un flujo. Algunos de los más
comunes son Stream.forEach o Stream.collect . Por lo general, se colocan después de una cadena
de operaciones intermedias y casi siempre están ansiosos .
Operaciones de estado
La notificación de estado significa que la operación en cada elemento depende de (algunos) otros
elementos de la transmisión. Esto requiere un estado para ser preservado. Las operaciones de
estado de estado pueden romperse con flujos largos o infinitos. Las operaciones como
Stream.sorted requieren que la totalidad de la secuencia se procese antes de que se emita
cualquier elemento que se rompa en una secuencia lo suficientemente larga. Esto se puede
demostrar mediante un flujo largo ( ejecutado bajo su propio riesgo ):
https://riptutorial.com/es/home 340
Esto causará una falta de memoria debido a la condición de estado de Stream.sorted :
https://riptutorial.com/es/home 341
Esto es equivalente a (((1+2)+3)+4)
El método de reduce de un flujo permite crear una reducción personalizada. Es posible utilizar el
método de reduce para implementar el método sum() :
IntStream istr;
//Initialize istr
OptionalInt istr.reduce((a,b)->a+b);
La versión Optional se devuelve para que las secuencias vacías se puedan manejar
adecuadamente.
https://riptutorial.com/es/home 342
:
Stream<LinkedList<T>> listStream;
//Create a Stream<LinkedList<T>>
Stream<LinkedList<T>> listStream;
//Create a Stream<LinkedList<T>>
El operador binario también debe ser asociativo , lo que significa que (a+b)+c==a+(b+c) . Esto se
debe a que los elementos pueden reducirse en cualquier orden. Por ejemplo, la reducción de
adición anterior se podría realizar de la siguiente manera:
https://riptutorial.com/es/home 343
Esta reducción es equivalente a la escritura ((1+2)+(3+4)) . La propiedad de asociatividad también
permite que Java reduzca el Stream en paralelo; cada procesador puede reducir una parte del
flujo, con una reducción que combina el resultado de cada procesador al final.
Un caso de uso que aparece con frecuencia es crear una String partir de una secuencia, donde
los elementos de la secuencia están separados por un determinado carácter. El método
Collectors.joining() se puede usar para esto, como en el siguiente ejemplo:
System.out.println(result);
Salida:
https://riptutorial.com/es/home 344
String result = fruitStream.filter(s -> s.contains("e"))
.map(String::toUpperCase)
.sorted()
.collect(Collectors.joining(", ", "Fruits: ", "."));
System.out.println(result);
Salida:
Vivir en Ideone
https://riptutorial.com/es/home 345
Capítulo 52: Creando imágenes
programáticamente
Observaciones
BufferedImage.getGraphics() siempre devuelve Graphics2D .
Examples
Creando una imagen simple programáticamente y mostrándola.
class ImageCreationExample {
return img;
}
https://riptutorial.com/es/home 346
ImageIcon icon = new ImageIcon(img);
frame.add(new JLabel(icon));
frame.pack();
frame.setVisible(true);
}
}
https://riptutorial.com/es/home 347
}
https://riptutorial.com/es/home 348
Creando una imagen con la clase BufferedImage
Graphics g = image.createGraphics();
g.setColor(Color.BLUE);
g.drawOval(120, 120, 80, 40);
//now image has programmatically generated content, you can use it in graphics.drawImage() to
draw it somewhere else
//or just simply save it to a file
ImageIO.write(image, "png", new File("myimage.png"));
Salida:
https://riptutorial.com/es/home 349
Edición y reutilización de imágenes con BufferedImage.
//modify it
Graphics g = cat.createGraphics();
g.setColor(Color.RED);
g.drawString("Cat", 10, 10);
g.dispose();
g.setColor(Color.BLUE);
g.drawRect(0, 0, 255, 255); //add some nice border
g.dispose(); //and done
Archivo producido:
https://riptutorial.com/es/home 350
Configuración del color de píxel individual en BufferedImage
//you don't have to use the Graphics object, you can read and set pixel color individually
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
int alpha = 255; //don't forget this, or use BufferedImage.TYPE_INT_RGB instead
int red = i; //or any formula you like
int green = j; //or any formula you like
int blue = 50; //or any formula you like
int color = (alpha << 24) | (red << 16) | (green << 8) | blue;
image.setRGB(i, j, color);
}
}
Salida:
/**
* Resizes an image using a Graphics2D object backed by a BufferedImage.
https://riptutorial.com/es/home 351
* @param srcImg - source image to scale
* @param w - desired width
* @param h - desired height
* @return - the new resized image
*/
private BufferedImage getScaledImage(Image srcImg, int w, int h){
//Create a new image with good size that contains or might contain arbitrary alpha values
between and including 0.0 and 1.0.
BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
//Finally draw the source image in the Graphics2D with the desired size.
g2.drawImage(srcImg, 0, 0, w, h, null);
//Disposes of this graphics context and releases any system resources that it is using
g2.dispose();
https://riptutorial.com/es/home 352
Capítulo 53: Desmontaje y Descompilación.
Sintaxis
• javap [opciones] <clases>
Parámetros
Nombre Descripción
-c Desmontar el codigo
-classpath
<path> Especifique dónde encontrar los archivos de clase de usuario
-bootclasspath
<path> Anular la ubicación de los archivos de clase de arranque
https://riptutorial.com/es/home 353
Examples
Viendo bytecode con javap
Si desea ver el código de bytes generado para un programa Java, puede usar el comando javap
proporcionado para verlo.
package com.stackoverflow.documentation;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
@Service
public class HelloWorldService {
void stuff() {
System.out.println("stuff");
}
}
https://riptutorial.com/es/home 354
protected java.lang.String tryCatchResources(java.lang.String) throws java.io.IOException;
void stuff();
}
Esto enumera todos los métodos no privados en la clase, pero eso no es particularmente útil para
la mayoría de los propósitos. El siguiente comando es mucho más útil:
Classfile /Users/pivotal/IdeaProjects/stackoverflow-spring-
docs/target/classes/com/stackoverflow/documentation/HelloWorldService.class
Last modified Jul 22, 2016; size 2167 bytes
MD5 checksum 6e33b5c292ead21701906353b7f06330
Compiled from "HelloWorldService.java"
public class com.stackoverflow.documentation.HelloWorldService
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #5.#60 // java/lang/Object."<init>":()V
#2 = Fieldref #61.#62 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #63 // Hello, World!
#4 = Methodref #64.#65 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #66 // java/lang/Object
#6 = Methodref #5.#67 // java/lang/Object.getClass:()Ljava/lang/Class;
#7 = Methodref #68.#69 //
java/lang/Class.getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream;
#8 = Methodref #70.#71 // java/io/InputStream.read:([B)I
#9 = Class #72 // java/lang/String
#10 = Methodref #9.#73 // java/lang/String."<init>":([BII)V
#11 = Methodref #70.#74 // java/io/InputStream.close:()V
#12 = Class #75 // java/lang/Throwable
#13 = Methodref #12.#76 //
java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
#14 = Class #77 // java/io/IOException
#15 = Class #78 // java/lang/RuntimeException
#16 = Methodref #79.#80 // java/lang/Exception.printStackTrace:()V
#17 = String #55 // stuff
#18 = Class #81 // com/stackoverflow/documentation/HelloWorldService
#19 = Utf8 <init>
#20 = Utf8 ()V
#21 = Utf8 Code
#22 = Utf8 LineNumberTable
#23 = Utf8 LocalVariableTable
#24 = Utf8 this
#25 = Utf8 Lcom/stackoverflow/documentation/HelloWorldService;
#26 = Utf8 sayHello
#27 = Utf8 pvtMethod
#28 = Utf8 (Ljava/util/List;)[Ljava/lang/Object;
#29 = Utf8 strings
#30 = Utf8 Ljava/util/List;
#31 = Utf8 LocalVariableTypeTable
#32 = Utf8 Ljava/util/List<Ljava/lang/String;>;
#33 = Utf8 Signature
#34 = Utf8 (Ljava/util/List<Ljava/lang/String;>;)[Ljava/lang/Object;
#35 = Utf8 tryCatchResources
https://riptutorial.com/es/home 355
#36 = Utf8 (Ljava/lang/String;)Ljava/lang/String;
#37 = Utf8 bytes
#38 = Utf8 [B
#39 = Utf8 read
#40 = Utf8 I
#41 = Utf8 inputStream
#42 = Utf8 Ljava/io/InputStream;
#43 = Utf8 e
#44 = Utf8 Ljava/lang/Exception;
#45 = Utf8 filename
#46 = Utf8 Ljava/lang/String;
#47 = Utf8 StackMapTable
#48 = Class #81 // com/stackoverflow/documentation/HelloWorldService
#49 = Class #72 // java/lang/String
#50 = Class #82 // java/io/InputStream
#51 = Class #75 // java/lang/Throwable
#52 = Class #38 // "[B"
#53 = Class #83 // java/lang/Exception
#54 = Utf8 Exceptions
#55 = Utf8 stuff
#56 = Utf8 SourceFile
#57 = Utf8 HelloWorldService.java
#58 = Utf8 RuntimeVisibleAnnotations
#59 = Utf8 Lorg/springframework/stereotype/Service;
#60 = NameAndType #19:#20 // "<init>":()V
#61 = Class #84 // java/lang/System
#62 = NameAndType #85:#86 // out:Ljava/io/PrintStream;
#63 = Utf8 Hello, World!
#64 = Class #87 // java/io/PrintStream
#65 = NameAndType #88:#89 // println:(Ljava/lang/String;)V
#66 = Utf8 java/lang/Object
#67 = NameAndType #90:#91 // getClass:()Ljava/lang/Class;
#68 = Class #92 // java/lang/Class
#69 = NameAndType #93:#94 //
getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream;
#70 = Class #82 // java/io/InputStream
#71 = NameAndType #39:#95 // read:([B)I
#72 = Utf8 java/lang/String
#73 = NameAndType #19:#96 // "<init>":([BII)V
#74 = NameAndType #97:#20 // close:()V
#75 = Utf8 java/lang/Throwable
#76 = NameAndType #98:#99 // addSuppressed:(Ljava/lang/Throwable;)V
#77 = Utf8 java/io/IOException
#78 = Utf8 java/lang/RuntimeException
#79 = Class #83 // java/lang/Exception
#80 = NameAndType #100:#20 // printStackTrace:()V
#81 = Utf8 com/stackoverflow/documentation/HelloWorldService
#82 = Utf8 java/io/InputStream
#83 = Utf8 java/lang/Exception
#84 = Utf8 java/lang/System
#85 = Utf8 out
#86 = Utf8 Ljava/io/PrintStream;
#87 = Utf8 java/io/PrintStream
#88 = Utf8 println
#89 = Utf8 (Ljava/lang/String;)V
#90 = Utf8 getClass
#91 = Utf8 ()Ljava/lang/Class;
#92 = Utf8 java/lang/Class
#93 = Utf8 getResourceAsStream
#94 = Utf8 (Ljava/lang/String;)Ljava/io/InputStream;
#95 = Utf8 ([B)I
https://riptutorial.com/es/home 356
#96 = Utf8 ([BII)V
#97 = Utf8 close
#98 = Utf8 addSuppressed
#99 = Utf8 (Ljava/lang/Throwable;)V
#100 = Utf8 printStackTrace
{
public com.stackoverflow.documentation.HelloWorldService();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 10: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/stackoverflow/documentation/HelloWorldService;
https://riptutorial.com/es/home 357
protected java.lang.String tryCatchResources(java.lang.String) throws java.io.IOException;
descriptor: (Ljava/lang/String;)Ljava/lang/String;
flags: ACC_PROTECTED
Code:
stack=5, locals=10, args_size=2
0: aload_0
1: invokevirtual #6 // Method
java/lang/Object.getClass:()Ljava/lang/Class;
4: aload_1
5: invokevirtual #7 // Method
java/lang/Class.getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream;
8: astore_2
9: aconst_null
10: astore_3
11: sipush 8192
14: newarray byte
16: astore 4
18: aload_2
19: aload 4
21: invokevirtual #8 // Method java/io/InputStream.read:([B)I
24: istore 5
26: new #9 // class java/lang/String
29: dup
30: aload 4
32: iconst_0
33: iload 5
35: invokespecial #10 // Method java/lang/String."<init>":([BII)V
38: astore 6
40: aload_2
41: ifnull 70
44: aload_3
45: ifnull 66
48: aload_2
49: invokevirtual #11 // Method java/io/InputStream.close:()V
52: goto 70
55: astore 7
57: aload_3
58: aload 7
60: invokevirtual #13 // Method
java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
63: goto 70
66: aload_2
67: invokevirtual #11 // Method java/io/InputStream.close:()V
70: aload 6
72: areturn
73: astore 4
75: aload 4
77: astore_3
78: aload 4
80: athrow
81: astore 8
83: aload_2
84: ifnull 113
87: aload_3
88: ifnull 109
91: aload_2
92: invokevirtual #11 // Method java/io/InputStream.close:()V
95: goto 113
98: astore 9
100: aload_3
https://riptutorial.com/es/home 358
101: aload 9
103: invokevirtual #13 // Method
java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
106: goto 113
109: aload_2
110: invokevirtual #11 // Method java/io/InputStream.close:()V
113: aload 8
115: athrow
116: astore_2
117: aload_2
118: invokevirtual #16 // Method
java/lang/Exception.printStackTrace:()V
121: aload_2
122: athrow
Exception table:
from to target type
48 52 55 Class java/lang/Throwable
11 40 73 Class java/lang/Throwable
11 40 81 any
91 95 98 Class java/lang/Throwable
73 83 81 any
0 70 116 Class java/io/IOException
0 70 116 Class java/lang/RuntimeException
73 116 116 Class java/io/IOException
73 116 116 Class java/lang/RuntimeException
LineNumberTable:
line 21: 0
line 22: 11
line 23: 18
line 24: 26
line 25: 40
line 21: 73
line 25: 81
line 26: 117
line 27: 121
LocalVariableTable:
Start Length Slot Name Signature
18 55 4 bytes [B
26 47 5 read I
9 107 2 inputStream Ljava/io/InputStream;
117 6 2 e Ljava/lang/Exception;
0 123 0 this Lcom/stackoverflow/documentation/HelloWorldService;
0 123 1 filename Ljava/lang/String;
StackMapTable: number_of_entries = 9
frame_type = 255 /* full_frame */
offset_delta = 55
locals = [ class com/stackoverflow/documentation/HelloWorldService, class
java/lang/String, class java/io/InputStream, class java/lang/Throwable, class "[B", int, class
java/lang/String ]
stack = [ class java/lang/Throwable ]
frame_type = 10 /* same */
frame_type = 3 /* same */
frame_type = 255 /* full_frame */
offset_delta = 2
locals = [ class com/stackoverflow/documentation/HelloWorldService, class
java/lang/String, class java/io/InputStream, class java/lang/Throwable ]
stack = [ class java/lang/Throwable ]
frame_type = 71 /* same_locals_1_stack_item */
stack = [ class java/lang/Throwable ]
frame_type = 255 /* full_frame */
offset_delta = 16
https://riptutorial.com/es/home 359
locals = [ class com/stackoverflow/documentation/HelloWorldService, class
java/lang/String, class java/io/InputStream, class java/lang/Throwable, top, top, top, top,
class java/lang/Throwable ]
stack = [ class java/lang/Throwable ]
frame_type = 10 /* same */
frame_type = 3 /* same */
frame_type = 255 /* full_frame */
offset_delta = 2
locals = [ class com/stackoverflow/documentation/HelloWorldService, class
java/lang/String ]
stack = [ class java/lang/Exception ]
Exceptions:
throws java.io.IOException
void stuff();
descriptor: ()V
flags:
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field
java/lang/System.out:Ljava/io/PrintStream;
3: ldc #17 // String stuff
5: invokevirtual #4 // Method
java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 32: 0
line 33: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/stackoverflow/documentation/HelloWorldService;
}
SourceFile: "HelloWorldService.java"
RuntimeVisibleAnnotations:
0: #59()
https://riptutorial.com/es/home 360
Capítulo 54: Despliegue de Java
Introducción
Existe una variedad de tecnologías para "empaquetar" aplicaciones Java, aplicaciones web, etc.,
para su implementación en la plataforma en la que se ejecutarán. Abarcan desde bibliotecas
simples o archivos JAR ejecutables, archivos WAR y EAR , hasta instaladores y ejecutables
independientes.
Observaciones
En el nivel más fundamental, un programa Java puede implementarse copiando una clase
compilada (es decir, un archivo ".class") o un árbol de directorios que contiene clases compiladas.
Sin embargo, Java normalmente se implementa de una de las siguientes maneras:
• Al colocar los archivos JAR para la aplicación en un servidor web para permitir que se
inicien utilizando Java WebStart.
El ejemplo de Creación de archivos JAR, WAR y EAR resume las diferentes formas de crear
estos archivos.
Examples
Haciendo un JAR ejecutable desde la línea de comando
Para hacer un jar, necesita uno o más archivos de clase. Esto debería tener un método principal
si se va a ejecutar haciendo doble clic.
https://riptutorial.com/es/home 361
import javax.swing.*;
import java.awt.Container;
Puede utilizar cualquier programa que desee hacer esto. Para ejecutar desde la línea de
comandos, consulte la documentación sobre cómo compilar y ejecutar su primer programa java.
Una vez que tengas HelloWorld.class, crea una nueva carpeta y llámala como quieras.
Main-Class: HelloWorld
Class-Path: HelloWorld.jar
Los tipos de archivos JAR, WAR y EAR son fundamentalmente archivos ZIP con un archivo
"manifiesto" y (para archivos WAR y EAR) un directorio / estructura interna particular.
https://riptutorial.com/es/home 362
específica de Java que "entienda" los requisitos para los tipos de archivo respectivos. Si no usa
una herramienta de compilación, la opción siguiente es intentar "exportar" al IDE.
( Nota editorial: las descripciones de cómo crear estos archivos se ubican mejor en la
documentación de las herramientas respectivas. Póngalas allí. ¡Por favor, muestre un poco de
autocontrol y NO las calce en este ejemplo! )
<packaging>jar</packaging>
<packaging>war</packaging>
Para más detalles. Maven se puede configurar para crear archivos JAR "ejecutables" agregando
la información necesaria sobre la clase de punto de entrada y las dependencias externas como
propiedades de plugin para el plugin de maven jar. Incluso hay un complemento para crear
archivos "uberJAR" que combinan una aplicación y sus dependencias en un solo archivo JAR.
• Eclipse - http://www.riptutorial.com/topic/1143
• NetBeans - http://www.riptutorial.com/topic/5438
• Intellij-IDEA - Exportando
https://riptutorial.com/es/home 363
Consulte el tema del comando jar ( Crear y modificar archivos JAR ) para obtener más
información.
El software Java Web Start brinda el poder de lanzar aplicaciones completas con un
solo clic. Los usuarios pueden descargar e iniciar aplicaciones, como un programa
completo de hoja de cálculo o un cliente de chat de Internet, sin pasar por largos
procedimientos de instalación.
Otras ventajas de Java Web Start son la compatibilidad con el código firmado y la declaración
explícita de las dependencias de la plataforma, y la compatibilidad con el almacenamiento en
caché de códigos y la implementación de actualizaciones de aplicaciones.
Java Web Start también se conoce como JavaWS y JAWS. Las principales fuentes de
información son:
Prerrequisitos
En un nivel alto, Web Start funciona distribuyendo aplicaciones Java empaquetadas como
archivos JAR desde un servidor web remoto. Los requisitos previos son:
• Una instalación Java preexistente (JRE o JDK) en la máquina de destino donde se ejecutará
la aplicación. Se requiere Java 1.2.2 o superior:
○ Desde Java 5.0 en adelante, el soporte de Web Start se incluye en el JRE / JDK.
○ Para versiones anteriores, el soporte de Web Start se instala por separado.
○ La infraestructura de Web Start incluye algunos Javascript que se pueden incluir en
una página web para ayudar al usuario a instalar el software necesario.
• El servidor web que aloja el software debe estar accesible para la máquina de destino.
• Si el usuario va a iniciar una aplicación Web Start utilizando un enlace en una página web,
entonces:
https://riptutorial.com/es/home 364
Un ejemplo de archivo JNLP
El siguiente ejemplo pretende ilustrar la funcionalidad básica de JNLP.
Como puede ver, un archivo JNLP está basado en XML y toda la información está contenida en el
elemento <jnlp> .
• El atributo spec proporciona la versión de la especificación JNPL que cumple este archivo.
• El atributo codebase proporciona la URL base para resolver las URL href relativas en el resto
del archivo.
• El atributo href proporciona la URL definitiva para este archivo JNLP.
• El elemento <information> contiene metadatos de la aplicación, incluidos su título, autores,
descripción y sitio web de ayuda.
• El elemento <resources> describe las dependencias para la aplicación, incluida la versión de
Java, la plataforma del sistema operativo y los archivos JAR requeridos.
• El elemento <application-desc> (o <applet-desc> ) proporciona la información necesaria para
iniciar la aplicación.
El archivo JNLP y los archivos JAR de la aplicación deben instalarse en el servidor web para que
estén disponibles utilizando las URL indicadas por el archivo JNLP.
https://riptutorial.com/es/home 365
en el servidor web.
• Si puede asumir que Java Web Start ya está instalado en la máquina del usuario, entonces
la página web simplemente necesita contener un enlace para iniciar la aplicación. Por
ejemplo.
NOTA: es una mala idea animar a los usuarios a animar a instalar Java de esta manera, o incluso
habilitar Java en sus navegadores web para que el lanzamiento de la página web JNLP funcione.
$ javaws <url>
Un requisito común para una aplicación Java es que puede implementarse copiando un solo
archivo. Para aplicaciones simples que dependen solo de las bibliotecas de clases estándar de
Java SE, este requisito se cumple creando un archivo JAR que contiene todas las clases de
aplicaciones (compiladas).
Las cosas no son tan sencillas si la aplicación depende de bibliotecas de terceros. Si simplemente
coloca los archivos JAR de dependencia dentro de un JAR de aplicación, el cargador de clases
Java estándar no podrá encontrar las clases de la biblioteca y su aplicación no se iniciará. En su
lugar, debe crear un solo archivo JAR que contenga las clases de la aplicación y los recursos
asociados junto con las clases de dependencia y los recursos. Estos deben organizarse como un
único espacio de nombres para que el cargador de clases busque.
https://riptutorial.com/es/home 366
simplicidad. Los comandos deben ser idénticos para Mac OS y similares para Windows).
$ mkdir tempDir
$ cd tempDir
2. Para cada archivo JAR dependiente, en el orden inverso al que deben aparecer en la ruta
de clase de la aplicación, usó el comando jar para descomprimir el JAR en el directorio
temporal.
Al hacer esto para múltiples archivos JAR se superpondrán los contenidos de los JAR.
$ cp -r path/to/classes .
Además, si usa una herramienta adecuada para crear UberJAR, tendrá la opción de excluir las
clases de biblioteca que no se usan del archivo JAR. Sin embargo, esto se hace típicamente
mediante análisis estático de las clases. Si su aplicación utiliza la reflexión, el procesamiento de
anotaciones y técnicas similares, debe tener cuidado de que las clases no se excluyan
incorrectamente.
https://riptutorial.com/es/home 367
Los UberJAR también tienen algunas desventajas:
• Si tiene muchos UberJAR con las mismas dependencias, cada uno contendrá una copia de
las dependencias.
• Algunas bibliotecas de código abierto tienen licencias que puede impedir su uso 1 en un
UberJAR.
1 - Algunas licencias de biblioteca de código abierto le permiten usar la biblioteca, solo si el usuario final puede
reemplazar una versión de la biblioteca por otra. UberJARs puede dificultar el reemplazo de dependencias de
versión.
https://riptutorial.com/es/home 368
Capítulo 55: Dividir una cadena en partes de
longitud fija
Observaciones
El objetivo aquí es no perder contenido, por lo que la expresión regular no debe consumir (igualar)
ninguna entrada. En su lugar, debe coincidir entre el último carácter de la entrada de destino
anterior y el primer carácter de la siguiente entrada de destino. por ejemplo, para las subcadenas
de 8 caracteres, necesitamos dividir la entrada (es decir, hacer coincidir) en los lugares marcados
a continuación:
a b c d e f g h i j k l m n o p q r s t u v w x y z
^ ^ ^
Ignore los espacios en la entrada que fueron necesarios para mostrar entre las posiciones de los
caracteres.
Examples
Rompe una cuerda en subcadenas, todas de una longitud conocida
El truco es usar un look-behind con el regex \G , que significa "final de la coincidencia anterior":
La expresión regular coincide con 8 caracteres después del final de la última coincidencia. Como
en este caso la coincidencia es de ancho cero, podríamos decir más simplemente "8 caracteres
después de la última coincidencia".
Igual que el ejemplo de longitud conocida, pero inserte la longitud en expresiones regulares:
int length = 5;
String[] parts = str.split("(?<=\\G.{" + length + "})");
https://riptutorial.com/es/home 369
Capítulo 56: Documentando el código de
Java
Introducción
La documentación para el código java a menudo se genera utilizando javadoc . Javadoc fue
creado por Sun Microsystems con el propósito de generar documentación de API en formato
HTML desde el código fuente de Java. El uso del formato HTML brinda la comodidad de poder
vincular documentos relacionados entre sí.
Sintaxis
• / ** - inicio de JavaDoc en una clase, campo, método o paquete
• @author // Para nombrar al autor de la clase, interfaz o enumeración. Es requerido.
• @version // La versión de esa clase, interfaz o enumeración. Es requerido. Puede usar
macros como% I% o% G% para que el software de control de origen complete en el proceso
de pago.
• @param // Para mostrar los argumentos (parámetros) de un método o un constructor.
Especifique una etiqueta @param para cada parámetro.
• @return // Para mostrar los tipos de retorno para métodos no nulos.
• @exception // Muestra qué excepciones se pueden lanzar desde el método o el constructor.
Las excepciones que DEBEN ser capturadas deben enumerarse aquí. Si lo desea, también
puede incluir aquellos que no necesitan ser capturados, como
ArrayIndexOutOfBoundsException. Especifique una @excepción para cada excepción que
se pueda lanzar.
• @throws // Igual que @exception.
• @see // Enlaces a un método, campo, clase o paquete. Utilizar en la forma de
package.Class # algo.
• @since // Cuando este método, campo o clase fue agregado. Por ejemplo, JDK-8 para una
clase como java.util.Optional <T> .
• @serial, @serialField, @serialData // Se usa para mostrar el serialVersionUID.
• @deprecated // Para marcar una clase, método o campo como obsoleto. Por ejemplo, uno
sería java.io.StringBufferInputStream . Vea una lista completa de las clases en desuso
existentes aquí .
• {@link} // Similar a @see, pero se puede usar con texto personalizado: {@link
#setDefaultCloseOperation (int closeOperation) vea JFrame # setDefaultCloseOperation
para más información}.
• {@linkplain} // Similar a {@link}, pero sin la fuente del código.
• {@code} // Para código literal, como etiquetas HTML. Por ejemplo: {@code <html> </html>}.
Sin embargo, esto usará una fuente monoespaciada. Para obtener el mismo resultado sin la
fuente monoespaciado, use {@literal}.
• {@literal} // Igual que {@code}, pero sin la fuente monoespaciada.
• {@value} // Muestra el valor de un campo estático: El valor de JFrame # EXIT_ON_CLOSE
https://riptutorial.com/es/home 370
es {@value}. O, podría vincular a un campo determinado: utiliza el nombre de la aplicación
{@value AppConstants # APP_NAME}.
• {@docRoot} // La carpeta raíz del HTML de JavaDoc relativa al archivo actual. Ejemplo: <a
href="{@docRoot}/credits.html"> Créditos </a>.
• Se permite HTML: <code> "Hola cookies" .substring (3) </code>.
• * / - final de la declaración de JavaDoc
Observaciones
Javadoc es una herramienta incluida con el JDK que permite que los comentarios en código se
conviertan a una documentación HTML. La especificación de la API de Java se generó utilizando
Javadoc. Lo mismo es cierto para gran parte de la documentación de las bibliotecas de terceros.
Examples
Documentación de la clase
/**
* Brief summary of this class, ending with a period.
*
* It is common to leave a blank line between the summary and further details.
* The summary (everything before the first period) is used in the class or package
* overview section.
*
* The following inline tags can be used (not an exhaustive list):
* {@link some.other.class.Documentation} for linking to other docs or symbols
* {@link some.other.class.Documentation Some Display Name} the link's appearance can be
* customized by adding a display name after the doc or symbol locator
* {@code code goes here} for formatting as code
* {@literal <>[]()foo} for interpreting literal text without converting to HTML markup
* or other tags.
*
* Optionally, the following tags may be used at the end of class documentation
* (not an exhaustive list):
*
* @author John Doe
* @version 1.0
* @since 5/10/15
* @see some.other.class.Documentation
* @deprecated This class has been replaced by some.other.package.BetterFileReader
*
* You can also have custom tags for displaying additional information.
* Using the @custom.<NAME> tag and the -tag custom.<NAME>:htmltag:"context"
* command line option, you can create a custom tag.
*
* Example custom tag and generation:
* @custom.updated 2.0
* Javadoc flag: -tag custom.updated:a:"Updated in version:"
https://riptutorial.com/es/home 371
* The above flag will display the value of @custom.updated under "Updated in version:"
*
*/
public class FileReader {
}
Las mismas etiquetas y formato que se usan para las Classes se pueden usar para Enums e
Interfaces .
Método de Documentación
/**
* Brief summary of method, ending with a period.
*
* Further description of method and what it does, including as much detail as is
* appropriate. Inline tags such as
* {@code code here}, {@link some.other.Docs}, and {@literal text here} can be used.
*
* If a method overrides a superclass method, {@inheritDoc} can be used to copy the
* documentation
* from the superclass method
*
* @param stream Describe this parameter. Include as much detail as is appropriate
* Parameter docs are commonly aligned as here, but this is optional.
* As with other docs, the documentation before the first period is
* used as a summary.
*
* @return Describe the return values. Include as much detail as is appropriate
* Return type docs are commonly aligned as here, but this is optional.
* As with other docs, the documentation before the first period is used as a
* summary.
*
* @throws IOException Describe when and why this exception can be thrown.
* Exception docs are commonly aligned as here, but this is
* optional.
* As with other docs, the documentation before the first period
* is used as a summary.
* Instead of @throws, @exception can also be used.
*
* @since 2.1.0
* @see some.other.class.Documentation
* @deprecated Describe why this method is outdated. A replacement can also be specified.
*/
public String[] read(InputStream stream) throws IOException {
return null;
}
Documentacion de campo
https://riptutorial.com/es/home 372
puede comenzar con espacios en blanco arbitrarios y un solo asterisco; estos se ignoran cuando
se generan los archivos de documentación.
/**
* Fields can be documented as well.
*
* As with other javadocs, the documentation before the first period is used as a
* summary, and is usually separated from the rest of the documentation by a blank
* line.
*
* Documentation for fields can use inline tags, such as:
* {@code code here}
* {@literal text here}
* {@link other.docs.Here}
*
* Field documentation can also make use of the following tags:
*
* @since 2.1.0
* @see some.other.class.Documentation
* @deprecated Describe why this field is outdated
*/
public static final String CONSTANT_STRING = "foo";
Java SE 5
/**
* Package documentation goes here; any documentation before the first period will
* be used as a summary.
*
* It is common practice to leave a blank line between the summary and the rest
* of the documentation; use this space to describe the package in as much detail
* as is appropriate.
*
* Inline tags such as {@code code here}, {@link reference.to.other.Documentation},
* and {@literal text here} can be used in this documentation.
*/
package com.example.foo;
En el caso anterior, debe colocar este archivo package-info.java dentro de la carpeta del paquete
de Java com.example.foo .
Campo de golf
https://riptutorial.com/es/home 373
/**
* You can link to the javadoc of an already imported class using {@link ClassName}.
*
* You can also use the fully-qualified name, if the class is not already imported:
* {@link some.other.ClassName}
*
* You can link to members (fields or methods) of a class like so:
* {@link ClassName#someMethod()}
* {@link ClassName#someMethodWithParameters(int, String)}
* {@link ClassName#someField}
* {@link #someMethodInThisClass()} - used to link to members in the current class
*
* You can add a label to a linked javadoc like so:
* {@link ClassName#someMethod() link text}
*/
Con la etiqueta @see puede agregar elementos a la sección Vea también . Como @param o @return
el lugar donde aparecen no es relevante. La especificación dice que debes escribirlo después de
@return .
/**
* This method has a nice explanation but you might found further
* information at the bottom.
*
* @see ClassName#someMethod()
*/
Si desea agregar enlaces a recursos externos, solo puede usar la etiqueta HTML <a> . Puede
usarlo en línea en cualquier lugar o dentro de las etiquetas @link y @see .
/**
* Wondering how this works? You might want
* to check this <a href="http://stackoverflow.com/">great service</a>.
*
* @see <a href="http://stackoverflow.com/">Stack Overflow</a>
*/
https://riptutorial.com/es/home 374
Construyendo Javadocs desde la línea de comando
Muchos IDE proporcionan soporte para generar HTML desde Javadocs automáticamente;
Algunas herramientas de compilación ( Maven y Gradle , por ejemplo) también tienen
complementos que pueden manejar la creación de HTML.
Sin embargo, estas herramientas no son necesarias para generar el HTML Javadoc; Esto se
puede hacer utilizando la herramienta de línea de comandos javadoc .
javadoc JavaFile.java
Un uso más práctico de la herramienta de línea de comandos, que leerá recursivamente todos los
archivos java en [source-directory] , creará la documentación para [package.name] y todos los
subpaquetes, y colocará el HTML generado en el [docs-directory] es:
Los comentarios de una sola línea se inician con // y se pueden colocar después de una
declaración en la misma línea, pero no antes.
Los comentarios multilínea se definen entre /* y */ . Pueden abarcar varias líneas e incluso
pueden colocarse entre sentencias.
/*
multi
line
comment
*/
object/*inner-line-comment*/.method();
https://riptutorial.com/es/home 375
}
Los JavaDocs son una forma especial de comentarios de varias líneas, comenzando con /** .
Como demasiados comentarios en línea pueden disminuir la legibilidad del código, se deben usar
de forma dispersa en caso de que el código no se explique lo suficiente o la decisión de diseño no
sea obvia.
Un caso de uso adicional para los comentarios de una sola línea es el uso de TAG, que son
palabras clave cortas y basadas en convenciones. Algunos entornos de desarrollo reconocen
ciertas convenciones para dichos comentarios individuales. Ejemplos comunes son
• //TODO
• //FIXME
• //PRJ-1234
/**
* The Class TestUtils.
* <p>
* This is an {@code inline("code example")}.
* <p>
* You should wrap it in pre tags when writing multiline code.
* <pre>{@code
* Example example1 = new FirstLineExample();
* example1.butYouCanHaveMoreThanOneLine();
* }</pre>
* <p>
* Thanks for reading.
*/
class TestUtils {
A veces es posible que necesite poner un código complejo dentro del comentario javadoc. El
signo @ es especialmente problemático. El uso de la etiqueta <code> antigua junto con la
construcción {@literal } resuelve el problema.
/**
* Usage:
* <pre><code>
* class SomethingTest {
* {@literal @}Rule
* public SingleTestRule singleTestRule = new SingleTestRule("test1");
*
* {@literal @}Test
* public void test1() {
* // only this test will be executed
* }
https://riptutorial.com/es/home 376
*
* ...
* }
* </code></pre>
*/
class SingleTestRule implements TestRule { }
https://riptutorial.com/es/home 377
Capítulo 57: E / S de consola
Examples
Lectura de entrada de usuario desde la consola.
Utilizando BufferedReader :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
Utilizando Scanner :
Java SE 5
import java.util.Scanner;
System.out.println("Please enter your first and your last name, on separate lines.");
https://riptutorial.com/es/home 378
Hay dos métodos para obtener Strings , next() y nextLine() . next() devuelve el texto hasta el
primer espacio (también conocido como "token"), y nextLine() devuelve todo el texto que el
usuario ingresó hasta presionar intro.
Scanner también proporciona métodos de utilidad para leer tipos de datos que no sean String .
Éstos incluyen:
scanner.nextByte();
scanner.nextShort();
scanner.nextInt();
scanner.nextLong();
scanner.nextFloat();
scanner.nextDouble();
scanner.nextBigInteger();
scanner.nextBigDecimal();
El prefijo de cualquiera de estos métodos con has (como en hasNextLine() , hasNextInt() ) devuelve
true si el flujo tiene más del tipo de solicitud. Nota: estos métodos bloquearán el programa si la
entrada no es del tipo solicitado (por ejemplo, al escribir "a" para nextInt() ). Puede usar un try {}
catch() {} para evitar esto (ver: Excepciones )
Utilizando System.console :
Java SE 6
Ventajas :
Nota : Esto solo funcionará si el programa se ejecuta desde una línea de comando real sin
redirigir las secuencias de entrada y salida estándar. No funciona cuando el programa se ejecuta
desde ciertos IDE, como Eclipse. Para el código que funciona dentro de los IDE y con la
https://riptutorial.com/es/home 379
redirección de flujos, vea los otros ejemplos.
private static final String CMD_QUIT = "quit"; //string for exiting the program
private static final String CMD_HELLO = "hello"; //string for printing "Hello World!"
on the screen
private static final String CMD_ANSWER = "answer"; //string for printing 42 on the
screen
try {
claimCli.start(); //calls the start function to do the work like console
}
catch (IOException e) {
e.printStackTrace(); //prints the exception log if it is failed to do get the
user input or something like that
}
}
cmd = reader.readLine(); //takes input from user. user input should be started
with "hello", "answer" or "quit"
String[] cmdArr = cmd.split(" ");
// prints "Hello World!" on the screen if user input starts with "hello"
private void hello(String[] cmdArr) {
System.out.println("Hello World!");
}
https://riptutorial.com/es/home 380
}
}
Salida:
1 1 1
1234 1234 1234
1234567 1234567 123456
123456789 12345678 123456
El uso de cadenas de formato con permisos de tamaño fijo para imprimir las cadenas en una
apariencia similar a una tabla con columnas de tamaño fijo:
Salida:
1 1 1
123 1234 1234
https://riptutorial.com/es/home 381
123 1234567 123456
123 12345678 123456
https://riptutorial.com/es/home 382
Capítulo 58: Ediciones, versiones,
lanzamientos y distribuciones de Java
Examples
Diferencias entre las distribuciones Java SE JRE o Java SE JDK
Las versiones de Sun / Oracle de Java SE vienen en dos formas: JRE y JDK. En términos
simples, los JRE admiten la ejecución de aplicaciones Java y los JDK también admiten el
desarrollo de Java.
• El comando java para ejecutar un programa Java en una JVM (Java Virtual Machine)
• El comando jjs para ejecutar el motor de Javascript de Nashorn.
• El comando keytool para manipular los almacenes de claves de Java.
• El comando policytool para editar las políticas de seguridad de sandbox.
• Las herramientas pack200 y unpack200 para empaquetar y desempaquetar el archivo
"pack200" para el despliegue web.
• Los orbd , rmid , rmiregistry y tnameserv que admiten aplicaciones Java CORBA y RMI.
Los instaladores de "Desktop JRE" incluyen un complemento de Java adecuado para algunos
navegadores web. Esto se deja deliberadamente fuera de "Server JRE" installers.linux syscall
read benchmarku
A partir de la actualización 6 de Java 7, los instaladores de JRE han incluido JavaFX (versión 2.2
o posterior).
• El comando javac , que compila el código fuente de Java (".java") en archivos de código de
bytes (".class").
• Las herramientas para crear archivos JAR como jar y jarsigner
• Herramientas de desarrollo tales como:
○appletviewer para ejecutar applets
○idlj el IDL CORBA al compilador de Java
https://riptutorial.com/es/home 383
○ el generador de javah JNI
javah
○native2ascii para la conversión de native2ascii de caracteres del código fuente de
Java
○schemagen el generador de esquemas de Java a XML (parte de JAXB)
○serialver generar la cadena de versión de Java Object Serialization.
○wsgen herramientas de soporte wsgen y wsimport para JAX-WS
• Herramientas de diagnóstico tales como:
○jdb el depurador de Java básico
○jmap y jhat para descargar y analizar un montón de Java.
○jstack para obtener un volcado de pila de hilos.
○javap para examinar archivos ".class".
• Gestión de aplicaciones y herramientas de monitoreo tales como:
○jconsole una consola de gestión,
○jstat , jstatd , jinfo y jps para monitoreo de aplicaciones
Una instalación típica de Sun / Oracle JDK también incluye un archivo ZIP con el código fuente de
las bibliotecas de Java. Antes de Java 6, este era el único código fuente de Java disponible
públicamente.
Desde Java 6 en adelante, el código fuente completo de OpenJDK está disponible para su
descarga desde el sitio de OpenJDK. Normalmente no se incluye en los paquetes JDK (Linux),
pero está disponible como un paquete separado.
Ortogonal a la dicotomía JRE versus JDK, hay dos tipos de versión de Java que están
ampliamente disponibles:
• Las versiones de Oracle Hotspot son las que se descargan de los sitios de descarga de
Oracle.
• Las versiones de OpenJDK son las que se crean (normalmente por proveedores de
terceros) a partir de los repositorios de origen de OpenJDK.
En términos funcionales, hay poca diferencia entre una versión de Hotspot y una versión de
OpenJDK. Hay algunas características "empresariales" adicionales en Hotspot que los clientes de
Oracle (de pago) de Java pueden habilitar, pero aparte de eso, la misma tecnología está presente
tanto en Hotspot como en OpenJDK.
Otra ventaja de Hotspot sobre OpenJDK es que las versiones de parches para Hotspot tienden a
estar disponibles un poco antes. Esto también depende de cuán ágil sea su proveedor de
OpenJDK; por ejemplo, cuánto tiempo tarda el equipo de compilación de una distribución de Linux
en preparar y realizar un control de calidad en una nueva compilación de OpenJDK y colocarla en
sus repositorios públicos.
La otra cara es que las versiones de Hotspot no están disponibles en los repositorios de paquetes
para la mayoría de las distribuciones de Linux. Esto significa que mantener su software Java
actualizado en una máquina con Linux generalmente es más trabajo si usa Hotspot.
https://riptutorial.com/es/home 384
Diferencias entre Java EE, Java SE, Java ME y JavaFX
Hay varias plataformas de Java. Muchos desarrolladores, incluso los desarrolladores de lenguajes
de programación Java de larga data, no entienden cómo las diferentes plataformas se relacionan
entre sí.
• Java FX
Todas las plataformas de Java consisten en una Máquina Virtual de Java (VM) y una interfaz de
programación de aplicaciones (API). La máquina virtual de Java es un programa, para una
plataforma de hardware y software en particular, que ejecuta aplicaciones de tecnología Java.
Una API es una colección de componentes de software que puede utilizar para crear otros
componentes de software o aplicaciones. Cada plataforma Java proporciona una máquina virtual
y una API, y esto permite que las aplicaciones escritas para esa plataforma se ejecuten en
cualquier sistema compatible con todas las ventajas del lenguaje de programación Java:
independencia de la plataforma, potencia, estabilidad, facilidad de desarrollo y seguridad.
Java SE
Cuando la mayoría de la gente piensa en el lenguaje de programación Java, piensa en la API de
Java SE. La API de Java SE proporciona la funcionalidad principal del lenguaje de programación
Java. Define todo, desde los tipos y objetos básicos del lenguaje de programación Java hasta las
clases de alto nivel que se utilizan para redes, seguridad, acceso a bases de datos, desarrollo de
interfaz gráfica de usuario (GUI) y análisis de XML.
Además de la API central, la plataforma Java SE consta de una máquina virtual, herramientas de
desarrollo, tecnologías de implementación y otras bibliotecas de clase y kits de herramientas que
se utilizan comúnmente en las aplicaciones de tecnología Java.
https://riptutorial.com/es/home 385
Java EE
La plataforma Java EE está construida sobre la plataforma Java SE. La plataforma Java EE
proporciona una API y un entorno de tiempo de ejecución para desarrollar y ejecutar aplicaciones
de red a gran escala, de múltiples niveles, escalables, confiables y seguras.
Java ME
La plataforma Java ME proporciona una API y una máquina virtual de tamaño reducido para
ejecutar aplicaciones de lenguaje de programación Java en dispositivos pequeños, como
teléfonos móviles. La API es un subconjunto de la API de Java SE, junto con bibliotecas de clases
especiales útiles para el desarrollo de aplicaciones de dispositivos pequeños. Las aplicaciones
Java ME son a menudo clientes de los servicios de la plataforma Java EE.
Java FX
La tecnología Java FX es una plataforma para crear aplicaciones de Internet enriquecidas escritas
en Java FX ScriptTM. Java FX Script es un lenguaje declarativo de tipo estático que se compila
en el bytecode de la tecnología Java, que luego se puede ejecutar en una máquina virtual Java.
Las aplicaciones escritas para la plataforma Java FX pueden incluir y vincular clases de lenguaje
de programación Java y pueden ser clientes de los servicios de la plataforma Java EE.
Versiones de Java SE
https://riptutorial.com/es/home 386
Fin de la vida Fecha de
Java SE versión 1 Nombre clave
(libre 2 ) lanzamiento
Notas al pie:
1. Los enlaces son para copias en línea de la documentación de las versiones respectivas en
el sitio web de Oracle. La documentación de muchas versiones anteriores ya no está en
línea, aunque normalmente se puede descargar desde los Archivos Java de Oracle.
2. La mayoría de las versiones históricas de Java SE han pasado sus fechas oficiales de "fin
de vida". Cuando una versión de Java supera este hito, Oracle deja de proporcionarle
actualizaciones gratuitas. Las actualizaciones todavía están disponibles para los clientes
con contratos de soporte.
Fuente:
https://riptutorial.com/es/home 387
Versión
de Java Reflejos
SE
Java SE La palabra clave strictfp . Swing APIs. El plugin de Java (para navegadores
1.2 web). Interoperabilidad CORBA. Marco de colecciones.
Fuente:
https://riptutorial.com/es/home 388
Capítulo 59: Ejecutor, ExecutorService y
grupos de subprocesos
Introducción
La interfaz de Executor en Java proporciona una forma de desacoplar el envío de tareas de la
mecánica de cómo se ejecutará cada tarea, incluidos los detalles del uso de subprocesos, la
programación, etc. Normalmente se utiliza un Ejecutor en lugar de crear subprocesos
explícitamente. Con los Ejecutores, los desarrolladores no tendrán que reescribir
significativamente su código para poder ajustar fácilmente la política de ejecución de tareas de su
programa.
Observaciones
Escollos
Examples
Fuego y olvido - Tareas ejecutables
El uso sería:
Tenga en cuenta que con este ejecutor, no tiene medios para recuperar ningún valor calculado.
Con Java 8, uno puede utilizar lambdas para acortar el ejemplo de código.
Java SE 8
https://riptutorial.com/es/home 389
ThreadPoolExecutor
Un Ejecutor común que se usa es el ThreadPoolExecutor , que se encarga del manejo de Thread.
Puede configurar la cantidad mínima de subprocesos que el ejecutor siempre debe mantener
cuando no hay mucho que hacer (se denomina tamaño del núcleo) y un tamaño máximo de
subprocesos en el que la agrupación puede crecer, si hay más trabajo por hacer. Una vez que la
carga de trabajo disminuye, el Grupo reduce lentamente el número de subprocesos nuevamente
hasta que alcanza el tamaño mínimo.
pool.execute(new Runnable() {
@Override public void run() {
//code to run
}
});
de JavaDoc
Ventajas:
https://riptutorial.com/es/home 390
velocidad a la que se envían las nuevas tareas.
Si su cómputo produce algún valor de retorno que luego se requiere, una simple tarea Ejecutable
no es suficiente. Para tales casos, puede usar ExecutorService.submit( Callable <T>) que devuelve
un valor una vez que se completa la ejecución.
El Servicio devolverá un Future que puede utilizar para recuperar el resultado de la ejecución de la
tarea.
try {
// Blocks current thread until future is completed
Integer result = future.get();
catch (InterruptedException || ExecutionException e) {
// handle appropriately
}
try {
// Blocks current thread for a maximum of 500 milliseconds.
// If the future finishes before that, result is returned,
https://riptutorial.com/es/home 391
// otherwise TimeoutException is thrown.
Integer result = future.get(500, TimeUnit.MILLISECONDS);
catch (InterruptedException || ExecutionException || TimeoutException e) {
// handle appropriately
}
https://riptutorial.com/es/home 392
La ejecución de la tarea continuará de acuerdo con el cronograma hasta que la pool se cierre, el
future se cancele o una de las tareas encuentre una excepción.
Se garantiza que las tareas programadas por una llamada scheduledAtFixedRate AtFixedRate no se
superpondrán en el tiempo. Si una tarea lleva más tiempo que el período prescrito, las
ejecuciones de la siguiente tarea y las posteriores pueden comenzar tarde.
La ejecución de la tarea continuará de acuerdo con el cronograma hasta que la pool se cierre, el
future se cancele o una de las tareas encuentre una excepción.
Si
RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) .
https://riptutorial.com/es/home 393
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) // <--
Generalmente, el comando de ejecución () se usa para las llamadas de disparo y olvido (sin
necesidad de analizar el resultado) y el comando de envío () se usa para analizar el resultado del
objeto futuro.
Caso 1: envíe el comando Ejecutable con ejecutar (), que informa la Excepción.
import java.util.concurrent.*;
import java.util.*;
https://riptutorial.com/es/home 394
class ExtendedExecutor extends ThreadPoolExecutor {
public ExtendedExecutor() {
super(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
}
// ...
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
System.out.println(t);
}
}
salida:
creating service
a and b=4:0
a and b=4:0
Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-2"
java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caso 2: Reemplace execute () con submit (): service.submit(new Runnable(){ En este caso,
Framework se traga las excepciones ya que el método run () no las detectó explícitamente.
salida:
creating service
a and b=4:0
a and b=4:0
salida:
https://riptutorial.com/es/home 395
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
a and b=4:0
java.lang.ArithmeticException: / by zero
He demostrado este ejemplo para cubrir dos temas: Use su ThreadPoolExecutor personalizado y
maneje Exectpion con ThreadPoolExecutor personalizado.
Otra solución simple al problema anterior: cuando está utilizando el comando ExecutorService
& submit normal, obtenga el objeto Future del comando submit () call call get () en Future. Capte
las tres excepciones, que se han citado en la implementación del método afterExecute. Ventaja
de ThreadPoolExecutor personalizado sobre este enfoque: tiene que manejar el mecanismo de
manejo de excepciones en un solo lugar: ThreadPoolExecutor personalizado.
1. EjecutorServicio
2. CountDownLatch
Casos de uso:
3. Detección de interbloqueo.
https://riptutorial.com/es/home 396
.
Java 8 ha introducido una API más en ExecutorService para crear un grupo de robo de
trabajo. No tiene que crear RecursiveTask y RecursiveAction pero aún puede usar ForkJoinPool
.
Todos estos cuatro mecanismos son complementarios entre sí. Dependiendo del nivel de
granularidad que desee controlar, debe elegir los correctos.
Echemos un vistazo a varias opciones para esperar a que se completen las tareas enviadas a
Executor
1. ExecutorService invokeAll()
Ejecuta las tareas dadas, devolviendo una lista de futuros que mantienen su
https://riptutorial.com/es/home 397
estado y resultados cuando todo está completado.
Ejemplo:
import java.util.concurrent.*;
import java.util.*;
2. CountDownLatch
Una ayuda de sincronización que permite que uno o más subprocesos esperen
hasta que se complete un conjunto de operaciones que se están realizando en
otros subprocesos.
https://riptutorial.com/es/home 398
4. Iterar a través de todos los objetos Future creados después de enviar a ExecutorService
En el ejemplo anterior, si sus tareas tardan más tiempo en completarse, puede cambiar si la
condición se convierte en condición condicional.
Reemplazar
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
con
while(!pool.awaitTermination(60, TimeUnit.SECONDS)) {
Thread.sleep(60000);
Crea un Ejecutor que utiliza un único subproceso de trabajo que opera en una
cola ilimitada
https://riptutorial.com/es/home 399
Hay una diferencia entre newFixedThreadPool(1) y newSingleThreadExecutor() como dice el
documento java para este último:
Casos de uso:
Contras:
Casos de uso:
Contras:
Casos de uso:
Contras:
https://riptutorial.com/es/home 400
1. La cola no unida es dañina.
2. Cada nueva tarea creará un nuevo hilo si todos los hilos existentes están ocupados. Si
la tarea está tomando una larga duración, se crearán más hilos, lo que degradará el
rendimiento del sistema. Alternativa en este caso: newFixedThreadPool
Casos de uso:
Contras:
Casos de uso:
Contras:
Puede ver un inconveniente común en todos estos ExecutorService: cola ilimitada. Esto será
abordado con ThreadPoolExecutor
https://riptutorial.com/es/home 401
Uso de grupos de subprocesos
Se pueden usar los siguientes métodos para enviar trabajo para ejecución:
Método Descripción
Ejecuta el trabajo enviado y devuelve un futuro que puede usarse para obtener el
submit
resultado.
Ejecuta todo pero devuelve solo el resultado de uno que ha sido exitoso (sin
invokeAny
excepciones)
Una vez que haya terminado con el grupo de subprocesos, puede llamar a shutdown() para
terminar el grupo de subprocesos. Esto ejecuta todas las tareas pendientes. Para esperar a que
se ejecuten todas las tareas, puede recorrer awaitTermination o isShutdown() .
https://riptutorial.com/es/home 402
Capítulo 60: El classpath
Introducción
La ruta de clase enumera los lugares donde el tiempo de ejecución de Java debe buscar clases y
recursos. El compilador de Java también utiliza la ruta de clase para encontrar dependencias
compiladas previamente y externas.
Observaciones
Carga de clases de Java
La JVM (Java Virtual Machine) cargará las clases a medida que se requieran las clases (esto se
denomina carga lenta). Las ubicaciones de las clases que se utilizarán se especifican en tres
lugares:
1. Los requeridos por la plataforma Java se cargan primero, como los de la biblioteca de
clases de Java y sus dependencias.
2. Las clases de extensión se cargan a continuación (es decir, aquellas en jre/lib/ext/ )
3. Luego se cargan las clases definidas por el usuario a través del classpath.
Las clases se cargan utilizando clases que son subtipos de java.lang.ClassLoader . Esto se
describe con más detalle en este tema: Cargadores de clases .
Classpath
El classpath es un parámetro utilizado por la JVM o compilador que especifica las ubicaciones de
las clases y los paquetes definidos por el usuario. Esto se puede establecer en la línea de
comandos como en la mayoría de estos ejemplos o mediante una variable de entorno ( CLASSPATH )
Examples
Diferentes formas de especificar el classpath.
https://riptutorial.com/es/home 403
Tenga en cuenta que la -classpath (o -cp ) tiene prioridad sobre la variable de entorno
CLASSPATH .
Tenga en cuenta que esto solo se aplica cuando el archivo JAR se ejecuta así:
Relacionado:
• https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html
• http://docs.oracle.com/javase/7/docs/technotes/tools/windows/classpath.html
Si desea agregar todos los archivos JAR en el directorio a la ruta de clase, puede hacer esto de
manera concisa usando la sintaxis de comodín de la ruta de clase; por ejemplo:
someFolder/*
Esto le indica a la JVM que agregue todos los archivos JAR y ZIP en el directorio someFolder a la
ruta de someFolder . Esta sintaxis se puede usar en un argumento -cp , una variable de entorno
CLASSPATH o un atributo Class-Path en el archivo de manifiesto de un archivo JAR ejecutable.
Consulte Configuración de la ruta de clase: comodines de ruta de clase para ver ejemplos y
advertencias.
Notas:
1. Los comodines de Classpath se introdujeron por primera vez en Java 6. Las versiones
anteriores de Java no tratan a "*" como un comodín.
2. No puede poner otros caracteres antes o después de " "; por ejemplo, "someFolder / .jar" no
es un comodín.
3. Un comodín coincide solo con archivos con el sufijo ".jar" o ".JAR". Los archivos ZIP se
ignoran, al igual que los archivos JAR con sufijos diferentes.
4. Un comodín solo coincide con los archivos JAR en el directorio, no en sus subdirectorios.
5. Cuando un grupo de archivos JAR coincide con una entrada de comodín, no se especifica
su orden relativo en la ruta de clase.
https://riptutorial.com/es/home 404
Sintaxis de ruta de clase
La ruta de clase es una secuencia de entradas que son nombres de ruta de directorio, nombres
de ruta de archivos JAR o ZIP o especificaciones de comodín JAR / ZIP.
• Para una ruta de clase especificada en la línea de comando (por ejemplo, -classpath ) o
como una variable de entorno, las entradas deben estar separadas con ; (punto y coma) en
Windows, o : (dos puntos) en otras plataformas (Linux, UNIX, MacOSX, etc.).
• Para el elemento Class-Path en MANIFEST.MF un archivo JAR, use un solo espacio para
separar las entradas.
Classpath dinámico
A veces, solo agregar todos los archivos JAR desde una carpeta no es suficiente, por ejemplo,
cuando tiene un código nativo y necesita seleccionar un subconjunto de archivos JAR. En este
caso, necesitas dos métodos main() . El primero construye un cargador de clases y luego usa este
cargador de clases para llamar al segundo main() .
Este es un ejemplo que selecciona el JAR nativo SWT correcto para su plataforma, agrega todos
los JAR de su aplicación y luego invoca el método main() real: Cree una aplicación SWT Java
multiplataforma
Puede ser útil cargar un recurso (imagen, archivo de texto, propiedades, KeyStore, ...) que está
empaquetado dentro de un JAR. Para este propósito, podemos usar los Class y ClassLoader s.
program.jar
|
\-com
\-project
|
https://riptutorial.com/es/home 405
|-file.txt
\-Test.class
Y queremos acceder al contenido de file.txt desde la clase Test . Podemos hacerlo preguntando
al cargador de clases:
InputStream is = Test.class.getClassLoader().getResourceAsStream("com/project/file.txt");
InputStream is = Test.class.getResourceAsStream("file.txt");
Usando el objeto de clase, la ruta es relativa a la clase en sí. Test.class estar nuestro Test.class
en el paquete com.project , al igual que file.txt , no necesitamos especificar ninguna ruta.
Sin embargo, podemos usar rutas absolutas desde el objeto de clase, de esta manera:
is = Test.class.getResourceAsStream("/com/project/file.txt");
• Para las clases en el paquete predeterminado, las rutas de acceso son nombres de archivos
simples.
• Para las clases en un paquete con nombre, los componentes del nombre del paquete se
asignan a directorios.
• Para las clases anidadas e internas nombradas, el componente de nombre de archivo se
forma al unir los nombres de clase con un carácter $ .
• Para las clases internas anónimas, los números se utilizan en lugar de los nombres.
https://riptutorial.com/es/home 406
Nombre de la clase Fuente de acceso Nombre de archivo
El propósito del classpath es decirle a una JVM dónde encontrar clases y otros recursos. El
significado de la ruta de clase y el proceso de búsqueda están entrelazados.
El classpath es una forma de ruta de búsqueda que especifica una secuencia de ubicaciones para
buscar recursos. En una ruta de clase estándar, estos lugares son un directorio en el sistema de
archivos del host, un archivo JAR o un archivo ZIP. En cada caso, la ubicación es la raíz de un
espacio de nombres que se buscará.
El procedimiento para buscar un recurso en la ruta de clase depende de si la ruta del recurso es
absoluta o relativa. Para una ruta de recursos absoluta, el procedimiento es el anterior. Para una
ruta de recursos relativa resuelta utilizando Class.getResource o Class.getResourceAsStream , la ruta
para el paquete de clases se añade antes de la búsqueda.
(Tenga en cuenta que estos son los procedimientos implementados por los cargadores de clases
Java estándar. Un cargador de clases personalizado podría realizar la búsqueda de manera
diferente).
Los cargadores de clases de Java normales buscan clases primero en la ruta de clase de rutina
de carga, antes de verificar las extensiones y la ruta de clase de la aplicación. De forma
predeterminada, la ruta de clase de arranque consta del archivo "rt.jar" y algunos otros archivos
JAR importantes que se suministran con la instalación de JRE. Estos proporcionan todas las
clases en la biblioteca de clases estándar de Java SE, junto con varias clases de implementación
"internas".
https://riptutorial.com/es/home 407
comandos como java , javac , etc. usarán las versiones apropiadas de las bibliotecas de tiempo
de ejecución.
El comando java proporciona las siguientes opciones -X para modificar la ruta de clase de
arranque:
Tenga en cuenta que cuando utiliza las opciones de la ruta de inicio para reemplazar o anular una
clase de Java (etcétera), técnicamente está modificando Java. Puede haber implicaciones de
licencia si luego distribuye su código. (Consulte los términos y condiciones de la licencia binaria
de Java ... y consulte a un abogado).
https://riptutorial.com/es/home 408
Capítulo 61: El Comando de Java - 'java' y
'javaw'
Sintaxis
• java [ <opt> ... ] <class-name> [ <argument> ... ]
Observaciones
El comando java se utiliza para ejecutar una aplicación Java desde la línea de comandos. Está
disponible como parte de cualquier Java SE JRE o JDK.
En otros sistemas (por ejemplo, Linux, Mac OSX, UNIX) solo se proporciona el comando java y no
se abre una nueva ventana de consola.
El símbolo <opt> en la sintaxis denota una opción en la línea de comando java . Los temas
"Opciones de Java" y "Opciones de tamaño de pila y pila" cubren las opciones más utilizadas.
Otros están cubiertos en el tema Banderas JVM .
Examples
Ejecutando un archivo JAR ejecutable
Los archivos JAR ejecutables son la forma más sencilla de ensamblar código Java en un solo
archivo que se puede ejecutar. * (Nota editorial: la creación de archivos JAR debe estar cubierta
por un tema separado.) *
Suponiendo que tiene un archivo JAR ejecutable con la ruta de acceso <jar-path> , debería poder
ejecutarlo de la siguiente manera:
https://riptutorial.com/es/home 409
antes que la opción -jar . Tenga en cuenta que una opción -cp / -classpath se ignorará si utiliza -
jar . La ruta de clase de la aplicación está determinada por el archivo JAR manifiesto.
java HelloWorld
Especificando un classpath
A menos que estemos usando la sintaxis del comando java -jar , el comando java busca la clase
que se cargará buscando la ruta de clase; ver el classpath . El comando anterior se basa en que
la ruta de clase predeterminada es (o incluye) el directorio actual. Podemos ser más explícitos
sobre esto especificando la ruta de -cp que se usará usando la opción -cp .
Esto dice que hacer que el directorio actual (que es a lo que "." Se refiere) sea la única entrada en
el classpath.
El -cp es una opción que es procesada por el comando java . Todas las opciones destinadas al
comando java deben estar antes del nombre de clase. Cualquier cosa después de la clase se
tratará como un argumento de línea de comando para la aplicación Java y se pasará a la
aplicación en la String[] que se pasa al método main .
(Si no se proporciona la opción -cp , java usará la ruta de clase que proporciona la variable de
entorno CLASSPATH . Si esa variable no está establecida o está vacía, java usa "." Como la ruta de
clase predeterminada).
https://riptutorial.com/es/home 410
Clases de punto de entrada
Una clase de punto de entrada Java tiene un método main con la siguiente firma y modificadores:
Nota al margen: debido a cómo funcionan las matrices, también puede ser (String
args[])
Cuando el comando java inicia la máquina virtual, carga las clases de punto de entrada
especificadas e intenta encontrar las main . Si tiene éxito, los argumentos de la línea de comando
se convierten en objetos de String Java y se ensamblan en una matriz. Si main se invoca así, la
matriz no será null y no contendrá ninguna entrada null .
Es convencional declarar la clase como public pero esto no es estrictamente necesario. Desde
Java 5 en adelante, el tipo de argumento del método main puede ser una String varargs en lugar
de una cadena de cadenas. Opcionalmente, main puede lanzar excepciones, y su parámetro
puede tener cualquier nombre, pero convencionalmente es args .
• Extender javafx.application.Application
• Sé public y no abstract
• No ser genérico o anidado
• Tener un constructor no-args public explícito o implícito
Este ejemplo cubre errores comunes con el uso del comando 'java'.
"Comando no encontrado"
Si recibe un mensaje de error como:
https://riptutorial.com/es/home 411
java: command not found
cuando intenta ejecutar el comando java , esto significa que no hay un comando java en la ruta de
búsqueda de comandos de su shell. La causa podría ser:
Consulte "Instalación de Java" para conocer los pasos que debe seguir.
• Si tiene un código fuente para una clase, entonces el nombre completo consiste en el
nombre del paquete y el nombre de la clase simple. La instancia de la clase "Main" se
declara en el paquete "com.example.myapp" y su nombre completo es
"com.example.myapp.Main".
• Si tiene un archivo de clase compilado, puede encontrar el nombre de la clase
ejecutando javap en él.
• Si el archivo de clase está en un directorio, puede inferir el nombre completo de la
clase a partir de los nombres de directorio.
• Si el archivo de clase está en un archivo JAR o ZIP, puede inferir el nombre completo
de la clase a partir de la ruta del archivo en el archivo JAR o ZIP.
2. Mira el mensaje de error del comando java . El mensaje debe terminar con el nombre
completo de la clase que java está tratando de usar.
• Compruebe que coincida exactamente con el nombre de clase completo para la clase
de punto de entrada.
• No debe terminar con ".java" o ".class".
• No debe contener barras o ningún otro carácter que no sea legal en un identificador de
Java 1 .
• La carcasa del nombre debe coincidir exactamente con el nombre completo de la
clase.
https://riptutorial.com/es/home 412
3. Si está utilizando el nombre de clase correcto, asegúrese de que la clase esté realmente en
la ruta de clase:
• Calcula el nombre de ruta al que se asigna el nombre de clase; ver Asignar nombres
de clases a rutas de acceso
• Averigua cuál es el classpath; Vea este ejemplo: Diferentes maneras de especificar la
ruta de clase.
• Mire cada uno de los archivos JAR y ZIP en la ruta de clase para ver si contienen una
clase con la ruta de acceso requerida.
• Mire cada directorio para ver si la ruta de acceso se resuelve en un archivo dentro del
directorio.
Si la comprobación del classpath a mano no encontró el problema, puede agregar las opciones -
Xdiag y -XshowSettings . La primera lista todas las clases que se cargan, y la última imprime
configuraciones que incluyen la ruta de clase efectiva para la JVM.
• Un archivo JAR ejecutable con un atributo de Main-Class que especifica una clase que no
existe.
• Un archivo JAR ejecutable con un atributo de Class-Path incorrecto.
• Si se equivoca 2 las opciones antes de que el nombre de la clase, el java comando puede
tratar de interpretar uno de ellos como el nombre de clase.
• Si alguien ha ignorado las reglas de estilo de Java y ha usado identificadores de paquete o
clase que difieren solo en letras mayúsculas, y está ejecutando en una plataforma que trata
las letras mayúsculas en los nombres de archivo como no significativas.
• Problemas con homoglifos en los nombres de clase en el código o en la línea de comando.
• Si está intentando ejecutar un archivo JAR ejecutable, entonces el manifiesto de JAR tiene
un atributo "Clase principal" incorrecto que especifica una clase que no es una clase de
punto de entrada válida.
• Le ha dicho al comando java una clase que no es una clase de punto de entrada.
• La clase de punto de entrada es incorrecta; ver Clases de punto de entrada para más
información.
Otros recursos
• ¿Qué significa "no se pudo encontrar o cargar la clase principal"?
• http://docs.oracle.com/javase/tutorial/getStarted/problems/index.html
https://riptutorial.com/es/home 413
1 - Desde Java 8 y java posteriores, el comando java asignará de manera útil un separador de nombre de archivo
("/" o "") a un punto ("."). Sin embargo, este comportamiento no está documentado en las páginas del manual.
2 - Un caso muy oscuro es si copia y pega un comando de un documento formateado donde el editor de texto ha
usado un "guión largo" en lugar de un guión normal.
Las aplicaciones Java típicas consisten en un código específico de la aplicación y varios códigos
de biblioteca reutilizables que ha implementado o que ha sido implementado por terceros. Estas
últimas se conocen comúnmente como dependencias de bibliotecas y, por lo general, se
empaquetan como archivos JAR.
Java es un lenguaje enlazado dinámicamente. Cuando ejecuta una aplicación Java con
dependencias de biblioteca, la JVM necesita saber dónde están las dependencias para poder
cargar las clases según sea necesario. En términos generales, hay dos maneras de lidiar con
esto:
• Se le puede decir a la JVM dónde encontrar los archivos JAR dependientes a través del
classpath de tiempo de ejecución.
Para un archivo JAR ejecutable, la ruta de clase de tiempo de ejecución se especifica mediante el
atributo de manifiesto "Class-Path". (Nota editorial: Esto se debe describir en un Tema separado
en el comando jar ). De lo contrario, la ruta de -cp tiempo de ejecución debe suministrarse
mediante la opción -cp o la variable de entorno CLASSPATH .
Por ejemplo, supongamos que tenemos una aplicación Java en el archivo "myApp.jar" cuya clase
de punto de entrada es com.example.MyApp . Supongamos también que la aplicación depende de
los archivos JAR de la biblioteca "lib / library1.jar" y "lib / library2.jar". Podríamos iniciar la
aplicación usando el comando java como sigue en una línea de comando:
$ # Alternative 1 (preferred)
$ java -cp myApp.jar:lib/library1.jar:lib/library2.jar com.example.MyApp
$ # Alternative 2
$ export CLASSPATH=myApp.jar:lib/library1.jar:lib/library2.jar
$ java com.example.MyApp
Si bien un desarrollador de Java se sentiría cómodo con eso, no es "fácil de usar". Por lo tanto, es
una práctica común escribir un script de shell simple (o un archivo por lotes de Windows) para
ocultar los detalles que el usuario no necesita conocer. Por ejemplo, si coloca el siguiente script
de shell en un archivo llamado "myApp", lo convierte en ejecutable y lo coloca en un directorio en
https://riptutorial.com/es/home 414
la ruta de búsqueda de comandos:
#!/bin/bash
# The 'myApp' wrapper script
export DIR=/usr/libexec/myApp
export CLASSPATH=$DIR/myApp.jar:$DIR/lib/library1.jar:$DIR/lib/library2.jar
java com.example.MyApp
Como ejemplo, supongamos que tenemos el siguiente programa simple que imprime el tamaño
de un archivo:
import java.io.File;
Ahora supongamos que queremos imprimir el tamaño de un archivo cuyo nombre de ruta tiene
espacios en él; Por ejemplo, /home/steve/Test File.txt . Si ejecutamos el comando así:
https://riptutorial.com/es/home 415
estos shells, puede resolver el problema citando el argumento.
Las comillas dobles alrededor de la ruta de acceso le indican al shell que se debe pasar como un
solo argumento. Las citas serán eliminadas cuando esto suceda. Hay un par de otras maneras de
hacer esto:
Las comillas simples (rectas) se tratan como comillas dobles, excepto que también suprimen
varias expansiones dentro del argumento.
Una barra invertida escapa al siguiente espacio y hace que no se interprete como un separador
de argumentos.
Para obtener una documentación más completa, incluidas las descripciones de cómo tratar otros
caracteres especiales en los argumentos, consulte el tema de cita en la documentación de Bash .
• Sin embargo, cuando intenta combinar esto con el uso de SET y la sustitución de variables
en un archivo por lotes, se vuelve realmente complicado si se eliminan las comillas dobles.
• El shell cmd.exe aparentemente tiene otros mecanismos de escape; por ejemplo, duplicar las
comillas dobles y usar ^ escapes.
Opciones de Java
https://riptutorial.com/es/home 416
• Todas las opciones comienzan con un único guión o signo menos ( - ): no se admite la
convención de GNU / Linux de usar -- para opciones "largas".
• Las opciones deben aparecer antes del <classname> o del -jar <jarfile> para ser
reconocido. Cualquier argumento posterior a ellos se tratará como argumentos que se
pasarán a la aplicación Java que se está ejecutando.
• Las opciones que no comienzan con -X o -XX son opciones estándar. Puede confiar en todas
las implementaciones de Java 1 para admitir cualquier opción estándar.
• Las opciones que comienzan con -X son opciones no estándar y pueden retirarse de una
versión de Java a la siguiente.
• Las opciones que comienzan con -XX son opciones avanzadas y también se pueden retirar.
https://riptutorial.com/es/home 417
$ # Enable assertions for all classes in a package except for one.
$ java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat MyApp
• El formulario "cliente" está optimizado para las aplicaciones de usuario y ofrece un inicio
más rápido.
• El formulario "servidor" está optimizado para aplicaciones de larga ejecución. La estadística
de captura lleva más tiempo durante el "calentamiento" de JVM, lo que permite al
compilador JIT hacer un mejor trabajo de optimización del código nativo.
1 - Verifique el manual oficial del comando java . A veces, una opción estándar se describe como "sujeto a cambio".
https://riptutorial.com/es/home 418
Capítulo 62: Encapsulacion
Introducción
Imagine que tiene una clase con algunas variables bastante importantes y que fueron
configuradas (por otros programadores desde su código) a valores inaceptables. Su código trajo
errores en su código. Como solución, en OOP, permite que el estado de un objeto (almacenado
en sus variables) se modifique solo a través de métodos. Ocultar el estado de un objeto y
proporcionar toda la interacción a través de los métodos de un objeto se conoce como
encapsulación de datos.
Observaciones
Es mucho más fácil comenzar marcando una variable como private y exponerla si es necesario
que ocultar una variable que ya es public .
Hay una excepción en la que la encapsulación puede no ser beneficiosa: estructuras de datos
"simples" (clases cuyo único propósito es mantener variables).
Tenga en cuenta que las variables marcadas como final pueden marcarse como public sin violar
la encapsulación porque no se pueden cambiar después de establecerlas.
Examples
Encapsulamiento para mantener invariantes.
https://riptutorial.com/es/home 419
public class Angle {
La encapsulación le permite realizar cambios internos en una clase sin afectar ningún código que
llame a la clase. Esto reduce el acoplamiento , o cuánto una clase dada depende de la
implementación de otra clase.
https://riptutorial.com/es/home 420
a.angleInDegrees = degrees;
return a;
}
private Angle(){}
}
La implementación de esta clase ha cambiado para que solo almacene una representación del
ángulo y calcule el otro ángulo cuando sea necesario.
Sin embargo, la implementación cambió, pero la interfaz no . Si una clase que llama se basó
en acceder al método angleInRadians, tendría que cambiarse para usar la nueva versión de Angle
. Las clases que llaman no deberían preocuparse por la representación interna de una clase.
https://riptutorial.com/es/home 421
Capítulo 63: Enchufes
Introducción
Un zócalo es un punto final de un enlace de comunicación de dos vías entre dos programas que
se ejecutan en la red.
Examples
Leer de socket
try (
Socket echoSocket = new Socket(hostName, portNumber);
PrintWriter out =
new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(echoSocket.getInputStream()));
BufferedReader stdIn =
new BufferedReader(
new InputStreamReader(System.in))
) {
//Use the socket
}
https://riptutorial.com/es/home 422
Capítulo 64: Enum a partir del número
Introducción
Java no permite que el nombre de enumeración comience con un número como 100A, 25K. En
ese caso, podemos agregar el código con _ (guión bajo) o cualquier patrón permitido y verificarlo.
Examples
Enum con nombre al principio
https://riptutorial.com/es/home 423
Capítulo 65: Enums
Introducción
Las enumeraciones de Java (declaradas usando la palabra clave enum ) son sintaxis abreviada
para cantidades considerables de constantes de una sola clase.
Sintaxis
• Enumeración [pública / protegida / privada] Enum_name {// Declarar una nueva
enumeración.
• ENUM_CONSTANT_1 [, ENUM_CONSTANT_2 ...]; // Declara las constantes de
enumeración. Esta debe ser la primera línea dentro de la enumeración y debe estar
separada por comas, con un punto y coma al final.
• ENUM_CONSTANT_1 (param) [, ENUM_CONSTANT_2 (param) ...]; // Declarar constantes
de enumeración con parámetros. Los tipos de parámetros deben coincidir con el
constructor.
• ENUM_CONSTANT_1 {...} [, ENUM_CONSTANT_2 {...} ...]; // Declarar constantes de
enumeración con métodos sobrescritos. Esto debe hacerse si la enumeración contiene
métodos abstractos; Todos estos métodos deben ser implementados.
• ENUM_CONSTANT.name () // Devuelve una cadena con el nombre de la enumeración
constante.
• ENUM_CONSTANT.ordinal () // Devuelve el ordinal de esta constante de enumeración, su
posición en su declaración enum, donde a la constante inicial se le asigna un ordinal de
cero.
• Enum_name.values () // Devuelve una nueva matriz (de tipo Enum_name []) que contiene
cada constante de esa enumeración cada vez que se llama.
• Enum_name.valueOf ("ENUM_CONSTANT") // El inverso de ENUM_CONSTANT.name () -
devuelve la constante de enumeración con el nombre dado.
• Enum.valueOf (Enum_name.class, "ENUM_CONSTANT") // Un sinónimo del anterior: El
inverso de ENUM_CONSTANT.name () - devuelve la enumeración constante con el nombre
dado.
Observaciones
Restricciones
Las enumeraciones siempre extienden java.lang.Enum , por lo que es imposible que una
enumeración extienda una clase. Sin embargo, pueden implementar muchas interfaces.
consejos y trucos
Debido a su representación especializada, hay mapas y conjuntos más eficientes que se pueden
https://riptutorial.com/es/home 424
usar con las enumeraciones como sus claves. Estos a menudo se ejecutan más rápido que sus
contrapartes no especializadas.
Examples
Declarar y usar una enumeración básica
Enum puede ser considerado como sintaxis de azúcar para una clase sellada que solo se crea
una instancia de varias veces conocidas en tiempo de compilación para definir un conjunto de
constantes.
Una enumeración simple para enumerar las diferentes temporadas se declararía de la siguiente
manera:
/**
* This enum is declared in the Season.java file.
*/
public enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
/**
https://riptutorial.com/es/home 425
* This enum is declared inside the Day.java file and
* cannot be accessed outside because it's declared as private.
*/
private enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
/**
* Constructor
*/
public Day() {
// Illegal. Compilation error
enum Season {
WINTER,
SPRING,
SUMMER,
FALL
}
}
https://riptutorial.com/es/home 426
Cada constante de enumeración es public , static y final por defecto. Como todas las constantes
son static , se puede acceder directamente usando el nombre de enumeración.
Puede obtener una matriz de las constantes de enumeración utilizando el método values() . Se
garantiza que los valores están en orden de declaración en la matriz devuelta:
Nota: este método asigna una nueva matriz de valores cada vez que se llama.
https://riptutorial.com/es/home 427
Otra forma de comparar las constantes de enumeración es utilizando equals() como se muestra a
continuación, lo que se considera una mala práctica, ya que puede caer fácilmente en las
dificultades de la siguiente manera:
Season.FALL.equals(Season.FALL); // true
Season.FALL.equals(Season.WINTER); // false
Season.FALL.equals("FALL"); // false and no compiler error
// Usage:
MutableExample.A.print(); // Outputs 0
MutableExample.A.increment();
MutableExample.A.print(); // Outputs 1 -- we've changed a field
MutableExample.B.print(); // Outputs 0 -- another instance remains unchanged
Sin embargo, una buena práctica es hacer que las instancias de enum inmutables, es decir, cuando
no tienen campos adicionales o todos estos campos están marcados como final y son
inmutables. Esto asegurará que durante toda la vida de la aplicación, una enum no perderá
memoria y que es seguro usar sus instancias en todos los subprocesos.
Una enum no puede tener un constructor público; sin embargo, los constructores privados son
aceptables (los constructores para enums son de paquete privado por defecto):
https://riptutorial.com/es/home 428
private int value;
Coin(int value) {
this.value = value;
}
Las constantes de enumeración son técnicamente mutables, por lo que se podría agregar un
setter para cambiar la estructura interna de una constante de enumeración. Sin embargo, esto se
considera muy mala práctica y debe evitarse.
La mejor práctica es hacer que los campos de Enum sean inmutables, con final :
Coin(int value){
this.value = value;
}
...
https://riptutorial.com/es/home 429
Puede definir múltiples constructores en la misma enumeración. Cuando lo hace, los argumentos
que pasa en su declaración de enumeración deciden a qué constructor se llama:
Coin(int value){
this(value, false);
}
...
Nota: Todos los campos de enumeración no primitivos deberían implementar Serializable porque
la clase Enum sí lo hace.
Una enumeración puede contener un método, al igual que cualquier clase. Para ver cómo
funciona esto, declararemos una enumeración como esta:
https://riptutorial.com/es/home 430
Esto se puede mejorar aún más mediante el uso de campos y bloques de inicialización estáticos:
static {
NORTH.opposite = SOUTH;
SOUTH.opposite = NORTH;
WEST.opposite = EAST;
EAST.opposite = WEST;
}
}
Implementa interfaz
Esta es una enum que también es una función invocable que prueba las entradas de String contra
patrones de expresión regular precompilados.
import java.util.function.Predicate;
import java.util.regex.Pattern;
@Override
public boolean test(final String input) {
return this.pattern.matcher(input).matches();
}
}
https://riptutorial.com/es/home 431
Cada miembro de la enumeración también puede implementar el método:
import java.util.function.Predicate;
De esta manera, cualquier enum etiquetada por (implementando) la interfaz se puede usar como
un parámetro, lo que permite al programador crear una cantidad variable de enum que será
aceptada por el método. Esto puede ser útil, por ejemplo, en las API donde hay una enum
predeterminada (no modificable) y el usuario de estas API desea "extender" la enum con más
valores.
https://riptutorial.com/es/home 432
}
Ejemplo que muestra cómo usar las enumeraciones: observe cómo printEnum() acepta valores de
ambos tipos de enum :
printEnum(DefaultValues.VALUE_ONE); // VALUE_ONE
printEnum(DefaultValues.VALUE_TWO); // VALUE_TWO
printEnum(ExtendedValues.VALUE_THREE); // VALUE_THREE
printEnum(ExtendedValues.VALUE_FOUR); // VALUE_FOUR
Nota: este patrón no le impide redefinir los valores de enumeración, que ya están definidos en
una enumeración, en otra enumeración. Estos valores de enumeración serían diferentes
instancias entonces. Además, no es posible utilizar switch-on-enum ya que todo lo que tenemos
es la interfaz, no la enum real.
Las enumeraciones pueden definir métodos abstractos, que cada miembro de la enum debe
implementar.
enum Action {
DODGE {
public boolean execute(Player player) {
return player.isAttacking();
}
},
ATTACK {
public boolean execute(Player player) {
return player.hasWeapon();
}
},
JUMP {
public boolean execute(Player player) {
return player.getCoordinates().equals(new Coordinates(0, 0));
}
};
Esto permite que cada miembro de la enumeración defina su propio comportamiento para una
operación dada, sin tener que activar tipos en un método en la definición de nivel superior.
Tenga en cuenta que este patrón es una forma corta de lo que normalmente se logra utilizando
polimorfismo y / o implementación de interfaces.
Documentando enumeraciones
No siempre el nombre de la enum es lo suficientemente claro como para ser entendido. Para
https://riptutorial.com/es/home 433
documentar una enum , use javadoc estándar:
/**
* United States coins
*/
public enum Coins {
/**
* One-cent coin, commonly known as a penny,
* is a unit of currency equaling one-hundredth
* of a United States dollar
*/
PENNY(1),
/**
* A nickel is a five-cent coin equaling
* five-hundredth of a United States dollar
*/
NICKEL(5),
/**
* The dime is a ten-cent coin refers to
* one tenth of a United States dollar
*/
DIME(10),
/**
* The quarter is a US coin worth 25 cents,
* one-fourth of a United States dollar
*/
QUARTER(25);
Coins(int value){
this.value = value;
}
Cada clase de enumeración contiene un método estático implícito llamado values() . Este método
devuelve una matriz que contiene todos los valores de esa enumeración. Puede utilizar este
método para iterar sobre los valores. Sin embargo, es importante tener en cuenta que este
método devuelve una nueva matriz cada vez que se llama.
/**
* Print out all the values in this enum.
*/
public static void printAllDays() {
https://riptutorial.com/es/home 434
for(Day day : Day.values()) {
System.out.println(day.name());
}
}
}
Al escribir una clase con genéricos en java, es posible asegurarse de que el parámetro type sea
una enumeración. Como todas las enumeraciones amplían la clase Enum , se puede usar la
siguiente sintaxis.
enum DayOfWeek {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}
Una enumeración se compila con un método static valueOf() incorporado que se puede usar para
buscar una constante por su nombre:
https://riptutorial.com/es/home 435
Guava Optional para eliminar el manejo de excepciones explícitas:
INSTANCE;
private Attendant() {
// perform some initialization routine
}
Según el libro "Effective Java" de Joshua Bloch, una enumeración de un solo elemento es la
mejor manera de implementar un singleton. Este enfoque tiene las siguientes ventajas:
En caso de que queramos usar enum con más información y no solo valores constantes, queremos
poder comparar dos enumeraciones.
https://riptutorial.com/es/home 436
private final int value;
Coin(int value){
this.value = value;
}
Aquí definimos un Enum llamado Coin que representa su valor. Con el método isGreaterThan
podemos comparar dos enum s:
A veces quieres convertir tu enumeración en una Cadena, hay dos formas de hacerlo.
Por ejemplo:
System.out.println(Fruit.BANANA.name()); // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.name()); // "GRAPE_FRUIT"
https://riptutorial.com/es/home 437
toString() está, por defecto , reemplazado para tener el mismo comportamiento que name()
Sin embargo, es probable que los desarrolladores toString() para que imprima una String más
fácil de usar
No uses toString() si quieres verificar tu código, name() es mucho más estable para
eso. Solo use toString() cuando vaya a dar salida al valor de logs o stdout o algo así
Por defecto:
System.out.println(Fruit.BANANA.toString()); // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "GRAPE_FRUIT"
System.out.println(Fruit.BANANA.toString()); // "Banana"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "Grape Fruit"
En una enum es posible definir un comportamiento específico para una constante particular de la
enum que anula el comportamiento predeterminado de la enum , esta técnica se conoce como
cuerpo específico constante .
Supongamos que tres estudiantes de piano, John, Ben y Luke, se definen en una enum llamada
PianoClass , de la siguiente manera:
enum PianoClass {
JOHN, BEN, LUKE;
public String getSex() {
return "Male";
}
public String getLevel() {
return "Beginner";
}
}
Y un día llegan otros dos estudiantes, Rita y Tom, con un sexo (femenino) y un nivel (intermedio)
que no coinciden con los anteriores:
enum PianoClass2 {
JOHN, BEN, LUKE, RITA, TOM;
public String getSex() {
return "Male"; // issue, Rita is a female
}
public String getLevel() {
return "Beginner"; // issue, Tom is an intermediate student
}
}
https://riptutorial.com/es/home 438
de modo que simplemente agregar los nuevos alumnos a la declaración constante, como sigue,
no es correcto:
Es posible definir un comportamiento específico para cada una de las constantes, Rita y Tom, que
anula el comportamiento predeterminado de PianoClass2 la siguiente manera:
enum PianoClass3 {
JOHN, BEN, LUKE,
RITA {
@Override
public String getSex() {
return "Female";
}
},
TOM {
@Override
public String getLevel() {
return "Intermediate";
}
};
public String getSex() {
return "Male";
}
public String getLevel() {
return "Beginner";
}
}
Otra forma de definir el cuerpo específico del contenido es mediante el uso de constructor, por
ejemplo:
enum Friend {
MAT("Male"),
JOHN("Male"),
JANE("Female");
Friend(String gender) {
this.gender = gender;
}
https://riptutorial.com/es/home 439
}
}
y uso:
enum Util {
/* No instances */;
Del mismo modo que enum se puede utilizar para singletons (clases de 1 instancia), se puede usar
para clases de utilidad (0 clases de instancia). Solo asegúrese de terminar la lista (vacía) de
constantes de enumeración con un ; .
Consulte la pregunta Zero instance enum contra constructores privados para evitar la creación de
instancias para una discusión sobre pros y contras en comparación con constructores privados.
Si se requiere que su clase de enumeración tenga campos estáticos, tenga en cuenta que se
crean después de los propios valores de enumeración. Eso significa que, el siguiente código
resultará en una NullPointerException :
enum Example {
ONE(1), TWO(2);
enum Example {
ONE(1), TWO(2);
https://riptutorial.com/es/home 440
static Map<String, Integer> integers;
enum Example {
ONE(1), TWO(2);
inicialisis
Enums contiene solo constantes y puede compararse directamente con == . Por lo tanto, solo se
necesita una verificación de referencia, no es necesario utilizar el método .equals . Además, si
.equals usa incorrectamente, puede generar la NullPointerException mientras que ese no es el
caso con == check.
enum Day {
GOOD, AVERAGE, WORST;
}
https://riptutorial.com/es/home 441
public class Test {
if (day.equals(Day.GOOD)) {//NullPointerException!
System.out.println("Good Day!");
}
}
}
Para agrupar, complementar, EnumSet valores de enumeración, tenemos la clase EnumSet que
contiene diferentes métodos.
• EnumSet#range : para obtener un subconjunto de enumeración por rango definido por dos
puntos finales
enum Page {
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10
}
if (range.contains(Page.A4)) {
System.out.println("Range contains A4");
}
if (of.contains(Page.A1)) {
System.out.println("Of contains A1");
}
}
}
https://riptutorial.com/es/home 442
Capítulo 66: Errores comunes de Java
Introducción
Este tema describe algunos de los errores comunes que cometen los principiantes en Java.
Esto incluye cualquier error común en el uso del lenguaje Java o la comprensión del entorno de
tiempo de ejecución.
Los errores asociados con API específicas se pueden describir en temas específicos de esas API.
Las cuerdas son un caso especial; están cubiertos en la especificación del lenguaje Java. Los
detalles que no sean errores comunes se pueden describir en este tema en Cadenas .
Examples
Pitfall: utilizando == para comparar objetos de envoltorios primitivos, como
Integer
(Este escollo se aplica por igual a todos los tipos de envoltorios primitivos, pero lo ilustraremos
para Integer e int .)
Cuando se trabaja con objetos Integer , es tentador usar == para comparar valores, porque eso es
lo que haría con los valores int . Y en algunos casos esto parecerá funcionar:
Aquí creamos dos objetos Integer con el valor 1 y los comparamos (en este caso creamos uno de
una String y uno de un literal int . Hay otras alternativas). Además, observamos que los dos
métodos de comparación ( == y equals ) son ambos true .
https://riptutorial.com/es/home 443
tamaño"). Para los valores en este rango, Integer.valueOf() devolverá el valor almacenado en
caché en lugar de crear uno nuevo.
El operador == para tipos de referencia prueba la igualdad de referencia (es decir, el mismo
objeto). Por lo tanto, en el primer ejemplo int1_1 == int1_2 es true porque las referencias son las
mismas. En el segundo ejemplo int2_1 == int2_2 es falso porque las referencias son diferentes.
Cada vez que un programa abre un recurso, como un archivo o una conexión de red, es
importante liberar el recurso una vez que haya terminado de usarlo. Se debe tener la misma
precaución si se lanzara alguna excepción durante las operaciones con dichos recursos. Se
podría argumentar que FileInputStream tiene un finalizador que invoca el método close() en un
evento de recolección de basura; sin embargo, dado que no podemos estar seguros de cuándo
se iniciará un ciclo de recolección de basura, la secuencia de entrada puede consumir recursos
de computadora por un período de tiempo indefinido. El recurso se debe cerrar en una sección de
finally de un bloque try-catch:
Java SE 7
Desde Java 7 hay una declaración realmente útil y ordenada introducida en Java 7
particularmente para este caso, llamada try-with-resources:
Java SE 7
https://riptutorial.com/es/home 444
}
La sentencia try-con-recursos se puede utilizar con cualquier objeto que implemente la Closeable o
AutoCloseable interfaz. Asegura que cada recurso se cierre al final de la declaración. La diferencia
entre las dos interfaces es que el método close() de Closeable lanza una IOException que debe
manejarse de alguna manera.
En los casos en los que el recurso ya se ha abierto pero debe cerrarse de manera segura
después de su uso, se puede asignar a una variable local dentro de try-with-resources
Java SE 7
Sin embargo, puede evitar que se libere la memoria, permitiendo que se pueda acceder a objetos
que ya no son necesarios. Ya sea que llame a esto una pérdida de memoria o una tasa de
paquetes de memoria, el resultado es el mismo: un aumento innecesario en la memoria asignada.
Las fugas de memoria en Java pueden ocurrir de varias maneras, pero la razón más común son
las referencias eternas de objetos, porque el recolector de basura no puede eliminar objetos del
montón mientras todavía hay referencias a ellos.
Campos estáticos
Uno puede crear una referencia de este tipo definiendo la clase con un campo static contiene
alguna colección de objetos, y olvidando establecer ese campo static en null después de que la
colección ya no sea necesaria. static campos static se consideran raíces GC y nunca se
recopilan. Otro problema son las fugas en la memoria no de pila cuando se utiliza JNI .
De lejos, sin embargo, el tipo más insidioso de pérdida de memoria es la pérdida del cargador de
clases . Un cargador de clases contiene una referencia a cada clase que ha cargado, y cada
clase tiene una referencia a su cargador de clases. Cada objeto tiene una referencia a su clase
también. Por lo tanto, si incluso un solo objeto de una clase cargada por un cargador de clases no
es basura, no se puede recopilar una sola clase que ese cargador de clases haya cargado. Como
cada clase también hace referencia a sus campos estáticos, tampoco se pueden recopilar.
https://riptutorial.com/es/home 445
Fuga de acumulación El ejemplo de fuga de acumulación podría ser similar al siguiente:
scheduledExecutorService.scheduleAtFixedRate(() -> {
BigDecimal number = numbers.peekLast();
if (number != null && number.remainder(divisor).byteValue() == 0) {
System.out.println("Number: " + number);
System.out.println("Deque size: " + numbers.size());
}
}, 10, 10, TimeUnit.MILLISECONDS);
scheduledExecutorService.scheduleAtFixedRate(() -> {
numbers.add(new BigDecimal(System.currentTimeMillis()));
}, 10, 10, TimeUnit.MILLISECONDS);
try {
scheduledExecutorService.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
Este ejemplo crea dos tareas programadas. La primera tarea toma el último número de un deque
llamado numbers , y, si el número es divisible por 51, imprime el número y el tamaño del deque. La
segunda tarea pone números en el deque. Ambas tareas se programan a una velocidad fija y se
ejecutan cada 10 ms.
Si se ejecuta el código, verá que el tamaño del deque está aumentando permanentemente. Esto
eventualmente hará que el deque se llene con objetos que consumen toda la memoria disponible
del montón.
Para evitar esto y preservar la semántica de este programa, podemos usar un método diferente
para tomar números del deque: pollLast . Al contrario del método peekLast , pollLast devuelve el
elemento y lo elimina del deque, mientras que peekLast solo devuelve el último elemento.
Un error común para los principiantes de Java es usar el operador == para probar si dos cadenas
son iguales. Por ejemplo:
https://riptutorial.com/es/home 446
Se supone que el programa anterior prueba el primer argumento de la línea de comando e
imprime diferentes mensajes cuando no es la palabra "hola". Pero el problema es que no
funcionará. Ese programa producirá "¿Te sientes malhumorado hoy?" no importa cuál sea el
primer argumento de la línea de comando.
En este caso particular, la String "hola" se coloca en el grupo de cadenas mientras que la String
args [0] reside en el montón. Esto significa que hay dos objetos que representan el mismo literal,
cada uno con su referencia. Dado que == prueba las referencias, no la igualdad real, la
comparación producirá un falso la mayoría de las veces. Esto no significa que siempre lo hará.
Cuando utiliza == para probar cadenas, lo que realmente está probando es si dos objetos de
String son el mismo objeto de Java. Desafortunadamente, eso no es lo que significa la igualdad
de cadenas en Java. De hecho, la forma correcta de probar cadenas es usar el método
equals(Object) . Para un par de cadenas, generalmente queremos probar si están formadas por
los mismos caracteres en el mismo orden.
Pero en realidad se pone peor. El problema es que == dará la respuesta esperada en algunas
circunstancias. Por ejemplo
Curiosamente, esto imprimirá "igual", aunque estamos probando las cadenas de manera
incorrecta. ¿Porqué es eso? Debido a que la Especificación del lenguaje Java (Sección 3.10.5:
Literales de cadenas) estipula que dos cadenas >> literales << consistentes en los mismos
caracteres serán representadas por el mismo objeto Java. Por lo tanto, la prueba == dará
verdadero para literales iguales. (Los literales de cadena se "internan" y se agregan a un "grupo
de cadenas" compartido cuando se carga su código, pero eso es en realidad un detalle de
implementación).
Para agregar a la confusión, la especificación del lenguaje Java también estipula que cuando se
https://riptutorial.com/es/home 447
tiene una expresión constante en tiempo de compilación que concatena dos literales de cadena,
es equivalente a un solo literal. Así:
Esto dará salida a "1. igual" y "2. diferente". En el primer caso, la expresión + se evalúa en tiempo
de compilación y comparamos un objeto String consigo mismo. En el segundo caso, se evalúa en
tiempo de ejecución y comparamos dos objetos String diferentes
En resumen, usar == para probar cadenas en Java es casi siempre incorrecto, pero no se
garantiza que dé la respuesta incorrecta.
Algunas personas recomiendan que aplique varias pruebas a un archivo antes de intentar abrirlo
para proporcionar un mejor diagnóstico o evitar tratar con excepciones. Por ejemplo, este método
intenta verificar si la path corresponde a un archivo legible:
File f = null;
try {
f = getValidatedFile("somefile");
} catch (IOException ex) {
System.err.println(ex.getMessage());
return;
}
try (InputStream is = new FileInputStream(file)) {
// Read data etc.
}
https://riptutorial.com/es/home 448
El primer problema está en la firma para FileInputStream(File) porque el compilador seguirá
insistiendo en que IOException aquí, o más arriba en la pila.
• Condiciones de la carrera: otro hilo o un proceso separado podría cambiar el nombre del
archivo, eliminar el archivo o eliminar el acceso de lectura después de que getValidatedFile
el getValidatedFile . Eso llevaría a una IOException "simple" sin el mensaje personalizado.
• Hay casos de borde no cubiertos por esas pruebas. Por ejemplo, en un sistema con
SELinux en modo "de cumplimiento", un intento de leer un archivo puede fallar a pesar de
que canRead() devuelva true .
El tercer problema es que las pruebas son ineficientes. Por ejemplo, las llamadas exists , isFile y
canRead harán cada una syscall para realizar la verificación requerida. Luego se hace otro syscall
para abrir el archivo, que repite las mismas comprobaciones detrás de escena.
En resumen, los métodos como getValidatedFile son erróneos. Es mejor simplemente intentar
abrir el archivo y manejar la excepción:
Si desea distinguir los errores de E / S que se producen al abrir y leer, puede usar un try / catch
anidado. Si desea producir mejores diagnósticos para fallas abiertas, puede realizar las isFile
exists , isFile y canRead en el controlador.
Si piensa erróneamente que las variables son objetos, el comportamiento real del lenguaje Java
lo sorprenderá.
• Para las variables de Java que tienen un tipo primitivo (como int o float ), la variable
contiene una copia del valor. Todas las copias de un valor primitivo son indistinguibles; es
decir, solo hay un valor int para el número uno. Los valores primitivos no son objetos y no
se comportan como objetos.
https://riptutorial.com/es/home 449
• Para las variables de Java que tienen un tipo de referencia (ya sea una clase o un tipo de
matriz), la variable contiene una referencia. Todas las copias de una referencia son
indistinguibles. Las referencias pueden apuntar a objetos, o pueden ser null que significa
que no apuntan a ningún objeto. Sin embargo, no son objetos y no se comportan como
objetos.
Las variables no son objetos en ningún caso, y no contienen objetos en ninguno de los casos.
Pueden contener referencias a objetos , pero eso es decir algo diferente.
Clase de ejemplo
Los ejemplos que siguen utilizan esta clase, que representa un punto en el espacio 2D.
Una instancia de esta clase es un objeto que tiene dos campos x y y que tienen el tipo int .
En lo anterior, hemos declarado tres variables here , there y en elsewhere que pueden contener
referencias a objetos MutableLocation .
Si (incorrectamente) piensa que estas variables son objetos, entonces es probable que
malinterprete las afirmaciones diciendo:
https://riptutorial.com/es/home 450
3. Copie la ubicación "[1, 2]" a elsewhere
A partir de eso, es probable que deduzca que tenemos tres objetos independientes en las tres
variables. De hecho solo hay dos objetos creados por el anterior. Las variables here y there
realidad se refieren al mismo objeto.
Le asignamos un nuevo valor a here.x y cambió el valor que vemos a través de there.x . Se están
refiriendo al mismo objeto. Pero el valor que vemos a través de elsewhere.x no ha cambiado, por
lo que en elsewhere debe referirse a un objeto diferente.
if (here == there) {
System.out.println("here is there");
}
if (here == elsewhere) {
System.out.println("here is elsewhere");
}
Esto imprimirá "aquí está ahí", pero no imprimirá "aquí está en otra parte". (Las referencias here y
en elsewhere son para dos objetos distintos).
if (here.equals(there)) {
https://riptutorial.com/es/home 451
System.out.println("here equals there");
}
if (here.equals(elsewhere)) {
System.out.println("here equals elsewhere");
}
Esto imprimirá ambos mensajes. En particular, here.equals(elsewhere) devuelve true porque los
criterios semánticos que elegimos para la igualdad de dos objetos MutableLocation se han
cumplido.
Cuando pasa un valor de referencia a un método, en realidad está pasando una referencia a un
objeto por valor , lo que significa que está creando una copia de la referencia del objeto.
Siempre que ambas referencias de objetos sigan apuntando al mismo objeto, puede modificar ese
objeto de cualquiera de las dos referencias, y esto es lo que causa confusión para algunos.
Sin embargo, no está pasando un objeto por referencia 2. La distinción es que si la copia de
referencia del objeto se modifica para apuntar a otro objeto, la referencia del objeto original
seguirá apuntando al objeto original.
void g() {
MutableLocation foo = MutableLocation(1, 2);
f(foo);
System.out.println("foo.x is " + foo.x); // Prints "foo.x is 1".
}
void g() {
MutableLocation foo = new MutableLocation(0, 0);
f(foo);
System.out.println("foo.x is " + foo.x); // Prints "foo.x is 42"
}
1 - En idiomas como Python y Ruby, el término "pasar compartiendo" se prefiere para "pasar por valor" de un objeto /
referencia.
2 - El término "pasar por referencia" o "llamada por referencia" tiene un significado muy específico en la terminología
del lenguaje de programación. En efecto, significa que pasa la dirección de una variable o un elemento de matriz , de
https://riptutorial.com/es/home 452
modo que cuando el método llamado asigna un nuevo valor al argumento formal, cambia el valor en la variable
original. Java no soporta esto. Para obtener una descripción más completa de los diferentes mecanismos para pasar
parámetros, consulte https://en.wikipedia.org/wiki/Evaluation_strategy .
i += a[i++] + b[i--];
Generalmente hablando:
Tales ejemplos se utilizan a menudo en exámenes o entrevistas de trabajo como un intento de ver
si el estudiante o el entrevistado entiende cómo funciona realmente la evaluación de expresiones
en el lenguaje de programación Java. Esto es posiblemente legítimo como una "prueba de
conocimiento", pero eso no significa que debas hacer esto en un programa real.
Para ilustrar, el siguiente ejemplo aparentemente simple ha aparecido varias veces en preguntas
de StackOverflow (como esta ). En algunos casos, aparece como un error genuino en el código
de alguien.
int a = 1;
a = a++;
System.out.println(a); // What does this print.
La mayoría de los programadores (incluidos los expertos en Java) que leen esas declaraciones
rápidamente dirían que produce 2 . De hecho, produce 1 . Para una explicación detallada de por
qué, lea esta Respuesta .
Sin embargo la comida para llevar real a partir de esto y ejemplos similares es que cualquier
declaración de Java que tanto le asigna y los efectos secundarios de la misma variable va a ser
en el mejor de difícil de entender, y en el peor francamente engañosa. Debes evitar escribir
código como este.
1 - módulo problemas potenciales con el modelo de memoria de Java si las variables u objetos son visibles a otros
hilos.
https://riptutorial.com/es/home 453
public class Shout {
public static void main(String[] args) {
for (String s : args) {
s.toUpperCase();
System.out.print(s);
System.out.print(" ");
}
System.out.println();
}
}
s.toUpperCase();
Podría pensar que llamar a toUpperCase() cambiará s a una cadena en mayúsculas. No lo hace No
se puede String objetos de String son inmutables. No se pueden cambiar.
En realidad, el método toUpperCase() devuelve un objeto String que es una versión en mayúsculas
del String que lo llamas. Probablemente este será un nuevo objeto String , pero si s ya estaba
todo en mayúsculas, el resultado podría ser la cadena existente.
Por lo tanto, para utilizar este método de manera efectiva, debe usar el objeto devuelto por la
llamada al método; por ejemplo:
s = s.toUpperCase();
De hecho, la regla de "las cadenas nunca cambian" se aplica a todos los métodos de String . Si
recuerdas eso, entonces puedes evitar toda una categoría de errores de principiantes.
https://riptutorial.com/es/home 454
Capítulo 67: Errores de Java - Nulls y
NullPointerException
Observaciones
El valor null es el valor predeterminado para un valor no inicializado de un campo cuyo tipo es un
tipo de referencia.
• El método de get(key) en la API de Map devolverá un null si lo llama con una clave que no
tiene una asignación.
• Los getResource(path) y getResourceAsStream(path) en las API de ClassLoader y Class
devolverán el null si no se puede encontrar el recurso.
• El método get() en la API de Reference devolverá un null si el recolector de basura ha
borrado la referencia.
• Varios métodos getXxxx en las API del servlet de Java EE devolverán un null si intenta
recuperar un parámetro de solicitud, una sesión o un atributo de sesión inexistentes, etc.
Existen estrategias para evitar las NPE no deseadas, como probar explícitamente la existencia de
valores null o el uso de la "Notación Yoda", pero estas estrategias a menudo tienen el resultado
indeseable de ocultar problemas en su código que realmente deberían solucionarse.
Examples
Trampa: el uso innecesario de envolturas primitivas puede llevar a
https://riptutorial.com/es/home 455
NullPointerExceptions
A veces, los programadores que son nuevos Java usarán tipos primitivos y envoltorios de manera
intercambiable. Esto puede llevar a problemas. Considera este ejemplo:
...
MyRecord record = new MyRecord();
record.a = 1; // OK
record.b = record.b + 1; // OK
record.c = 1; // OK
record.d = record.d + 1; // throws a NullPointerException
Nuestra clase 1 de MyRecord basa en la inicialización predeterminada para inicializar los valores en
sus campos. Por lo tanto, cuando new un registro, los a y b campos se ponen a cero, y los c y d
campos se establecerán en null .
Cuando intentamos usar los campos inicializados predeterminados, vemos que los campos int
funcionan todo el tiempo, pero los campos de Integer funcionan en algunos casos y no en otros.
Específicamente, en el caso de que falle (con d ), lo que sucede es que la expresión del lado
derecho intenta desempaquetar una referencia null , y eso es lo que hace que se lance la
excepción NullPointerException .
La lección aquí es no usar tipos de envoltorios primitivos a menos que realmente lo necesite.
1 - Esta clase no es un ejemplo de buenas prácticas de codificación. Por ejemplo, una clase bien diseñada no tendría
campos públicos. Sin embargo, ese no es el punto de este ejemplo.
Algunos programadores piensan que es una buena idea ahorrar espacio utilizando un null para
representar una matriz o colección vacía. Si bien es cierto que puede ahorrar una pequeña
cantidad de espacio, la otra cara es que hace que su código sea más complicado y más frágil.
Compara estas dos versiones de un método para sumar una matriz:
https://riptutorial.com/es/home 456
La primera versión es cómo normalmente codificarías el método:
/**
* Sum the values in an array of integers.
* @arg values the array to be summed
* @return the sum
**/
public int sum(int[] values) {
int sum = 0;
for (int value : values) {
sum += value;
}
return sum;
}
La segunda versión es cómo debe codificar el método si tiene la costumbre de usar null para
representar una matriz vacía.
/**
* Sum the values in an array of integers.
* @arg values the array to be summed, or null.
* @return the sum, or zero if the array is null.
**/
public int sum(int[] values) {
int sum = 0;
if (values != null) {
for (int value : values) {
sum += value;
}
}
return sum;
}
Como puedes ver, el código es un poco más complicado. Esto es directamente atribuible a la
decisión de usar null de esta manera.
Ahora considere si esta matriz que podría ser null se usa en muchos lugares. En cada lugar
donde lo use, debe considerar si necesita realizar una prueba de null . Si pierde una prueba null
que debe estar allí, se arriesga a una NullPointerException . Por lo tanto, la estrategia de utilizar
null de esta manera hace que su aplicación sea más frágil; Es decir, más vulnerable a las
consecuencias de los errores de programación.
La lección aquí es usar matrices vacías y listas vacías cuando eso es lo que quieres decir.
La sobrecarga de espacio es pequeña, y hay otras formas de minimizarlo si esto es algo que vale
la pena hacer.
https://riptutorial.com/es/home 457
En StackOverflow, a menudo vemos código como este en Respuestas:
A menudo, esto se acompaña con una afirmación que es "la mejor práctica" para realizar una
prueba null como esta para evitar NullPointerException .
Hay algunas suposiciones subyacentes que deben ser cuestionadas antes de que podamos decir
si es una buena idea hacer esto en nuestras joinStrings :
El problema con "hacer el bien" es que puede ocultar el problema o dificultar su diagnóstico.
https://riptutorial.com/es/home 458
¿Es esto eficiente / bueno para la calidad del código?
Si el enfoque de "hacer el bien" se usa constantemente, su código contendrá muchas pruebas
nulas "defensivas". Esto va a hacer que sea más largo y más difícil de leer. Además, todas estas
pruebas y "hacer el bien" pueden afectar el rendimiento de su aplicación.
En resumen
Si null es un valor significativo, entonces la prueba para el caso null es el enfoque correcto. El
corolario es que si un valor null es significativo, entonces esto debe documentarse claramente en
los javadocs de cualquier método que acepte el valor null o lo devuelva.
De lo contrario, es una mejor idea tratar un null inesperado como un error de programación y
dejar que se produzca la NullPointerException para que el desarrollador sepa que hay un
problema en el código.
Algunos programadores de Java tienen una aversión general a lanzar o propagar excepciones.
Esto conduce a un código como el siguiente:
El problema es que getReader está devolviendo un null como un valor especial para indicar que no
se pudo abrir el Reader . Ahora se debe probar el valor devuelto para ver si es null antes de
usarlo. Si se omite la prueba, el resultado será una NullPointerException .
De hecho, asumiendo que la excepción debía ser detectada temprano de esta manera, había un
par de alternativas para devolver null :
1. Sería posible implementar una clase NullReader ; por ejemplo, una en la que las operaciones
de API se comportan como si el lector ya estuviera en la posición de "final de archivo".
2. Con Java 8, sería posible declarar getReader como retornando un Optional<Reader> .
https://riptutorial.com/es/home 459
Pitfall: no se comprueba si un flujo de E / S ni siquiera se inicializa al cerrarlo
Para evitar pérdidas de memoria, no se debe olvidar cerrar una secuencia de entrada o una
secuencia de salida cuyo trabajo se haya realizado. Esto generalmente se hace con una
declaración try - catch - finally sin la parte catch :
Si bien el código anterior puede parecer inocente, tiene un defecto que puede hacer que la
depuración sea imposible. Si la línea en la out se inicializa ( out = new FileOutputStream(filename) )
lanza una excepción, entonces out será null cuando out.close() se ejecuta, lo que resulta en una
desagradable NullPointerException !
Para evitar esto, simplemente asegúrese de que el flujo no sea null antes de intentar cerrarlo.
if ("A".equals(someString)) {
https://riptutorial.com/es/home 460
// do something
}
Esto "evita" o "evita" una posible someString NullPointerException en el caso de que someString sea
null . Además, es discutible que
"A".equals(someString)
es mejor que:
(Es más conciso y, en algunas circunstancias, podría ser más eficiente. Sin embargo, como
argumentamos a continuación, la concisión podría ser negativa).
Sin embargo, el verdadero escollo es usar la prueba de Yoda para evitar NullPointerExceptions
como una cuestión de hábito.
Cuando escribes "A".equals(someString) realidad estás "haciendo bien" el caso en el que sucede
que someString son null . Pero como lo explica otro ejemplo ( Pitfall - "Hacer buenos" nulos
inesperados ), "Hacer buenos" valores null puede ser perjudicial por una variedad de razones.
Esto significa que las condiciones de Yoda no son "mejores prácticas" 1 . A menos que se espere
el null , es mejor dejar que ocurra la NullPointerException para que pueda obtener una falla de
prueba de la unidad (o un informe de error). Eso le permite encontrar y corregir el error que
provocó que apareciera un null inesperado / no deseado.
Las condiciones de Yoda solo deben usarse en los casos en que se espera el null porque el
objeto que está probando proviene de una API que está documentada como que devuelve un null
. Y podría decirse que podría ser mejor usar una de las formas menos bonitas que expresan la
prueba porque eso ayuda a resaltar la prueba null para alguien que está revisando su código.
1 - Según Wikipedia : "Las mejores prácticas de codificación son un conjunto de reglas informales que la comunidad
de desarrollo de software ha aprendido a lo largo del tiempo y puede ayudar a mejorar la calidad del software". . El
uso de la notación Yoda no logra esto. En muchas situaciones, empeora el código.
https://riptutorial.com/es/home 461
Capítulo 68: Errores de Java - Problemas de
rendimiento
Introducción
Este tema describe una serie de "errores" (es decir, los errores que cometen los programadores
java novatos) que se relacionan con el rendimiento de la aplicación Java.
Observaciones
Este tema describe algunas prácticas de codificación "micro" de Java que son ineficientes. En la
mayoría de los casos, las ineficiencias son relativamente pequeñas, pero aún así vale la pena
evitarlas.
Examples
Pitfall - Los gastos generales de crear mensajes de registro
TRACE niveles de registro TRACE y DEBUG están ahí para poder transmitir detalles sobre el
funcionamiento del código dado en tiempo de ejecución. Por lo general, se recomienda establecer
el nivel de registro por encima de estos, sin embargo, se debe tener cuidado con estas
afirmaciones para que no afecten el rendimiento, incluso cuando aparentemente están
"desactivadas".
Incluso cuando el nivel de registro se establece en INFO , los argumentos pasados a debug() se
evaluarán en cada ejecución de la línea. Esto hace que consuma innecesariamente en varios
aspectos:
Solución
La mayoría de los marcos de registro proporcionan medios para crear mensajes de registro
utilizando cadenas de arreglos y referencias de objetos. El mensaje de registro se evaluará solo si
https://riptutorial.com/es/home 462
el mensaje está realmente registrado. Ejemplo:
Esto funciona muy bien siempre que todos los parámetros se puedan convertir en cadenas
usando String.valueOf (Object) . Si la composición del mensaje de registro es más compleja, el
nivel de registro se puede verificar antes del registro:
if (LOG.isDebugEnabled()) {
// Argument expression evaluated only when DEBUG is enabled
LOG.debug("Request coming from {}, parameters: {}", myInetAddress,
Arrays.toString(veryLongParamArray);
}
Aquí, LOG.debug() con el costoso Arrays.toString(Obect[]) se procesa solo cuando DEBUG está
realmente habilitado.
Desafortunadamente, este código es ineficiente si la lista de words es larga. La raíz del problema
es esta declaración:
Para cada iteración de bucle, esta declaración crea una nueva cadena de message contiene una
copia de todos los caracteres en la cadena de message original con caracteres adicionales
añadidos. Esto genera una gran cantidad de cadenas temporales, y hace una gran cantidad de
copias.
Cuando analizamos joinWords , asumiendo que hay N palabras con una longitud promedio de M,
encontramos que se crean cadenas temporales O (N) y se copiarán caracteres O (MN 2 ) en el
proceso. El componente N 2 es particularmente preocupante.
https://riptutorial.com/es/home 463
message.append(" ").append(word);
}
return message.toString();
}
El análisis de joinWords2 debe tener en cuenta los gastos generales de "hacer crecer" la matriz de
respaldo StringBuilder que contiene los caracteres del constructor. Sin embargo, resulta que la
cantidad de nuevos objetos creados es O (logN) y que la cantidad de caracteres copiados es O
(MN). El último incluye caracteres copiados en la llamada final toString() .
(Puede ser posible sintonizar esto aún más, creando el StringBuilder con la capacidad correcta
para comenzar. Sin embargo, la complejidad general sigue siendo la misma).
Volviendo al método original de joinWords , resulta que la declaración crítica será optimizada por
un compilador típico de Java a algo como esto:
Sin embargo, el compilador de Java no "levantará" el StringBuilder fuera del bucle, como hicimos
a mano en el código para joinWords2 .
Referencia:
1 - En Java 8 y Joiner posteriores, la clase Joiner puede usarse para resolver este problema en particular. Sin
embargo, de eso no se trata realmente este ejemplo.
El lenguaje Java le permite usar lo new para crear instancias Integer , Boolean , etc., pero
generalmente es una mala idea. Es mejor usar el autoboxing (Java 5 y posterior) o el método
valueOf .
La razón por la que el uso de un new Integer(int) explícitamente es una mala idea es que crea un
nuevo objeto (a menos que el compilador JIT lo optimice). Por el contrario, cuando se usa el
autoboxing o una llamada explícita a valueOf , el tiempo de ejecución de Java intentará reutilizar
un objeto Integer desde un caché de objetos preexistentes. Cada vez que el tiempo de ejecución
tiene un "hit" de caché, evita la creación de un objeto. Esto también ahorra memoria del montón y
reduce los gastos generales del GC causados por la rotación de objetos.
Notas:
https://riptutorial.com/es/home 464
1. En las implementaciones recientes de Java, el autoboxing se implementa llamando a
valueOf , y hay cachés para Boolean , Byte , Short , Integer , Long y Character .
2. El comportamiento de almacenamiento en caché para los tipos integrales está ordenado por
la especificación del lenguaje Java.
Usar una new String(String) para duplicar una cadena es ineficiente y casi siempre es
innecesario.
• Los objetos de cadena son inmutables, por lo que no es necesario copiarlos para protegerse
contra los cambios.
• En algunas versiones anteriores de Java, los objetos String pueden compartir matrices de
respaldo con otros objetos String . En esas versiones, es posible perder memoria creando
una subcadena (pequeña) de una cadena (grande) y reteniéndola. Sin embargo, a partir de
Java 7 en adelante, las matrices de respaldo de String no se comparten.
"Llamar al método gc sugiere que la Máquina Virtual de Java haga un esfuerzo por
reciclar los objetos no utilizados para que la memoria que ocupan actualmente esté
disponible para una reutilización rápida. Cuando el control regresa de la llamada al
método, la Máquina Virtual de Java ha hecho un mejor esfuerzo para reclamar espacio
de todos los objetos descartados ".
1. El uso de la palabra "sugiere" en lugar de (decir) "dice" significa que la JVM es libre de
ignorar la sugerencia. El comportamiento predeterminado de la JVM (lanzamientos
recientes) es seguir la sugerencia, pero esto puede -XX:+DisableExplicitGC configurando -
XX:+DisableExplicitGC cuando se -XX:+DisableExplicitGC la JVM.
2. La frase "un mejor esfuerzo para recuperar espacio de todos los objetos descartados"
implica que llamar a gc activará una recolección de basura "completa".
https://riptutorial.com/es/home 465
En primer lugar, ejecutar una recolección de basura completa es costoso. Un GC completo
implica visitar y "marcar" todos los objetos a los que todavía se puede acceder; Es decir, todo
objeto que no sea basura. Si dispara esto cuando no hay mucha basura que recoger, entonces el
GC hace mucho trabajo por un beneficio relativamente pequeño.
En segundo lugar, una recolección de basura completa puede perturbar las propiedades de
"localidad" de los objetos que no se recolectan. Los objetos que se asignan por el mismo
subproceso casi al mismo tiempo tienden a asignarse juntos en la memoria. Esto es bueno. Es
probable que los objetos que se asignan al mismo tiempo estén relacionados; es decir, hacer
referencia entre sí. Si su aplicación utiliza esas referencias, es probable que el acceso a la
memoria sea más rápido debido a los diversos efectos de la memoria y el almacenamiento en
caché de la página. Desafortunadamente, una colección de basura completa tiende a mover
objetos, de modo que los objetos que una vez estuvieron cerca ahora están más separados.
Tercero, la ejecución de una recolección de basura completa puede hacer que su aplicación se
detenga hasta que se complete la recolección. Mientras esto suceda, su aplicación no
responderá.
De hecho, la mejor estrategia es dejar que la JVM decida cuándo ejecutar el GC y qué tipo de
colección ejecutar. Si no interfiere, la JVM elegirá un tiempo y un tipo de colección que optimice el
rendimiento o minimice los tiempos de pausa del GC.
Al principio dijimos "... (casi siempre) una mala idea ...". De hecho, hay un par de escenarios en
los que podría ser una buena idea:
1. Si está implementando una prueba unitaria para algún código que es sensible a la
recolección de basura (por ejemplo, algo que involucra finalizadores o referencias débiles /
blandas / fantasmas), entonces puede ser necesario llamar a System.gc() .
int a = 1000;
int b = a + 1;
Integer a = 1000;
Integer b = a + 1;
https://riptutorial.com/es/home 466
Respuesta: Las dos versiones parecen casi idénticas, pero la primera es mucho más eficiente que
la segunda.
La segunda versión está utilizando una representación para los números que ocupa más espacio,
y se basa en el boxeo automático y el boxeo automático entre bastidores. De hecho, la segunda
versión es directamente equivalente al siguiente código:
Comparando esto con la otra versión que usa int , hay claramente tres llamadas de método
adicionales cuando se usa Integer . En el caso de valueOf , cada llamada creará e inicializará un
nuevo objeto Integer . Es probable que todo este trabajo extra de boxeo y desempaquetado haga
que la segunda versión sea un orden de magnitud más lenta que la primera.
Además de eso, la segunda versión está asignando objetos en el montón en cada llamada valueOf
. Si bien la utilización del espacio es específica de la plataforma, es probable que se encuentre en
la región de 16 bytes para cada objeto Integer . En contraste, la versión int necesita cero espacio
de almacenamiento adicional, asumiendo que a y b son variables locales.
Otra razón importante por la que los primitivos son más rápidos que sus equivalentes en caja es
la forma en que sus respectivos tipos de matrices se presentan en la memoria.
Si toma int[] y Integer[] como ejemplo, en el caso de int[] los valores int se establecen de
forma contigua en la memoria. Pero en el caso de un Integer[] no son los valores que se
presentan, sino las referencias (punteros) a los objetos Integer , que a su vez contienen los
valores int reales.
Además de ser un nivel adicional de direccionamiento indirecto, este puede ser un gran tanque
cuando se trata de la localidad de caché cuando se itera sobre los valores. En el caso de un int[]
la CPU podría obtener todos los valores de la matriz, en su caché a la vez, porque son contiguos
en la memoria. Pero en el caso de un Integer[] la CPU potencialmente tiene que hacer una
recuperación de memoria adicional para cada elemento, ya que la matriz solo contiene
referencias a los valores reales.
https://riptutorial.com/es/home 467
Esto se debe a que requiere una búsqueda en el mapa (el método get() ) para cada clave en el
mapa. Es posible que esta búsqueda no sea eficiente (en un HashMap, implica llamar a hashCode
en la clave, luego buscar el depósito correcto en las estructuras de datos internas y, a veces,
incluso llamar a equals ). En un mapa grande, esto puede no ser una sobrecarga trivial.
La forma correcta de evitar esto es iterar en las entradas del mapa, que se detalla en el tema
Colecciones.
El Java Collections Framework proporciona dos métodos relacionados para todos los objetos de
la Collection :
Ambos métodos se pueden utilizar para probar el vacío de la colección. Por ejemplo:
Por el contrario, un método isEmpty() solo necesita probar si hay al menos un elemento en la
colección. Esto no implica contar los elementos.
https://riptutorial.com/es/home 468
Considere el siguiente ejemplo:
/**
* Test if all strings in a list consist of English letters and numbers.
* @param strings the list to be checked
* @return 'true' if an only if all strings satisfy the criteria
* @throws NullPointerException if 'strings' is 'null' or a 'null' element.
*/
public boolean allAlphanumeric(List<String> strings) {
for (String s : strings) {
if (!s.matches("[A-Za-z0-9]*")) {
return false;
}
}
return true;
}
Este código es correcto, pero es ineficiente. El problema está en la matches(...) llamada. Bajo el
capó, s.matches("[A-Za-z0-9]*") es equivalente a esto:
Pattern.matches(s, "[A-Za-z0-9]*")
Pattern.compile("[A-Za-z0-9]*").matcher(s).matches()
El problema es que todo este trabajo se repite para cada iteración de bucle. La solución es
reestructurar el código de la siguiente manera:
Las instancias de esta clase son inmutables y son seguras para el uso de múltiples
subprocesos simultáneos. Las instancias de la clase Matcher no son seguras para tal
uso.
https://riptutorial.com/es/home 469
No uses match () cuando deberías usar find ()
Supongamos que desea probar si una cadena s contiene tres o más dígitos seguidos. Usted
puede expresar esto de varias maneras, incluyendo:
if (s.matches(".*[0-9]{3}.*")) {
System.out.println("matches");
}
if (Pattern.compile("[0-9]{3}").matcher(s).find()) {
System.out.println("matches");
}
El primero es más conciso, pero también es probable que sea menos eficiente. A primera vista, la
primera versión intentará hacer coincidir toda la cadena con el patrón. Además, dado que ". *" Es
un patrón "codicioso", es probable que el emparejador del patrón avance "con entusiasmo" hasta
el final de la cadena y retroceda hasta que encuentre una coincidencia.
Por el contrario, la segunda versión buscará de izquierda a derecha y dejará de buscar tan pronto
como encuentre los 3 dígitos seguidos.
Pattern.compile("ABC").matcher(s).find()
s.contains("ABC")
Excepto que este último es mucho más eficiente. (Incluso si puede amortizar el costo de compilar
la expresión regular).
A menudo, la forma no regex es más complicada. Por ejemplo, la prueba realizada por la
matches() llama al método allAlplanumeric anterior allAlplanumeric puede reescribirse como:
https://riptutorial.com/es/home 470
}
return true;
}
Ahora es más código que usar un Matcher , pero también va a ser mucho más rápido.
Retroceso catastrófico
(Esto es potencialmente un problema con todas las implementaciones de expresiones regulares,
pero lo mencionaremos aquí porque es un escollo para Pattern uso del Pattern ).
La primera println llamada imprimir rápidamente true . El segundo imprimirá false . Finalmente.
De hecho, si experimenta con el código anterior, verá que cada vez que agregue una A antes de
la C , el tiempo se duplicará.
Veamos lo que realmente significa (A+)+B Superficialmente, parece decir "uno o más caracteres A
seguidos de un valor B ", pero en realidad dice uno o más grupos, cada uno de los cuales consta
de uno o más caracteres A Así por ejemplo:
El ejemplo anterior está claramente diseñado, pero los patrones que muestran este tipo de
características de rendimiento (es decir, O(2^N) u O(N^K) para un K grande aparecen con frecuencia
cuando se utilizan expresiones regulares mal consideradas. Hay algunos remedios estándar:
Finalmente, tenga cuidado con las situaciones en las que un usuario o un cliente de API puede
suministrar una cadena de expresiones regulares con características patológicas. Eso puede
https://riptutorial.com/es/home 471
llevar a una "denegación de servicio" accidental o deliberada.
Referencias:
Pitfall - Interning Strings para que puedas usar == es una mala idea
"Probar cadenas usando == es incorrecto (a menos que las cadenas estén internadas)"
su reacción inicial es aplicar cadenas internas para que puedan usar == . (Después de todo == es
más rápido que llamar a String.equals(...) , ¿no es así?)
Fragilidad
En primer lugar, solo puede usar de forma segura == si sabe que todos los objetos String que está
probando han sido internados. El JLS garantiza que los literales de cadena en su código fuente se
habrán internado. Sin embargo, ninguna de las API de Java SE estándar garantiza devolver
cadenas internadas, aparte de String.intern(String) . Si pierde solo una fuente de objetos String
que no han sido internados, su aplicación no será confiable. Esa falta de fiabilidad se manifestará
como falsos negativos en lugar de excepciones que pueden dificultar su detección.
Este costo debe compararse con el ahorro que obtendremos utilizando == lugar de equals . De
hecho, no vamos a interrumpir el equilibrio a menos que cada cadena internada se compare unas
pocas veces "varias veces".
(Aparte: las pocas situaciones en las que vale la pena realizar una pasantía tienden a ser reducir
la huella de memoria de una aplicación donde las mismas cadenas se repiten muchas veces, y
esas cadenas tienen una larga vida útil).
https://riptutorial.com/es/home 472
El impacto en la recolección de basura.
Además de los costos directos de CPU y memoria descritos anteriormente, las cadenas internas
afectan el rendimiento del recolector de basura.
Para las versiones de Java anteriores a Java 7, las cadenas internas se mantienen en el espacio
"PermGen" que se recopila con poca frecuencia. Si es necesario recopilar PermGen, esto
(normalmente) activa una recolección de basura completa. Si el espacio de PermGen se llena
completamente, la JVM se bloquea, incluso si había espacio libre en los espacios de
almacenamiento dinámico normales.
En Java 7, el grupo de cadenas se movió de "PermGen" al montón normal. Sin embargo, la tabla
hash seguirá siendo una estructura de datos de larga duración, lo que hará que las cadenas
internas sean de larga duración. (Incluso si los objetos de cadena internados se asignaran en el
espacio del Edén, probablemente se promoverían antes de ser recolectados).
Por lo tanto, en todos los casos, internar una cadena prolongará su tiempo de vida en relación
con una cadena normal. Eso aumentará los gastos generales de recolección de basura durante la
vida útil de la JVM.
El segundo problema es que la tabla hash necesita usar un mecanismo de referencia débil de
algún tipo para evitar que la cadena pierda la memoria interna. Pero tal mecanismo es más
trabajo para el recolector de basura.
Estos gastos generales de recolección de basura son difíciles de cuantificar, pero existen pocas
dudas de que existan. Si usas intern extensivamente, podrían ser importantes.
https://riptutorial.com/es/home 473
denegación de servicio (DoS). Si el agente malicioso dispone que todas las cadenas que
proporciona tienen el mismo código hash, esto podría llevar a una tabla hash no balanceada y un
rendimiento O(N) para el intern ... donde N es el número de cadenas colisionadas.
(Hay formas más simples / más efectivas de lanzar un ataque DoS contra un servicio. Sin
embargo, este vector podría usarse si el objetivo del ataque DoS es romper la seguridad o evadir
las defensas DoS de primera línea).
import java.io.*;
(Hemos deliberado omitido la verificación normal de los argumentos, el informe de errores, etc.,
ya que no son relevantes para el punto de este ejemplo).
Si compila el código anterior y lo utiliza para copiar un archivo enorme, notará que es muy lento.
De hecho, será al menos un par de órdenes de magnitud más lento que las utilidades estándar de
copia de archivos del sistema operativo.
La razón principal por la que el ejemplo anterior es lento (en el caso del archivo grande) es que
está realizando lecturas de un byte y escrituras de un byte en flujos de bytes sin búfer. La forma
sencilla de mejorar el rendimiento es envolver las secuencias con secuencias almacenadas en
búfer. Por ejemplo:
import java.io.*;
https://riptutorial.com/es/home 474
os.write(octet);
}
}
}
}
• Con is , los datos se leen del archivo en el búfer unos pocos kilobytes a la vez. Cuando se
llama a read() , la implementación normalmente devolverá un byte desde el búfer. Solo se
leerá de la secuencia de entrada subyacente si el búfer se ha vaciado.
• InputStream y OutputStream son las API base para E / S binarias basadas en flujo
• Reader y Writer son las API básicas para la E / S de texto basada en flujo.
• El método Java en una aplicación Java o las llamadas a procedimientos nativos en las
bibliotecas de tiempo de ejecución nativas de la JVM son rápidas. Por lo general, toman un
par de instrucciones de la máquina y tienen un impacto mínimo en el rendimiento.
• Por el contrario, las llamadas en tiempo de ejecución de JVM al sistema operativo no son
rápidas. Implican algo conocido como "syscall". El patrón típico para un syscall es el
siguiente:
https://riptutorial.com/es/home 475
diga que acceda a la memoria que el proceso del usuario no debería ver.
5. Se realiza el trabajo específico de syscall. En el caso de un syscall de read , esto
puede implicar:
1. verificar que haya datos para leer en la posición actual del descriptor de archivo
2. llamar al controlador del sistema de archivos para obtener los datos requeridos
del disco (o donde sea que estén almacenados) en el caché del búfer,
3. copiar datos desde la memoria caché del búfer a la dirección proporcionada por
la JVM
4. Ajuste de la posición del descriptor de archivos de Pointstream
6. Regreso del syscall. Esto implica cambiar de nuevo las asignaciones de VM y cambiar
de estado privilegiado.
Como se puede imaginar, realizar una sola llamada puede miles de instrucciones de la máquina.
De manera conservadora, al menos dos órdenes de magnitud más largos que una llamada de
método regular. (Probablemente tres o más).
Teniendo en cuenta esto, la razón por la que los flujos de búferes hacen una gran diferencia es
que reducen drásticamente el número de syscalls. En lugar de hacer un syscall para cada
llamada de read() , la secuencia de entrada almacenada en el búfer lee una gran cantidad de
datos en un búfer según se requiera. La mayoría de las llamadas de read() en el flujo almacenado
en búfer realizan algunas comprobaciones de límites simples y devuelven un byte que se leyó
anteriormente. Un razonamiento similar se aplica en el caso del flujo de salida, y también en los
casos del flujo de caracteres.
https://riptutorial.com/es/home 476
Capítulo 69: Errores de Java - sintaxis de
lenguaje
Introducción
Varios usos indebidos del lenguaje de programación Java pueden llevar a cabo un programa para
generar resultados incorrectos a pesar de haber sido compilados correctamente. El propósito
principal de este tema es enumerar las dificultades comunes con sus causas y proponer la forma
correcta de evitar caer en tales problemas.
Observaciones
Este tema trata sobre aspectos específicos de la sintaxis del lenguaje Java que son propensos a
errores o que no deben usarse de ciertas maneras.
Examples
Pitfall - Ignorar la visibilidad del método
Incluso los desarrolladores Java experimentados tienden a pensar que Java tiene solo tres
modificadores de protección. ¡El lenguaje en realidad tiene cuatro! El nivel de visibilidad del
paquete privado (también conocido como predeterminado) a menudo se olvida.
Debes prestar atención a los métodos que haces públicos. Los métodos públicos en una
aplicación son la API visible de la aplicación. Esto debería ser lo más pequeño y compacto
posible, especialmente si está escribiendo una biblioteca reutilizable (vea también el principio
SOLID ). Es importante considerar de manera similar la visibilidad de todos los métodos, y usar
solo el acceso privado protegido o en paquetes cuando sea apropiado.
Cuando declara métodos que deberían ser privados como públicos, expone los detalles de la
implementación interna de la clase.
Un corolario de esto es que solo prueba por unidad los métodos públicos de su clase; de hecho,
solo puede probar métodos públicos. Es una mala práctica aumentar la visibilidad de los métodos
privados solo para poder ejecutar pruebas unitarias contra esos métodos. La prueba de métodos
públicos que llaman a los métodos con una visibilidad más restrictiva debería ser suficiente para
probar una API completa. Nunca se debe ampliar su API con los métodos más comunes sólo
para permitir las pruebas unitarias.
Estos problemas de Java pueden ser muy embarazosos y, a veces, no se han descubierto hasta
que se ejecutan en producción. El comportamiento fallido en las declaraciones de cambio suele
ser útil; sin embargo, faltar una palabra clave de "ruptura" cuando no se desea tal comportamiento
https://riptutorial.com/es/home 477
puede llevar a resultados desastrosos. Si ha olvidado poner un "descanso" en el "caso 0" en el
ejemplo de código a continuación, el programa escribirá "Cero" seguido de "Uno", ya que el flujo
de control que se encuentra aquí pasará por toda la declaración del "interruptor" hasta que
Alcanza un “descanso”. Por ejemplo:
En la mayoría de los casos, la solución más limpia sería utilizar interfaces y mover el código con
un comportamiento específico a implementaciones separadas ( composición sobre herencia )
switch(caseIndex) {
[...]
case 2:
System.out.println("Two");
// fallthrough
default:
System.out.println("Default");
Este es un error que causa confusión real para los principiantes de Java, al menos la primera vez
que lo hacen. En lugar de escribir esto:
if (feeling == HAPPY)
System.out.println("Smile");
else
System.out.println("Frown");
if (feeling == HAPPY);
System.out.println("Smile");
else
System.out.println("Frown");
https://riptutorial.com/es/home 478
y se desconciertan cuando el compilador de Java les dice que la else está fuera de lugar. El
compilador de Java interpreta lo anterior de la siguiente manera:
if (feeling == HAPPY)
/*empty statement*/ ;
System.out.println("Smile"); // This is unconditional
else // This is misplaced. A statement cannot
// start with 'else'
System.out.println("Frown");
En otros casos, no habrá errores de compilación, pero el código no hará lo que pretende el
programador. Por ejemplo:
sólo imprime "Hola" una vez. Una vez más, el punto y coma falso significa que el cuerpo del bucle
for es una declaración vacía. Eso significa que la llamada println que sigue es incondicional.
Otra variación:
Esto dará un error de "No se puede encontrar el símbolo" para i . La presencia del punto y coma
espurio significa que la llamada de println está intentando usar i fuera de su alcance.
En esos ejemplos, hay una solución directa: simplemente elimine el punto y coma no esencial. Sin
embargo, hay algunas lecciones más profundas que se pueden extraer de estos ejemplos:
3. Utilice un indentador automático. Todos los IDE y muchos editores de texto simples
entienden cómo sangrar correctamente el código Java.
4. Esta es la lección más importante. Siga las últimas pautas de estilo de Java y ponga llaves
alrededor de las declaraciones "then" y "else" y la declaración del cuerpo de un bucle. La
abrazadera abierta ( { ) no debe estar en una nueva línea.
Si el programador siguiera las reglas de estilo, el ejemplo if con puntos y coma fuera de lugar se
vería así:
if (feeling == HAPPY); {
System.out.println("Smile");
} else {
https://riptutorial.com/es/home 479
System.out.println("Frown");
}
Eso se ve extraño para un ojo experimentado. Si autodentara ese código, probablemente se vería
así:
if (feeling == HAPPY); {
System.out.println("Smile");
} else {
System.out.println("Frown");
}
Trampa: omitir llaves: los problemas de "colgar si" y "colgar de otra manera"
La última versión de la guía de estilo Java de Oracle exige que las declaraciones "entonces" y
"más" en una instrucción if siempre deben estar entre "llaves" o "llaves". Reglas similares se
aplican a los cuerpos de varias declaraciones de bucle.
Esto no es realmente requerido por la sintaxis del lenguaje Java. De hecho, si la parte "entonces"
de una declaración if es una sola declaración, es legal omitir las llaves
if (a)
doSomething();
o incluso
if (a) doSomething();
Sin embargo, hay peligros en ignorar las reglas de estilo de Java y omitir las llaves.
Específicamente, aumenta significativamente el riesgo de que el código con sangría defectuosa
se lea mal.
if (a)
doSomething();
doSomeMore();
Este código parece decir que las llamadas a doSomething y doSomeMore se producen tanto si y sólo si
a es true . De hecho, el código está sangrado incorrectamente. La especificación del lenguaje
https://riptutorial.com/es/home 480
Java que la llamada doSomeMore() es una declaración separada que sigue a la instrucción if . La
sangría correcta es la siguiente:
if (a)
doSomething();
doSomeMore();
if (a)
if (b)
doX();
else if (c)
doY();
else
doZ();
El código anterior parece doZ que doZ se llamará cuando a sea false . De hecho, la sangría es
incorrecta una vez más. La sangría correcta para el código es:
if (a)
if (b)
doX();
else if (c)
doY();
else
doZ();
Si el código se escribiera de acuerdo con las reglas de estilo de Java, en realidad se vería así:
if (a) {
if (b) {
doX();
} else if (c) {
doY();
} else {
doZ();
}
}
Para ilustrar por qué es mejor eso, suponga que accidentalmente ha malgastado el código. Podría
terminar con algo como esto:
if (a) { if (a) {
if (b) { if (b) {
doX(); doX();
} else if (c) { } else if (c) {
doY(); doY();
} else { } else {
doZ(); doZ();
} }
https://riptutorial.com/es/home 481
} }
Pero en ambos casos, el código mal escrito "se ve mal" a los ojos de un programador Java
experimentado.
Este código no va a comportarse como se espera. El problema es que los métodos equals y
hashcode para Person no anulan los métodos estándar definidos por Object .
Sin embargo, hay una manera simple de lidiar con esto (desde Java 5 en adelante). Use la
anotación @Override siempre que pretenda que su método sea una anulación:
Java SE 5
@Override
public boolean equals(String other) {
....
https://riptutorial.com/es/home 482
}
@Override
public hashcode() {
....
}
}
El motivo es que el compilador de Java interpreta un literal entero que comienza con el dígito cero
('0') como un literal octal, no un literal decimal, como cabría esperar. Por lo tanto, 010 es el número
octal 10, que es 8 en decimal.
Pitfall - Declarar clases con los mismos nombres que las clases estándar
A veces, los programadores que son nuevos en Java cometen el error de definir una clase con un
nombre que es el mismo que una clase muy utilizada. Por ejemplo:
package com.example;
/**
* My string utilities
*/
public class String {
....
}
package com.example;
https://riptutorial.com/es/home 483
}
}
$ javac com/example/*.java
$ java com.example.Test
Error: Main method not found in class test.Test, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
Alguien que mire el código de la clase Test vería la declaración de main y miraría su firma y se
preguntaría de qué se está quejando el comando java . Pero, de hecho, el comando java está
diciendo la verdad.
Cuando declaramos una versión de String en el mismo paquete que Test , esta versión tiene
prioridad sobre la importación automática de java.lang.String . Por lo tanto, la firma del método
Test.main es en realidad
en lugar de
Lección: no defina clases que tengan el mismo nombre que las clases existentes en java.lang u
otras clases comúnmente utilizadas en la biblioteca de Java SE. Si haces eso, te estás abriendo
para todo tipo de errores oscuros.
Sin embargo, hay más errores con ok == true que simple torpeza. Considera esta variación:
https://riptutorial.com/es/home 484
public void check(boolean ok) {
if (ok = true) { // Oooops!
System.out.println("It is OK");
}
}
Aquí el programador ha escrito mal == como = ... y ahora el código tiene un error sutil. La
expresión x = true asigna incondicionalmente true a x y luego se evalúa como true . En otras
palabras, el método de check ahora imprimirá "Está bien", sin importar cuál fue el parámetro.
La lección aquí es dejar el hábito de usar == false y == true . Además de ser detallados, hacen
que su codificación sea más propensa a errores.
Nota: Una posible alternativa a ok == true que evita el escollo es usar las condiciones de Yoda ;
es decir, ponga el literal en el lado izquierdo del operador relacional, como en true == ok . Esto
funciona, pero la mayoría de los programadores probablemente estarían de acuerdo en que las
condiciones de Yoda son extrañas. Ciertamente, ok (o !ok ) es más conciso y más natural.
import com.example.somelib.*;
import com.acme.otherlib.*;
Supongamos que la primera vez que desarrolló el código contra la versión 1.0 de somelib y la
versión 1.0 de otherlib . Luego, en algún momento posterior, deberá actualizar sus dependencias
a versiones posteriores, y decide utilizar la versión 2.0 de otherlib . Supongamos también que
uno de los cambios que hicieron en otherlib entre 1.0 y 2.0 fue agregar una clase de Context .
Ahora, cuando recompiles la Test , obtendrás un error de compilación que te dice que el Context
es una importación ambigua.
Si está familiarizado con el código base, esto probablemente sea solo un inconveniente menor. Si
no es así, entonces tiene trabajo que hacer para solucionar este problema, aquí y potencialmente
en otro lugar.
El problema aquí es la importación de comodines. Por un lado, el uso de comodines puede hacer
que sus clases sean un poco más cortas. Por otra parte:
• Los cambios compatibles hacia arriba en otras partes de su base de código, bibliotecas
estándar de Java o bibliotecas de terceros pueden provocar errores de compilación.
https://riptutorial.com/es/home 485
• La legibilidad sufre. A menos que esté utilizando un IDE, puede ser difícil determinar cuál de
las importaciones de comodín está generando una clase con nombre.
La lección es que es una mala idea usar las importaciones de comodines en el código que debe
ser de larga duración. Las importaciones específicas (sin comodines) no son mucho esfuerzo de
mantener si usa un IDE, y el esfuerzo vale la pena.
Una pregunta que ocasionalmente en StackOverflow es si es apropiado usar assert para validar
los argumentos proporcionados a un método, o incluso las entradas proporcionadas por el
usuario.
Esto es lo que la Especificación del lenguaje Java (JLS 14.10, para Java 8) aconseja sobre este
asunto:
Debido a que las aserciones pueden estar deshabilitadas, los programas no deben
asumir que las expresiones contenidas en las aserciones serán evaluadas. Por lo
tanto, estas expresiones booleanas generalmente deben estar libres de efectos
secundarios. La evaluación de tal expresión booleana no debería afectar ningún
estado que sea visible después de que se complete la evaluación. No es ilegal que
una expresión booleana contenida en una aserción tenga un efecto secundario, pero
generalmente es inapropiado, ya que podría causar que el comportamiento del
programa varíe dependiendo de si las aserciones estaban habilitadas o deshabilitadas.
https://riptutorial.com/es/home 486
nunca se detecte, pero es posible hacerlo, por lo tanto, las reglas para las
declaraciones de prueba deben tratar las aserciones que aparecen en un bloque de
prueba de manera similar al tratamiento actual de las declaraciones de lanzamiento.
// example:
Boolean ignore = null;
if (ignore == false) {
System.out.println("Do not ignore!");
}
}
}
El escollo aquí es que null se compara con false . Como estamos comparando un boolean
primitivo con un Boolean , Java intenta desempaquetar el Object Boolean en un equivalente
primitivo, listo para la comparación. Sin embargo, dado que ese valor es null , se lanza una
NullPointerException .
Java es incapaz de comparar tipos primitivos contra valores null , lo que provoca una
NullPointerException en tiempo de ejecución. Considere el caso primitivo de la condición false ==
null ; esto generaría un error de tiempo de compilación de incomparable types: int and <null> .
https://riptutorial.com/es/home 487
Capítulo 70: Errores de Java - Uso de
excepciones
Introducción
Varios usos indebidos del lenguaje de programación Java pueden llevar a cabo un programa para
generar resultados incorrectos a pesar de haber sido compilados correctamente. El propósito
principal de este tema es enumerar las dificultades comunes relacionadas con el manejo de
excepciones y proponer la forma correcta de evitar tales dificultades.
Examples
Pitfall - Ignorar o aplastar excepciones
Este ejemplo trata sobre ignorar deliberadamente o "aplastar" las excepciones. O para ser más
precisos, se trata de cómo capturar y manejar una excepción de una manera que la ignora. Sin
embargo, antes de describir cómo hacer esto, primero debemos señalar que las excepciones de
aplastamiento generalmente no son la forma correcta de tratarlas.
Las excepciones generalmente se lanzan (por algo) para notificar a otras partes del programa que
ha ocurrido algún evento significativo (es decir, "excepcional"). En general (aunque no siempre)
una excepción significa que algo ha salido mal. Si codifica su programa para eliminar la
excepción, existe la posibilidad de que el problema vuelva a aparecer en otra forma. Para
empeorar las cosas, cuando aplastas la excepción, estás desechando la información en el objeto
de excepción y su seguimiento de pila asociado. Es probable que sea más difícil averiguar cuál
fue la fuente original del problema.
try {
inputStream = new FileInputStream("someFile");
} catch (IOException e) {
/* add exception handling code here */
}
Claramente, el programador ha aceptado la sugerencia del IDE para que desaparezca el error de
compilación, pero la sugerencia fue inapropiada. (Si el archivo ha fallado, lo más probable es que
el programa haga algo al respecto. Con la "corrección" anterior, es probable que el programa falle
más adelante; por ejemplo, con una NullPointerException porque inputStream ahora es null ).
Dicho esto, aquí hay un ejemplo de aplastar deliberadamente una excepción. (Para los fines del
argumento, supongamos que hemos determinado que una interrupción al mostrar la autofoto es
inofensiva). El comentario le dice al lector que eliminamos la excepción deliberadamente y por
https://riptutorial.com/es/home 488
qué lo hicimos.
try {
selfie.show();
} catch (InterruptedException e) {
// It doesn't matter if showing the selfie is interrupted.
}
Otra forma convencional de resaltar que estamos aplastando deliberadamente una excepción sin
decir por qué es indicar esto con el nombre de la variable de excepción, como este:
try {
selfie.show();
} catch (InterruptedException ignored) { }
Algunos IDE (como IntelliJ IDEA) no mostrarán una advertencia sobre el bloque catch vacío si el
nombre de la variable se establece en ignored .
Un patrón de pensamiento común que los programadores inexpertos Java es que las excepciones
son "un problema" o "una carga" y la mejor manera de lidiar con esto es que coger todos 1 tan
pronto como sea posible. Esto lleva a un código como este:
....
try {
InputStream is = new FileInputStream(fileName);
// process the input
} catch (Exception ex) {
System.out.println("Could not open file " + fileName);
}
El código anterior tiene un defecto significativo. La catch realidad va a atrapar más excepciones
de las que espera el programador. Supongamos que el valor del nombre de fileName es null ,
debido a un error en otra parte de la aplicación. Esto hará que el constructor FileInputStream lance
una NullPointerException . El controlador detectará esto e informará al usuario:
que es inútil y confuso. Peor aún, supongamos que fue el código de "procesar la entrada" el que
lanzó la excepción inesperada (activada o desactivada). Ahora el usuario recibirá el mensaje
engañoso para un problema que no se produjo al abrir el archivo y es posible que no esté
relacionado con la E / S en absoluto.
La raíz del problema es que el programador ha codificado un controlador para Exception . Esto es
casi siempre un error:
https://riptutorial.com/es/home 489
• El Error captura detectará las excepciones sin marcar que señalan errores internos de JVM.
Estos errores generalmente no son recuperables y no deben ser detectados.
• La captura de Throwable capturará todas las excepciones posibles.
En general, la solución correcta es lidiar con las excepciones que se lanzan. Por ejemplo, puedes
atraparlos y manejarlos in situ:
try {
InputStream is = new FileInputStream(fileName);
// process the input
} catch (FileNotFoundException ex) {
System.out.println("Could not open file " + fileName);
}
Hay muy pocas situaciones en las que la captura de Exception es apropiada. El único que surge
comúnmente es algo como esto:
Aquí realmente queremos lidiar con todas las excepciones, por lo que capturar Exception (o
incluso Throwable ) es correcto.
try {
InputStream is = new FileInputStream(someFile); // could throw IOException
https://riptutorial.com/es/home 490
...
if (somethingBad) {
throw new Exception(); // WRONG
}
} catch (IOException ex) {
System.err.println("cannot open ...");
} catch (Exception ex) {
System.err.println("something bad happened"); // WRONG
}
El problema es que debido a que lanzamos una instancia de Exception , nos vemos obligados a
atraparla. Sin embargo, como se describe en otro ejemplo, la captura de Exception es mala. En
esta situación, se vuelve difícil discriminar entre el caso "esperado" de una Exception que se lanza
si somethingBad es una true , y el caso inesperado en el que realmente detectamos una excepción
no comprobada, como NullPointerException .
Si se permite que la excepción de nivel superior se propague, nos encontramos con otros
problemas:
• Ahora tenemos que recordar todas las diferentes razones por las que lanzamos el nivel
superior y discriminarlos / manejarlos.
• En el caso de Exception y Throwable , también necesitamos agregar estas excepciones a la
cláusula de throws de métodos si queremos que la excepción se propague. Esto es
problemático, como se describe a continuación.
En resumen, no tirar estas excepciones. Lanzar una excepción más específica que describa con
más detalle el "evento excepcional" que ha ocurrido. Si lo necesita, defina y use una clase de
excepción personalizada.
Este consejo significa que se deben evitar ciertos otros patrones. Por ejemplo:
try {
doSomething();
} catch (Exception ex) {
https://riptutorial.com/es/home 491
report(ex);
throw ex;
}
Lo anterior intenta registrar todas las excepciones a medida que pasan, sin manejarlas
definitivamente. Desafortunadamente, antes de Java 7, el throw ex; La declaración hizo que el
compilador pensara que se podía lanzar cualquier Exception . Eso podría forzarlo a declarar el
método de cierre como throws Exception . Desde Java 7 en adelante, el compilador sabe que el
conjunto de excepciones que podrían ser (relanzadas) es menor.
try {
// Some code
} catch (Exception) {
// Some error handling
}
Viene con muchos problemas diferentes. Pero un problema importante es que puede provocar
interbloqueos ya que rompe el sistema de interrupción al escribir aplicaciones de subprocesos
múltiples.
Si inicia un hilo, por lo general, también debe poder detenerlo bruscamente por varios motivos.
t.start();
El t.interrupt() generará una InterruptedException en ese hilo, que está destinado a cerrar el
hilo. Pero, ¿qué pasa si el subproceso necesita limpiar algunos recursos antes de que se detenga
por completo? Para esto puede atrapar la excepción interrumpida y hacer algo de limpieza.
https://riptutorial.com/es/home 492
Thread t = new Thread(new Runnable() {
public void run() {
try {
while (true) {
//Do something indefinetely
}
} catch (InterruptedException ex) {
//Do some quick cleanup
Por lo tanto, es mejor capturar Excepciones individualmente, pero si insistes en usar un catch-all,
al menos debes capturar la InterruptedException individualmente de antemano.
https://riptutorial.com/es/home 493
} catch (InterruptedException ex) {
// Some quick cleanup code
Thread.currentThread().interrupt();
}
}
}
La esencia de esto es que es una mala idea (en Java) usar excepciones y el manejo de
excepciones para implementar el control de flujo normal. Por ejemplo, compare estas dos formas
de tratar un parámetro que podría ser nulo.
En este ejemplo, estamos (por diseño) tratando el caso donde la word es null como si fuera una
palabra vacía. Las dos versiones se ocupan de null ya sea utilizando convencional si ... más y / o
intentan ... atrapar . ¿Cómo deberíamos decidir qué versión es mejor?
Por otro lado, hay muchas situaciones donde el uso de excepciones es más legible, más eficiente
https://riptutorial.com/es/home 494
y (a veces) más correcto que usar el código condicional para tratar eventos "excepcionales". De
hecho, hay situaciones raras en las que es necesario usarlas para eventos "no excepcionales"; Es
decir, eventos que ocurren con relativa frecuencia. Para este último, vale la pena buscar formas
de reducir los gastos generales de creación de objetos de excepción.
Una de las cosas más molestas que pueden hacer los programadores es dispersar las llamadas a
printStackTrace() largo de su código.
• Para una aplicación que está destinada a usuarios finales que no son programadores de
Java, un seguimiento de pila no es informativo en el mejor de los casos, y alarmante en el
peor.
• Para una aplicación del lado del servidor, es probable que nadie vea la salida estándar.
Una idea mejor es no llamar directamente a printStackTrace , o si lo llama, hágalo de manera que
el seguimiento de la pila se escriba en un archivo de registro o de error en lugar de hacerlo en la
consola del usuario final.
Una forma de hacer esto es usar un marco de registro y pasar el objeto de excepción como un
parámetro del evento de registro. Sin embargo, incluso el registro de la excepción puede ser
perjudicial si se realiza de forma poco prudente. Considera lo siguiente:
Si la excepción se produce en el method2 , es probable que vea dos copias del mismo seguimiento
de pila en el archivo de registro, que corresponde al mismo error.
En resumen, registre la excepción o vuelva a lanzarla más (posiblemente envuelta con otra
excepción). No hagas ambas cosas.
https://riptutorial.com/es/home 495
Throwabletiene dos subclases directas, Exception y Error . Si bien es posible crear una nueva
clase que extienda Throwable directamente, esto no es aconsejable ya que muchas aplicaciones
suponen que solo existe Exception y Error .
Más aún, no hay ningún beneficio práctico en la subclasificación directa de Throwable , ya que la
clase resultante es, en efecto, simplemente una excepción comprobada. La Exception subclases
en cambio resultará en el mismo comportamiento, pero transmitirá más claramente su intención.
https://riptutorial.com/es/home 496
Capítulo 71: Escáner
Sintaxis
• Escáner escáner = nuevo escáner (fuente de origen);
• Escáner escáner = nuevo escáner (System.in);
Parámetros
Parámetro Detalles
Fuente La fuente puede ser una de String, File o cualquier tipo de InputStream
Observaciones
La clase Scanner se introdujo en Java 5. El método reset() se agregó en Java 6, y se agregaron
un par de nuevos constructores en Java 7 para la interoperabilidad con la (entonces) nueva
interfaz Path .
Examples
Lectura de la entrada del sistema utilizando el escáner
El objeto del escáner se inicializa para leer la entrada desde el teclado. Por lo tanto, para la
siguiente entrada del teclado, producirá la salida como Reading from keyboard
Reading
from
keyboard
//space
https://riptutorial.com/es/home 497
scanner = new Scanner(new File("Names.txt"));
while (scanner.hasNext()) {
System.out.println(scanner.nextLine());
}
} catch (Exception e) {
System.err.println("Exception occurred!");
} finally {
if (scanner != null)
scanner.close();
}
Aquí se crea un objeto Scanner pasando un objeto File que contiene el nombre de un archivo de
texto como entrada. Este archivo de texto se abrirá con el objeto Archivo y se leerá con el objeto
del escáner en las siguientes líneas. scanner.hasNext() verificará si hay una próxima línea de
datos en el archivo de texto. Combinar que con un while de bucle le permitirá iterar a través de
cada línea de datos en el Names.txt archivo. Para recuperar los datos en sí, podemos usar
métodos como nextLine() , nextInt() , nextBoolean() , etc. En el ejemplo anterior, se usa
scanner.nextLine() . nextLine() hace referencia a la siguiente línea en un archivo de texto, y su
combinación con un objeto de scanner permite imprimir el contenido de la línea. Para cerrar un
objeto de escáner, usaría .close() .
Al usar try con recursos (desde Java 7 en adelante), el código mencionado anteriormente puede
escribirse con elegancia de la siguiente manera.
Puede usar Scanner para leer todo el texto de la entrada como una Cadena, usando \Z (entrada
completa) como delimitador. Por ejemplo, esto se puede usar para leer todo el texto en un archivo
de texto en una línea:
Recuerde que tendrá que cerrar el Escáner, así como también capturar la IoException esto puede
IoException , como se describe en el ejemplo Leyendo la entrada del archivo usando el Escáner .
https://riptutorial.com/es/home 498
Scanner scanner = null;
try{
scanner = new Scanner("i,like,unicorns").useDelimiter(",");;
while(scanner.hasNext()){
System.out.println(scanner.next());
}
}catch(Exception e){
e.printStackTrace();
}finally{
if (scanner != null)
scanner.close();
}
Esto le permitirá leer cada elemento en la entrada individualmente. Tenga en cuenta que no debe
utilizar este para analizar los datos CSV, en cambio, utilizar una biblioteca adecuada analizador
CSV, consulte CSV analizador para Java para otras posibilidades.
package com.stackoverflow.scanner;
import javax.annotation.Nonnull;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.regex.Pattern;
static
{
final SortedSet<String> ecmds = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
ecmds.addAll(Arrays.asList("exit", "done", "quit", "end", "fino"));
EXIT_COMMANDS = Collections.unmodifiableSortedSet(ecmds);
final SortedSet<String> hcmds = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
hcmds.addAll(Arrays.asList("help", "helpi", "?"));
HELP_COMMANDS = Collections.unmodifiableSet(hcmds);
DATE_PATTERN = Pattern.compile("\\d{4}([-\\/])\\d{2}\\1\\d{2}"); //
http://regex101.com/r/xB8dR3/1
HELP_MESSAGE = format("Please enter some data or enter one of the following commands
to exit %s", EXIT_COMMANDS);
}
/**
https://riptutorial.com/es/home 499
* Using exceptions to control execution flow is always bad.
* That is why this is encapsulated in a method, this is done this
* way specifically so as not to introduce any external libraries
* so that this is a completely self contained example.
* @param s possible url
* @return true if s represents a valid url, false otherwise
*/
private static boolean isValidURL(@Nonnull final String s)
{
try { new URL(s); return true; }
catch (final MalformedURLException e) { return false; }
}
private static void output(@Nonnull final String format, @Nonnull final Object... args)
{
System.out.println(format(format, args));
}
https://riptutorial.com/es/home 500
else
{
if (EXIT_COMMANDS.contains(next))
{
output("Exit command %s issued, exiting!", next);
break;
}
else if (HELP_COMMANDS.contains(next)) { output(HELP_MESSAGE); }
else { output("You entered an unclassified String = %s", next); }
}
}
}
/*
This will close the underlying Readable, in this case System.in, and free those
resources.
You will not be to read from System.in anymore after this you call .close().
If you wanted to use System.in for something else, then don't close the Scanner.
*/
sis.close();
System.exit(0);
}
}
import java.util.Scanner;
Si desea leer un int desde la línea de comandos, solo use este fragmento. En primer lugar, debe
crear un objeto Escáner, que escucha System.in, que es la línea de comandos de forma
predeterminada, cuando inicia el programa desde la línea de comandos. Después de eso, con la
ayuda del objeto Escáner, lee el primer int que el usuario pasa a la línea de comando y lo
almacena en el número de variable. Ahora puedes hacer lo que quieras con ese int almacenado.
puede suceder que use un escáner con el System.in como parámetro para el constructor,
entonces debe tener en cuenta que al cerrar el escáner se cerrará también el InputStream, lo que
hará que cada vez que intente leer la entrada (o cualquier otro) objeto de escáner) lanzará una
java.util.NoSuchElementException o una java.lang.IllegalStateException
ejemplo:
https://riptutorial.com/es/home 501
Lea Escáner en línea: https://riptutorial.com/es/java/topic/551/escaner
https://riptutorial.com/es/home 502
Capítulo 72: Escogiendo Colecciones
Introducción
Java ofrece una amplia variedad de colecciones. Elegir qué colección usar puede ser complicado.
Consulte la sección de ejemplos para ver un diagrama de flujo fácil de seguir para elegir la
colección adecuada para el trabajo.
Examples
Diagrama de flujo de colecciones Java
Utilice el siguiente diagrama de flujo para elegir la Colección correcta para el trabajo.
https://riptutorial.com/es/home 503
Capítulo 73: Escritor Buffered
Sintaxis
• nuevo BufferedWriter (Writer); // El constructor por defecto
• BufferedWriter.write (int c); // escribe un solo caracter
• BufferedWriter.write (String str); // escribe una cadena
• BufferedWriter.newLine (); // Escribe un separador de linea
• BufferedWriter.close (); // Cierra el BufferedWriter
Observaciones
• Si intenta escribir desde un BufferedWriter (utilizando BufferedWriter.write() ) después de
cerrar el BufferedWriter (utilizando BufferedWriter.close() ), se emitirá una IOException .
• El constructor BufferedWriter(Writer) NO lanza una IOException . Sin embargo, el
FileWriter(File) lanza una FileNotFoundException , que extiende la IOException . Por lo tanto,
la captura de la IOException también detectará la FileNotFoundException , nunca se necesita
una segunda instrucción catch a menos que planee hacer algo diferente con la
FileNotFoundException .
Examples
Escribe una línea de texto a archivo
Este código escribe la cadena en un archivo. Es importante cerrar el escritor, así que esto se
hace en un finally de bloque.
También tenga en cuenta que write(String s) no coloca el carácter de nueva línea después de
que se haya escrito la cadena. Para ponerlo use el método newLine() .
Java SE 7
https://riptutorial.com/es/home 504
public void writeLineToFile(String str) throws IOException {
Path path = Paths.get("file.txt");
try (BufferedWriter bw = Files.newBufferedWriter(path)) {
bw.write(str);
}
}
https://riptutorial.com/es/home 505
Capítulo 74: Estructuras de control básicas
Observaciones
Todas las estructuras de control, a menos que se indique lo contrario, utilizan declaraciones de
bloque . Estos se denotan mediante llaves {} .
Esto difiere de los enunciados normales , que no requieren llaves, pero también vienen con una
advertencia rígida en que solo se considerará la línea que sigue inmediatamente al enunciado
anterior.
Por lo tanto, es perfectamente válido escribir cualquiera de estas estructuras de control sin llaves,
siempre y cuando solo una declaración siga el principio, pero está totalmente desaconsejada ,
ya que puede llevar a implementaciones defectuosas o códigos rotos.
Ejemplo:
Examples
Si / Else Si / Else Control
if (i < 2) {
System.out.println("i is less than 2");
} else if (i > 2) {
System.out.println("i is more than 2");
} else {
System.out.println("i is not less than 2, and not more than 2");
}
La condición else if se comprueba solo si todas las condiciones anteriores (en las anteriores
construcciones else if , y la primaria if construye) se han probado como false . En este ejemplo,
la condición else if solo se verificará si i es mayor o igual a 2.
https://riptutorial.com/es/home 506
de que se omita.
Si ninguna de las condiciones if y else if han sido probadas como true , se ejecutará el bloque
else al final.
Para loops
Los tres componentes del bucle for (separados por ; ) son la declaración / inicialización de la
variable (aquí int i = 0 ), la condición (aquí i < 100 ) y la declaración de incremento (aquí i++ ).
La declaración de variables se realiza una vez como si se colocara justo dentro de { en la primera
ejecución. Luego se comprueba la condición, si es true el cuerpo del bucle se ejecutará, si es
false el bucle se detendrá. Suponiendo que el bucle continúe, el cuerpo se ejecutará y,
finalmente, cuando se alcance el } la instrucción de incremento se ejecutará justo antes de que se
compruebe nuevamente la condición.
Las llaves son opcionales (puede una línea con un punto y coma) si el bucle contiene una sola
instrucción. Pero, siempre se recomienda utilizar llaves para evitar malentendidos y errores.
Los componentes de bucle for son opcionales. Si su lógica de negocios contiene una de estas
partes, puede omitir el componente correspondiente de su bucle for .
Cualquier instrucción de bucle que tenga otra instrucción de bucle dentro de un bucle anidado
llamado. La misma forma para que el bucle tenga más bucle interno se llama 'anidado para bucle'.
for(;;){
//Outer Loop Statements
for(;;){
//Inner Loop Statements
}
//Outer Loop Statements
}
Se puede demostrar que Nested for loop imprime números en forma de triángulo.
https://riptutorial.com/es/home 507
System.out.print(" ");
}
for(int j=i;j<=9;j++){//Inner Loop -2
System.out.print(" "+j);
}
}
Mientras bucles
int i = 0;
while (i < 100) { // condition gets checked BEFORE the loop body executes
System.out.println(i);
i++;
}
A while bucle se ejecuta siempre que la condición dentro de los paréntesis es true . Esto también
se denomina estructura de "bucle de prueba previa" porque la declaración condicional debe
cumplirse antes de que se realice el cuerpo del bucle principal cada vez.
Las llaves son opcionales si el bucle contiene solo una declaración, pero algunas convenciones
de estilo de codificación prefieren tener las llaves independientemente.
El bucle do...while while difiere de otros bucles en que se garantiza que se ejecutará al menos
una vez . También se denomina estructura de "bucle posterior a la prueba" porque la declaración
condicional se realiza después del cuerpo del bucle principal.
int i = 0;
do {
i++;
System.out.println(i);
} while (i < 100); // Condition gets checked AFTER the content of the loop executes.
En este ejemplo, el bucle se ejecutará hasta que se imprima el número 100 (aunque la condición
sea i < 100 y no i <= 100 ), porque la condición del bucle se evalúa después de que se ejecuta el
bucle.
Con la garantía de al menos una ejecución, es posible declarar variables fuera del bucle e
inicializarlas dentro.
String theWord;
Scanner scan = new Scanner(System.in);
do {
theWord = scan.nextLine();
} while (!theWord.equals("Bird"));
System.out.println(theWord);
En este contexto, la theWord se define fuera del bucle, pero como se garantiza que tiene un valor
basado en su flujo natural, la theWord se inicializará.
https://riptutorial.com/es/home 508
Para cada
Java SE 5
Con Java 5 y superior, se pueden usar bucles para cada uno, también conocidos como bucles for
mejorados:
strings.add("This");
strings.add("is");
strings.add("a for-each loop");
Para cada bucle se puede usar para iterar sobre arreglos e implementaciones de la interfaz de
Iterable , el último incluye clases de colecciones , como List o Set .
La variable de bucle puede ser de cualquier tipo que sea asignable desde el tipo de fuente.
La variable de bucle para un bucle mejorado para Iterable<T> o T[] puede ser de tipo S , si
• T extends S
• tanto T como S son tipos primitivos y se pueden asignar sin una conversión
• S es un tipo primitivo y T puede convertirse en un tipo asignable a S después de la
conversión de unboxing.
• T es un tipo primitivo y se puede convertir a S mediante la conversión autoboxing.
Ejemplos:
T elements = ...
for (S s : elements) {
}
T S Compila
En t[] largo sí
largo[] En t no
Iterable<Byte> largo sí
Iterable<String> CharSequence sí
Iterable<CharSequence> Cuerda no
En t[] Largo no
En t[] Entero sí
https://riptutorial.com/es/home 509
Si / Else
int i = 2;
if (i < 2) {
System.out.println("i is less than 2");
} else {
System.out.println("i is greater than 2");
}
Cambiar la declaración
Con la excepción de continue , es posible usar cualquier declaración que cause la finalización
brusca de una declaración . Esto incluye:
• break
• return
• throw
En el siguiente ejemplo, una declaración de switch típica se escribe con cuatro casos posibles,
incluido el default .
https://riptutorial.com/es/home 510
case 1:
System.out.println("i is one");
break;
case 2:
System.out.println("i is two");
break;
default:
System.out.println("i is less than zero or greater than two");
}
Al omitir una break o cualquier declaración que pudiera completarse de manera abrupta, podemos
aprovechar lo que se conoce como casos "directos", que evalúan varios valores. Esto se puede
usar para crear rangos para que un valor sea exitoso, pero aún no es tan flexible como las
desigualdades.
Java SE 5
enum Option {
BLUE_PILL,
RED_PILL
}
https://riptutorial.com/es/home 511
}
}
Java SE 7
Operador ternario
A veces hay que verificar una condición y establecer el valor de una variable.
Por ej.
String name;
if (A > B) {
name = "Billy";
} else {
name = "Jimmy";
}
Descanso
La instrucción break termina un bucle (como for , while ) o la evaluación de una instrucción switch
.
Lazo:
while(true) {
if(someCondition == 5) {
break;
}
https://riptutorial.com/es/home 512
}
Si varios bucles se conectan en cascada, solo la mayoría de los bucles internos terminan
utilizando break .
La estructura de control try { ... } catch ( ... ) { ... } se utiliza para manejar las excepciones
.
Esto imprimiría:
Se puede añadir una cláusula finally después de la catch . La cláusula finally siempre se
ejecutaría, independientemente de si se lanzó una excepción.
Esto imprimiría:
https://riptutorial.com/es/home 513
Pausa anidada / continuar
outerloop:
for(...) {
innerloop:
for(...) {
if(condition1)
break outerloop;
if(condition2)
continue innerloop; // equivalent to: continue;
}
}
La instrucción continue se usa para omitir los pasos restantes en la iteración actual y comenzar
con la siguiente iteración de bucle. El control pasa de la instrucción de continue al valor de paso
(incremento o decremento), si lo hay.
La instrucción de continue también puede hacer que el control del programa cambie al valor de
paso (si lo hay) de un bucle con nombre:
https://riptutorial.com/es/home 514
Capítulo 75: Evaluación XML XPath
Observaciones
Las expresiones XPath se utilizan para navegar y seleccionar uno o más nodos dentro de un
documento del árbol XML, como seleccionar un elemento o atributo determinado.
Consulte esta recomendación del W3C para obtener una referencia en este idioma.
Examples
Evaluando un NodeList en un documento XML
<documentation>
<tags>
<tag name="Java">
<topic name="Regular expressions">
<example>Matching groups</example>
<example>Escaping metacharacters</example>
</topic>
<topic name="Arrays">
<example>Looping over arrays</example>
<example>Converting an array to a list</example>
</topic>
</tag>
<tag name="Android">
<topic name="Building Android projects">
<example>Building an Android application using Gradle</example>
<example>Building an Android application using Maven</example>
</topic>
<topic name="Layout resources">
<example>Including layout resources</example>
<example>Supporting multiple device screens</example>
</topic>
</tag>
</tags>
</documentation>
Lo siguiente recupera todos los nodos de example para la etiqueta de Java (use este método si
solo evalúa XPath en el XML una vez. Vea otro ejemplo para cuando se evalúan múltiples
llamadas de XPath en el mismo archivo XML):
https://riptutorial.com/es/home 515
Analizar múltiples expresiones XPath en un solo XML
Usando el mismo ejemplo que Evaluating a NodeList en un documento XML , aquí es cómo
podría hacer múltiples llamadas XPath de manera eficiente:
<documentation>
<tags>
<tag name="Java">
<topic name="Regular expressions">
<example>Matching groups</example>
<example>Escaping metacharacters</example>
</topic>
<topic name="Arrays">
<example>Looping over arrays</example>
<example>Converting an array to a list</example>
</topic>
</tag>
<tag name="Android">
<topic name="Building Android projects">
<example>Building an Android application using Gradle</example>
<example>Building an Android application using Maven</example>
</topic>
<topic name="Layout resources">
<example>Including layout resources</example>
<example>Supporting multiple device screens</example>
</topic>
</tag>
</tags>
</documentation>
...
En este caso, desea tener la expresión compilada antes de las evaluaciones, para que cada
llamada a evaluate no compile la misma expresión. La sintaxis simple sería:
https://riptutorial.com/es/home 516
DocumentBuilder builder = DocumentBuilderFactory.newInstance();
Document doc = builder.parse(new File("path/to/xml.xml")); //Specify XML file path
En general, dos llamadas a XPathExpression.evaluate() serán mucho más eficientes que dos
llamadas a XPath.evaluate() .
https://riptutorial.com/es/home 517
Capítulo 76: Examen de la unidad
Introducción
Las pruebas unitarias son una parte integral del desarrollo impulsado por pruebas, y una
característica importante para construir cualquier aplicación robusta. En Java, las pruebas
unitarias se realizan casi exclusivamente utilizando bibliotecas y marcos externos, la mayoría de
los cuales tienen su propia etiqueta de documentación. Este talón sirve como medio para
presentar al lector las herramientas disponibles y su documentación respectiva.
Observaciones
JUIT
Prueba
Mockito - marco burlón ; Permite que los objetos sean imitados. Útil para imitar el comportamiento
esperado de una unidad externa dentro de la prueba de una unidad dada, para no vincular el
comportamiento de la unidad externa a las pruebas de la unidad dada.
JBehave - BDD Framework. Permite vincular las pruebas a los comportamientos de los usuarios
(lo que permite la validación de requisitos / escenarios) No hay etiquetas de documentos
disponibles en el momento de la escritura; Aquí hay un enlace externo .
Examples
¿Qué es la prueba unitaria?
https://riptutorial.com/es/home 518
conoce los conceptos básicos de la prueba de unidad, siéntase libre de saltar a los comentarios,
donde se mencionan los marcos específicos.
// Application-level test.
public Example() {
Consumer c = new Consumer();
System.out.println("VALUE = " + c.getVal());
}
// Your Module.
class Consumer {
private Capitalizer c;
public Consumer() {
c = new Capitalizer();
}
public Capitalizer() {
dr = new DataReader();
}
https://riptutorial.com/es/home 519
Entonces este ejemplo es trivial; DataReader obtiene los datos de un archivo, los pasa al
Capitalizer , que convierte todos los caracteres a mayúsculas, que luego pasa al Consumer . Pero
el DataReader está fuertemente vinculado a nuestro entorno de aplicación, por lo que aplazamos
las pruebas de esta cadena hasta que estemos listos para implementar una versión de prueba.
Ahora, supongamos que en algún momento del lanzamiento de una versión, por razones
desconocidas, el método getVal() en Capitalizer cambió de devolver una cadena toUpperCase() a
una toLowerCase() :
Claramente, esto rompe el comportamiento esperado. Pero, debido a los arduos procesos
involucrados en la ejecución del DataReader , no lo notaremos hasta nuestra próxima
implementación de prueba. Entonces, los días / semanas / meses pasan con este error en
nuestro sistema, y luego el gerente de producto ve esto y se dirige instantáneamente a usted, el
líder del equipo asociado con el Consumer . "¿Por qué está sucediendo esto? ¿Qué cambiaron?"
Obviamente, no tienes ni idea. No tienes idea de lo que está pasando. No cambiaste ningún
código que debería estar tocando esto; ¿Por qué se rompe de repente?
Hay que apreciar que, en este ejemplo, he expresado un error muy trivial que se introdujo y pasó
desapercibido. En una aplicación industrial, con docenas de módulos que se actualizan
constantemente, estos pueden arrastrarse por todas partes. Arregla algo con un módulo, solo
para darte cuenta de que el mismo comportamiento que "arreglaste" se confió de alguna manera
en otra parte (ya sea interna o externamente).
Sin una validación rigurosa, las cosas entrarán en el sistema. Es posible que, si se descuida lo
suficiente, esto resulte en mucho trabajo adicional al tratar de arreglar los cambios (y luego
corregir esos arreglos, etc.), que un producto aumente en el trabajo restante a medida que se
pone esfuerzo en ello. No quieres estar en esta situación.
https://riptutorial.com/es/home 520
Las pruebas deben ser de grano fino
El segundo problema observado en nuestro ejemplo anterior es la cantidad de tiempo que llevó
rastrear el error. El gerente de producto le hizo un ping cuando los evaluadores lo notaron, usted
investigó y encontró que el Capitalizer estaba devolviendo datos aparentemente malos, hizo un
ping al equipo de Capitalizer con sus hallazgos, investigaron, etc., etc., etc.
El mismo punto que mencioné anteriormente sobre la cantidad y la dificultad de este ejemplo
trivial se sostiene aquí. Obviamente, cualquier persona razonablemente versada en Java podría
encontrar el problema introducido rápidamente. Pero a menudo es mucho, mucho más difícil
rastrear y comunicar problemas. Tal vez el equipo de Capitalizer proporcionó un JAR sin ninguna
fuente. Tal vez estén ubicados en el otro lado del mundo, y las horas de comunicación son muy
limitadas (tal vez a correos electrónicos que se envían una vez al día). Puede dar lugar a errores
que tardan semanas o más en rastrearse (y, nuevamente, podría haber varios de estos para una
versión determinada).
Para mitigar esto, queremos que las pruebas rigurosas se realicen en el nivel más preciso
posible (también desea que las pruebas generales aseguren que los módulos interactúen
correctamente, pero ese no es nuestro punto focal aquí). Queremos especificar rigurosamente
cómo funciona toda la funcionalidad orientada hacia el exterior (como mínimo), y probar esa
funcionalidad.
Aquí se hacen algunas omisiones en cuanto a cómo implementar estas pruebas, pero están
cubiertas en la documentación específica del marco (enlazada en los comentarios). Con suerte,
esto sirve como un ejemplo de por qué las pruebas unitarias son importantes.
https://riptutorial.com/es/home 521
Capítulo 77: Excepciones y manejo de
excepciones.
Introducción
Los objetos del tipo Throwable y sus subtipos pueden enviarse a la pila con la palabra clave throw y
capturados con try…catch declaraciones try…catch .
Sintaxis
• void someMethod () emite SomeException {} // declaración de método, obliga a los
llamadores a capturar si SomeException es un tipo de excepción comprobada
• tratar {
• captura (SomeException e) {
• finalmente {
//code that will always run, whether try block finishes or not
Examples
Atrapando una excepción con try-catch
Se puede capturar y manejar una excepción utilizando la declaración try...catch . (De hecho, las
declaraciones de try toman otras formas, como se describe en otros ejemplos sobre
try...catch...finally y try-with-resources ).
https://riptutorial.com/es/home 522
try {
doSomething();
} catch (SomeException e) {
handle(e);
}
// next statement
try {
doSomething();
} catch (SomeException e) {
handleOneWay(e)
} catch (SomeOtherException e) {
handleAnotherWay(e);
}
// next statement
Si hay varios bloques de catch , se intentan uno por uno comenzando con el primero, hasta que
se encuentra una coincidencia para la excepción. El controlador correspondiente se ejecuta
(como anteriormente) y luego el control se pasa a la siguiente instrucción después de la
instrucción try...catch . Los bloques de catch posteriores a los que coinciden siempre se omiten,
incluso si el código del manejador lanza una excepción .
La estrategia de coincidencia "de arriba abajo" tiene consecuencias para los casos en que las
excepciones en los bloques catch no son desunidas. Por ejemplo:
try {
throw new RuntimeException("test");
} catch (Exception e) {
System.out.println("Exception");
https://riptutorial.com/es/home 523
} catch (RuntimeException e) {
System.out.println("RuntimeException");
}
La lección para aprender de esto es que los bloques de catch más específicos (en términos de los
tipos de excepción) deben aparecer primero, y los más generales deben ser los últimos. (Algunos
compiladores de Java le avisarán si una catch nunca puede ejecutarse, pero esto no es un error
de compilación).
A partir de Java SE 7, un solo bloque catch puede manejar una lista de excepciones no
relacionadas. El tipo de excepción se enumera, separado por un símbolo de barra vertical ( | ).
Por ejemplo:
try {
doSomething();
} catch (SomeException | SomeOtherException e) {
handleSomeException(e);
}
El comportamiento de una captura de múltiples excepciones es una extensión simple para el caso
de excepción única. La catch coincide si la excepción lanzada coincide (al menos) con una de las
excepciones enumeradas.
Hay alguna sutileza adicional en la especificación. El tipo de e es una unión sintética de los tipos
de excepción en la lista. Cuando se utiliza el valor de e , su tipo estático es el supertipo menos
común de la unión de tipos. Sin embargo, si e es rethrown dentro del bloque catch , los tipos de
excepción que se lanzan son los tipos en la unión. Por ejemplo:
En lo anterior, IOException y SQLException son excepciones revisadas cuyo supertipo menos común
es Exception . Esto significa que el método de report debe coincidir con el report(Exception) . Sin
embargo, el compilador sabe que el throw puede lanzar solamente una IOException o un
SQLException . Por lo tanto, el method se puede declarar como throws IOException, SQLException
lugar de throws Exception . (Lo que es bueno: vea Pitfall - Lanzar Throwable, Exception, Error o
RuntimeException ).
https://riptutorial.com/es/home 524
Lanzar una excepción
La excepción es lanzada en la tercera línea. Esta declaración se puede dividir en dos partes:
Cuando se lanza la excepción, hace que las declaraciones adjuntas terminen de forma anormal
hasta que se maneje la excepción. Esto se describe en otros ejemplos.
Es una buena práctica crear y lanzar el objeto de excepción en una sola declaración, como se
muestra arriba. También es una buena práctica incluir un mensaje de error significativo en la
excepción para ayudar al programador a comprender la causa del problema. Sin embargo, este
no es necesariamente el mensaje que debe mostrar al usuario final. (Para empezar, Java no tiene
soporte directo para internacionalizar mensajes de excepción).
Encadenamiento de excepciones
Muchas excepciones estándar tienen un constructor con un segundo argumento de cause además
del argumento de message convencional. La cause permite encadenar excepciones. Aquí hay un
ejemplo.
Primero definimos una excepción no verificada que nuestra aplicación va a lanzar cuando
https://riptutorial.com/es/home 525
encuentra un error no recuperable. Tenga en cuenta que hemos incluido un constructor que
acepta un argumento de cause .
El throw dentro del bloque try detecta un problema y lo informa a través de una excepción con un
mensaje simple. Por el contrario, el throw dentro del bloque catch está manejando la IOException
envolviéndolo en una nueva excepción (marcada). Sin embargo, no está tirando la excepción
original. Al pasar la IOException como cause , la grabamos para que pueda imprimirse en el
seguimiento de pila, como se explica en Creación y lectura de los registros de pila .
Excepciones personalizadas
En la mayoría de los casos, es más simple desde el punto de vista de diseño de código usar
clases de Exception genéricas existentes al lanzar excepciones. Esto es especialmente cierto si
solo necesita la excepción para llevar un simple mensaje de error. En ese caso, generalmente se
prefiere RuntimeException , ya que no es una excepción marcada. Existen otras clases de
excepción para las clases comunes de errores:
Casos en los que usted desee utilizar una clase de excepción personalizada incluyen los
siguientes:
https://riptutorial.com/es/home 526
• Está escribiendo una API o biblioteca para que otros la utilicen, y quiere permitir que los
usuarios de su API puedan capturar y manejar específicamente las excepciones de su API y
poder diferenciar esas excepciones de otras excepciones más genéricas .
• Está lanzando excepciones para un tipo específico de error en una parte de su programa,
que desea detectar y manejar en otra parte de su programa, y desea poder diferenciar estos
errores de otros errores más genéricos.
Puede crear sus propias excepciones personalizadas extendiendo RuntimeException para una
excepción no verificada, o excepción comprobada extendiendo cualquier Exception que no sea
también subclase de RuntimeException , porque:
https://riptutorial.com/es/home 527
Más:
Java SE 7
¿Qué es un recurso?
Java 7 introdujo la interfaz java.lang.AutoCloseable para permitir que las clases se administren
usando la declaración try-with-resources . Las instancias de clases que implementan
AutoCloseable se conocen como recursos . Por lo general, estos deben eliminarse de manera
oportuna en lugar de confiar en el recolector de basura para eliminarlos.
Un método close() debe disponer del recurso de una manera apropiada. La especificación
establece que debería ser seguro llamar al método en un recurso que ya se ha eliminado.
Además, se recomienda encarecidamente a las clases que implementan el Autocloseable que
declaren el método close() para lanzar una excepción más específica que la Exception , o ninguna
excepción en absoluto.
Una amplia gama de clases e interfaces Java estándar implementan AutoCloseable . Éstos
incluyen:
https://riptutorial.com/es/home 528
stream.println("Hello world!");
}
Los recursos a administrar se declaran como variables en la sección (...) después de la cláusula
try . En el ejemplo anterior, declaramos un stream variable de recurso y lo inicializamos a un
PrintStream recién creado.
Una vez que las variables de recursos se han inicializado, se ejecuta el bloque try . Cuando esto
se complete, se stream.close() automáticamente para garantizar que el recurso no se escape.
Tenga en cuenta que la llamada close() ocurre sin importar cómo se complete el bloque.
Si la inicialización del recurso o el bloque try lanzan la excepción, entonces se ejecutará el bloque
catch . El bloque finally siempre se ejecutará, como con una sentencia convencional try-catch-
finally .
https://riptutorial.com/es/home 529
Esto se comporta como cabría esperar. Ambos is y os se cierran automáticamente al final del
bloque try . Hay un par de puntos a tener en cuenta:
Por lo tanto, en el ejemplo anterior, is inicializa antes del sistema os y se limpia después de él, y
is limpiará si hay una excepción al inicializar el sistema os .
https://riptutorial.com/es/home 530
}
}
}
(El JLS especifica que las variables t y primaryException reales serán invisibles para el código
Java normal).
es equivalente a:
try {
try (PrintStream stream = new PrintStream(fileName)) {
stream.println("Hello world!");
}
} catch (NullPointerException ex) {
System.err.println("Null filename");
} finally {
System.err.println("All done");
}
Cuando se crea un objeto de excepción (es decir, cuando se crea una new ), el constructor
Throwable captura información sobre el contexto en el que se creó la excepción. Más adelante,
esta información se puede generar en forma de stacktrace, que puede usarse para ayudar a
diagnosticar el problema que causó la excepción en primer lugar.
Imprimiendo un stacktrace
Imprimir un stacktrace es simplemente una cuestión de llamar al método printStackTrace() . Por
ejemplo:
try {
int a = 0;
int b = 0;
int c = a / b;
} catch (ArithmeticException ex) {
// This prints the stacktrace to standard output
ex.printStackTrace();
}
https://riptutorial.com/es/home 531
Es decir, el actual System.out . También hay printStackTrace(PrintStream) e
printStackTrace(PrintWriter) que se imprimen en un Stream o Writer específico.
Notas:
1. El stacktrace no incluye los detalles de la excepción en sí. Puedes usar el método toString()
para obtener esos detalles; p.ej
Entendiendo un stacktrace
Considere el siguiente programa simple que consiste en dos clases en dos archivos. (Hemos
mostrado los nombres de archivo y los números de línea agregados con fines ilustrativos).
File: "Main.java"
1 public class Main {
2 public static void main(String[] args) {
3 new Test().foo();
4 }
5 }
File: "Test.java"
1 class Test {
2 public void foo() {
3 bar();
4 }
5
6 public int bar() {
7 int a = 1;
8 int b = 0;
9 return a / b;
10 }
Vamos a leer esta línea a la vez para averiguar lo que nos está diciendo.
La línea # 1 nos dice que el hilo llamado "main" ha terminado debido a una excepción no
detectada. El nombre completo de la excepción es java.lang.ArithmeticException , y el mensaje de
excepción es "/ by zero".
https://riptutorial.com/es/home 532
Si buscamos los javadocs para esta excepción, dice:
De hecho, el mensaje "/ por cero" es un fuerte indicio de que la causa de la excepción es que
algún código ha intentado dividir algo entre cero. ¿Pero que?
Las 3 líneas restantes son la traza de pila. Cada línea representa una llamada de método (o
constructor) en la pila de llamadas, y cada una nos dice tres cosas:
Estas líneas de un seguimiento de pila se enumeran con el marco para la llamada actual en la
parte superior. El cuadro superior en nuestro ejemplo anterior está en el método Test.bar y en la
línea 9 del archivo Test.java. Esa es la siguiente línea:
return a / b;
Si quisiéramos ir más lejos, podemos ver que desde el StackTrace bar() fue llamado desde foo()
en la línea 3 de Test.java, y que foo() a su vez fue llamado desde Main.main() .
Nota: Los nombres de clase y método en los marcos de pila son los nombres internos de las
clases y métodos. Tendrá que reconocer los siguientes casos inusuales:
(En algunas versiones de Java, el código de formato stacktrace detectará y eliminará las
secuencias repetidas de cuadros de pila, como puede ocurrir cuando una aplicación falla debido a
una recursión excesiva).
https://riptutorial.com/es/home 533
File: Test,java
1 public class Test {
2 int foo() {
3 return 0 / 0;
4 }
5
6 public Test() {
7 try {
8 foo();
9 } catch (ArithmeticException ex) {
10 throw new RuntimeException("A bad thing happened", ex);
11 }
12 }
13
14 public static void main(String[] args) {
15 new Test();
16 }
17 }
El "Causado por:" solo se incluye en la salida cuando la cause la excepción principal no es null ).
Las excepciones se pueden encadenar indefinidamente, y en ese caso, el seguimiento de pila
puede tener múltiples trazas de "Causado por:".
Nota: el mecanismo de cause solo se expuso en la API de Throwable en Java 1.4.0. Antes de eso,
era necesario que la aplicación implementara el encadenamiento de excepciones utilizando un
campo de excepción personalizado para representar la causa y un método personalizado de
printStackTrace .
Las bibliotecas Apache Commons y Guava proporcionan métodos de utilidad para capturar un
https://riptutorial.com/es/home 534
stacktrace como una cadena:
org.apache.commons.lang.exception.ExceptionUtils.getStackTrace(Throwable)
com.google.common.base.Throwables.getStackTraceAsString(Throwable)
/**
* Returns the string representation of the stack trace.
*
* @param throwable the throwable
* @return the string.
*/
public static String stackTraceToString(Throwable throwable) {
StringWriter stringWriter = new StringWriter();
throwable.printStackTrace(new PrintWriter(stringWriter));
return stringWriter.toString();
}
Tenga en cuenta que si su intención es analizar el seguimiento de pila, es más sencillo utilizar
getStackTrace() y getCause() que intentar analizar un seguimiento de pila.
Manipulación InterruptedException
Pero esta es exactamente la manera incorrecta de manejar un evento "imposible" que ocurre. Si
sabe que su aplicación nunca encontrará una InterruptedException , debe tratar dicho evento
como una violación grave de las suposiciones de su programa y salir lo más rápido posible.
https://riptutorial.com/es/home 535
Thread.currentThread().interrupt();
throw new AssertionError(e);
}
Esto hace dos cosas; primero restaura el estado de interrupción del hilo (como si la
InterruptedException no se hubiera lanzado en primer lugar), y luego lanza un AssertionError
indica que se han violado los invariantes básicos de su aplicación. Si sabe con certeza que nunca
interrumpirá el hilo en el que se ejecuta este código es seguro, ya que nunca debe catch bloque
catch .
Más a menudo, sin embargo, no puede garantizar que su hilo nunca será interrumpido. En
particular, si está escribiendo un código que será ejecutado por un Executor o algún otro
administrador de subprocesos, es fundamental que su código responda rápidamente a las
interrupciones, de lo contrario su aplicación se atascará o incluso se interrumpirá.
En tales casos, lo mejor es generalmente permitir que la InterruptedException propague por la pila
de llamadas, agregando una throws InterruptedException a cada método. Esto puede parecer un
poco confuso, pero en realidad es una propiedad deseable: las firmas de su método ahora indican
a las personas que llaman que responderá rápidamente a las interrupciones.
// Let the caller determine how to handle the interrupt if you're unsure
public void myLongRunningMethod() throws InterruptedException {
...
}
En casos limitados (p. Ej., Al anular un método que no throw ninguna excepción comprobada),
puede restablecer el estado interrumpido sin generar una excepción, esperando que se ejecute
cualquier código al lado para manejar la interrupción. Esto retrasa el manejo de la interrupción
pero no la suprime por completo.
// Suppresses the exception but resets the interrupted state letting later code
// detect the interrupt and handle it properly.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return ...; // your expectations are still broken at this point - try not to do more work.
}
Todas las excepciones de Java son instancias de clases en la jerarquía de clases de Excepción.
Esto se puede representar de la siguiente manera:
https://riptutorial.com/es/home 536
• java.lang.Throwable : esta es la clase base para todas las clases de excepción. Sus métodos
y constructores implementan una gama de funcionalidades comunes a todas las
excepciones.
○ java.lang.Exception : esta es la superclase de todas las excepciones normales.
○ Diversas clases de excepción estándar y personalizadas.
○ java.lang.RuntimeException - Esta es la superclase de todas las excepciones
normales que son excepciones sin marcar .
○Varias clases de excepción de tiempo de ejecución estándar y
personalizadas.
○ java.lang.Error : esta es la superclase de todas las excepciones de "error fatal".
Notas:
El lenguaje Java aborda esta preocupación con el mecanismo de excepción verificado. Primero,
Java clasifica las excepciones en dos categorías:
• Las excepciones verificadas típicamente representan eventos anticipados con los que una
aplicación debería poder lidiar. Por ejemplo, IOException y sus subtipos representan
condiciones de error que pueden ocurrir en operaciones de E / S. Los ejemplos incluyen, el
archivo se abre porque falla porque no existe un archivo o directorio, la red lee y escribe
fallas porque una conexión de red se ha roto y así sucesivamente.
• Las excepciones no verificadas típicamente representan eventos no anticipados con los que
una aplicación no puede lidiar. Estos suelen ser el resultado de un error en la aplicación.
(En lo siguiente, "lanzado" se refiere a cualquier excepción lanzada explícitamente (por una declaración de throw ), o
implícitamente (en una desreferencia fallida, tipo de conversión y así sucesivamente). De manera similar,
"propagada" se refiere a una excepción que fue lanzada en una llamada anidada, y no atrapada dentro de esa
llamada. El siguiente código de ejemplo lo ilustrará.)
La segunda parte del mecanismo de excepción comprobada es que existen restricciones en los
métodos en los que se puede producir una excepción comprobada:
https://riptutorial.com/es/home 537
• Cuando una excepción marcada es lanzada o propagada en un método, debe ser capturada
por el método o listada en la cláusula de throws del método. (El significado de la cláusula de
throws se describe en este ejemplo ).
• Cuando se lanza o se propaga una excepción marcada en un bloque de inicialización, se
debe capturar el bloque.
• Una excepción comprobada no puede propagarse mediante una llamada de método en una
expresión de inicialización de campo. (No hay manera de atrapar tal excepción.)
Estas restricciones no se aplican a las excepciones sin marcar. Esto incluye todos los casos en
los que se lanza una excepción implícitamente, ya que todos los casos arrojan excepciones no
verificadas.
// INCORRECT
public void methodThrowingCheckedException(boolean flag) {
int i = 1 / 0; // Compiles OK, throws ArithmeticException
if (flag) {
throw new MyException(); // Compilation error
} else {
throw new MyException2(); // Compiles OK
}
}
// CORRECTED
public void methodThrowingCheckedException(boolean flag) throws MyException {
int i = 1 / 0; // Compiles OK, throws ArithmeticException
if (flag) {
throw new MyException(); // Compilation error
} else {
throw new MyException2(); // Compiles OK
}
}
https://riptutorial.com/es/home 538
El segundo ejemplo muestra cómo se puede tratar una excepción comprobada propagada.
// INCORRECT
public void methodWithPropagatedCheckedException() {
InputStream is = new FileInputStream("someFile.txt"); // Compilation error
// FileInputStream throws IOException or a subclass if the file cannot
// be opened. IOException is a checked exception.
...
}
// CORRECTED (Version A)
public void methodWithPropagatedCheckedException() throws IOException {
InputStream is = new FileInputStream("someFile.txt");
...
}
// CORRECTED (Version B)
public void methodWithPropagatedCheckedException() {
try {
InputStream is = new FileInputStream("someFile.txt");
...
} catch (IOException ex) {
System.out.println("Cannot open file: " + ex.getMessage());
}
}
El último ejemplo muestra cómo lidiar con una excepción marcada en un inicializador de campo
estático.
// INCORRECT
public class Test {
private static final InputStream is =
new FileInputStream("someFile.txt"); // Compilation error
}
// CORRECTED
public class Test {
private static final InputStream is;
static {
InputStream tmp = null;
try {
tmp = new FileInputStream("someFile.txt");
} catch (IOException ex) {
System.out.println("Cannot open file: " + ex.getMessage());
}
is = tmp;
}
}
Nótese que en este último caso, también tenemos que hacer frente a los problemas que is no se
pueden asignar a más de una vez, y sin embargo, también tiene que ser asignado a, incluso en el
caso de una excepción.
Introducción
Las excepciones son errores que ocurren cuando un programa se está ejecutando. Considere el
https://riptutorial.com/es/home 539
siguiente programa Java que divide dos enteros.
class Division {
public static void main(String[] args) {
int a, b, result;
a = input.nextInt();
b = input.nextInt();
result = a / b;
La división por cero es una operación no válida que produciría un valor que no se puede
representar como un entero. Java se ocupa de esto lanzando una excepción . En este caso, la
excepción es una instancia de la clase ArithmeticException .
Nota: el ejemplo sobre la creación y lectura de seguimientos de pila explica qué significa la salida
después de los dos números.
La utilidad de una excepción es el control de flujo que permite. Sin usar excepciones, una
solución típica a este problema puede ser verificar primero si b == 0 :
class Division {
public static void main(String[] args) {
int a, b, result;
a = input.nextInt();
b = input.nextInt();
if (b == 0) {
System.out.println("You cannot divide by zero.");
return;
}
result = a / b;
https://riptutorial.com/es/home 540
}
}
Esto imprime el mensaje You cannot divide by zero. a la consola y abandona el programa de una
manera elegante cuando el usuario intenta dividir por cero. Una forma equivalente de resolver
este problema mediante el manejo de excepciones sería reemplazar el control if flow con un
bloque try-catch :
...
a = input.nextInt();
b = input.nextInt();
try {
result = a / b;
}
catch (ArithmeticException e) {
System.out.println("An ArithmeticException occurred. Perhaps you tried to divide by
zero.");
return;
}
...
En general, se considera una buena práctica usar el manejo de excepciones como parte del
control de flujo normal de una aplicación donde el comportamiento sería indefinido o inesperado.
Por ejemplo, en lugar de devolver un null cuando falla un método, generalmente es una mejor
práctica lanzar una excepción para que la aplicación que hace uso del método pueda definir su
propio control de flujo para la situación mediante el manejo de excepciones del tipo ilustrado
anteriormente. En cierto sentido, esto soluciona el problema de tener que devolver un tipo
particular, ya que se pueden lanzar cualquiera de los múltiples tipos de excepciones para indicar
el problema específico que ocurrió.
Para obtener más consejos sobre cómo y cómo no usar excepciones, consulte Desventajas de
Java - Uso de excepciones
https://riptutorial.com/es/home 541
public static int returnTest(int number){
try{
if(number%2 == 0) throw new Exception("Exception thrown");
else return x;
}
catch(Exception e){
return 3;
}
finally{
return 7;
}
}
Este método siempre devolverá 7 ya que el bloque finally asociado con el bloque try / catch se
ejecuta antes de que se devuelva algo. Ahora, como finalmente ha return 7; , este valor
reemplaza los valores de retorno de prueba / captura.
Si el bloque catch devuelve un valor primitivo y ese valor primitivo se cambia posteriormente en el
bloque finally, se devolverá el valor devuelto en el bloque catch y se ignorarán los cambios del
bloque finally.
System.out.println(n);
}
int returnNumber = 0;
try {
if (number % 2 == 0)
throw new Exception("Exception thrown");
else
return returnNumber;
} catch (Exception e) {
return returnNumber;
} finally {
returnNumber = 1;
}
}
}
Este ejemplo cubre algunas características avanzadas y casos de uso para excepciones.
https://riptutorial.com/es/home 542
El uso principal de los stacktraces de excepción es proporcionar información sobre un error de
aplicación y su contexto para que el programador pueda diagnosticar y solucionar el problema. A
veces se puede utilizar para otras cosas. Por ejemplo, una clase de SecurityManager debe
examinar la pila de llamadas para decidir si el código que está realizando una llamada debe ser
confiable.
2. Los javadocs para getStackTrace() establecen que una JVM puede omitir marcos:
La información del marco de pila necesaria para los stacktraces, se captura cuando los
constructores de Throwable llaman al método Throwable.fillInStackTrace() . Este método es public
, lo que significa que una subclase puede anularlo. El truco consiste en anular el método
heredado de Throwable con uno que no hace nada; p.ej
@Override
public void fillInStackTrace() {
// do nothing
}
}
El problema con este enfoque es que una excepción que reemplaza a fillInStackTrace() nunca
https://riptutorial.com/es/home 543
puede capturar el seguimiento de pila, y es inútil en los escenarios en los que necesita uno.
En algunas situaciones, el seguimiento de pila para una excepción creada de manera normal
contiene información incorrecta o información que el desarrollador no quiere revelar al usuario.
Para estos escenarios, Throwable.setStackTrace se puede usar para reemplazar la matriz de
objetos StackTraceElement que contiene la información.
Por ejemplo, se puede usar lo siguiente para descartar la información de la pila de una excepción:
exception.setStackTrace(new StackTraceElement[0]);
Excepciones suprimidas
Java SE 7
Cuando se lanza la excepción, el try llamará a close() en la w lo que vaciará cualquier salida con
búfer y luego cerrará el FileWriter . Pero, ¿qué sucede si se lanza una IOException al vaciar la
salida?
Lo que sucede es que se suprime cualquier excepción que se lance al limpiar un recurso. La
excepción se captura y se agrega a la lista de excepciones suprimidas de la excepción primaria. A
continuación, el try-with-resources continuará con la limpieza de los otros recursos. Finalmente, la
excepción primaria será devuelta.
Se produce un patrón similar si se produce una excepción durante la inicialización del recurso, o
si el bloque try se completa normalmente. La primera excepción lanzada se convierte en la
excepción principal, y las subsiguientes que surgen de la limpieza se suprimen.
Las excepciones suprimidas se pueden recuperar del objeto de excepción principal llamando a
getSuppressedExceptions .
https://riptutorial.com/es/home 544
Intento-finalmente
Aquí hay un ejemplo de la forma más simple ( try...finally ):
try {
doSomething();
} finally {
cleanUp();
}
El código dentro de finally de bloque se ejecutará siempre. (Las únicas excepciones son si
System.exit(int) se llama, o si los pánicos de JVM.) Así pues, un finally de bloque es el código
correcto lugar que siempre necesita ser ejecutada; Por ejemplo, cerrando archivos y otros
recursos o liberando bloqueos.
prueba-captura-finalmente
Nuestro segundo ejemplo muestra cómo catch y finally pueden usarse juntos. También ilustra
que la limpieza de recursos no es sencilla.
https://riptutorial.com/es/home 545
es demasiado complicado de describir aquí. La versión simple es que el código en el bloque
finally siempre será ejecutado.
• Declaramos el "recurso" (es decir, la variable del reader ) antes del bloque try para que esté
dentro del alcance del bloque finally .
• Al colocar el new FileReader(...) , la catch puede manejar cualquier excepción IOError
produce al abrir el archivo.
• Necesitamos un reader.close() en el bloque finally porque hay algunas rutas de excepción
que no podemos interceptar ni en el bloque try ni en el bloque catch .
• Sin embargo, dado que se podría haber lanzado una excepción antes de que se inicializara
el reader , también necesitamos una prueba null explícita.
• Finalmente, la llamada reader.close() podría (hipotéticamente) lanzar una excepción. No
nos importa eso, pero si no detectamos la excepción en la fuente, tendremos que lidiar con
eso más arriba en la pila de llamadas.
Java SE 7
Java 7 y versiones posteriores ofrecen una sintaxis alternativa de prueba con recursos que
simplifica significativamente la limpieza de recursos.
La throws OddNumberException declara que una llamada a checkEven podría lanzar una excepción de
tipo OddNumberException .
Una cláusula de throws puede declarar una lista de tipos y puede incluir excepciones no
comprobadas, así como excepciones comprobadas.
https://riptutorial.com/es/home 546
¿Cuál es el punto de declarar excepciones no marcadas
como lanzadas?
La cláusula de throws en una declaración de método tiene dos propósitos:
1. Le dice al compilador qué excepciones se lanzan para que el compilador pueda reportar las
excepciones sin marcar (marcadas) como errores.
2. Le dice a un programador que está escribiendo un código que llama al método qué
excepciones esperar. Para este propósito, a menudo hace que los sentidos incluyan
excepciones no verificadas en una lista de throws .
@Override
public void checkEven(int number) throws NullPointerException // OK—NullPointerException is an
unchecked exception
...
@Override
public void checkEven(Double number) throws OddNumberException // OK—identical to the
superclass
...
@Override
public void checkEven(int number) throws PrimeNumberException, NonEvenNumberException //
OK—these are both subclasses
@Override
public void checkEven(Double number) throws IOExcepion // ERROR
La razón de esta regla es que si un método anulado puede lanzar una excepción marcada que el
método anulado no podría lanzar, eso interrumpiría la sustituibilidad del tipo.
https://riptutorial.com/es/home 547
Capítulo 78: Expresiones
Introducción
Las expresiones en Java son la construcción primaria para hacer cálculos.
Observaciones
Para obtener una referencia sobre los operadores que se pueden usar en expresiones, consulte
Operadores .
Examples
Precedencia del operador
Cuando una expresión contiene múltiples operadores, potencialmente puede leerse de diferentes
maneras. Por ejemplo, la expresión matemática 1 + 2 x 3 se puede leer de dos maneras:
Java tiene las mismas reglas claras sobre cómo leer una expresión, en función de la precedencia
de los operadores que se utilizan.
Por ejemplo:
1 + 2 * 3
https://riptutorial.com/es/home 548
Operadores / constructos
Descripción Precedencia Asociatividad
(primarios)
Índice
Paréntesis
nombre . nombre
Creación de
( expr )
instancias
new
Acceso al campo De izquierda a
primaria . nombre 15
Acceso a la matriz derecha
primaria [ expr ]
Invocación de
primaria ( expr, ... )
método
primario :: nombre
Referencia del
método
-
Pre incremento ++ expr, -- expr, De derecha a
Unario + Expr, - expr, ~ expr, ! expr 13 izquierda
Reparto 1 ( tipo ) expr De derecha a
izquierda
De izquierda a
Multiplicativa * /% 12
derecha
De izquierda a
Aditivo +- 11
derecha
De izquierda a
Cambio << >> >>> 10
derecha
De izquierda a
Relacional <> <=> = instanceof 9
derecha
De izquierda a
Igualdad ==! = 8
derecha
De izquierda a
Y a nivel de bit Y 7
derecha
De izquierda a
Bitwise inclusive O | 5
derecha
De izquierda a
Y lógico && 4
derecha
O lógico || 3 De izquierda a
https://riptutorial.com/es/home 549
Operadores / constructos
Descripción Precedencia Asociatividad
(primarios)
derecha
De derecha a
Condicional 1 ?: 2
izquierda
= * = / =% = + = - = << = >> =
Asignación De derecha a
>>> = & = ^ = | = 1
Lambda 1 izquierda
->
Expresiones constantes
Una expresión constante es una expresión que produce un tipo primitivo o una cadena, y cuyo
valor puede evaluarse en tiempo de compilación a un literal. La expresión debe evaluar sin lanzar
una excepción, y debe estar compuesta de solo lo siguiente:
• Los siguientes operadores binarios: * , / , % , + , - , << , >> , >>> , < , <= , > , >= , == != , & , ^ , | ,
&& y || .
• Nombres simples que se refieren a variables constantes. (Una variable constante es una
variable declarada como final donde la expresión inicializadora es en sí misma una
expresión constante).
Tenga en cuenta que la lista anterior excluye ++ y -- , los operadores de asignación, class y
instanceof , llamadas de método y referencias a variables generales o campos.
Las expresiones constantes de tipo String resultar en una "internados" String , y operaciones de
punto flotante en expresiones constantes se evalúan con la semántica FP-estrictas.
https://riptutorial.com/es/home 550
Las expresiones constantes se pueden usar (casi) en cualquier lugar donde se pueda usar una
expresión normal. Sin embargo, tienen un significado especial en los siguientes contextos.
Las expresiones constantes son necesarias para las etiquetas de casos en las declaraciones de
cambio. Por ejemplo:
switch (someValue) {
case 1 + 1: // OK
case Math.min(2, 3): // Error - not a constant expression
doSomething();
}
Cuando se usa una expresión constante como condición en un do , while o for , entonces afecta el
análisis de legibilidad. Por ejemplo:
while (false) {
doSomething(); // Error - statenent not reachable
}
boolean flag = false;
while (flag) {
doSomething(); // OK
}
(Tenga en cuenta que esto no se aplica a las sentencias if . El compilador de Java permite que
se pueda acceder al bloque then o else de una sentencia if . Este es el análogo de Java de la
compilación condicional en C y C ++).
Finalmente, static final campos static final en una clase o interfaz con inicializadores de
expresiones constantes se inicializan con entusiasmo. Por lo tanto, se garantiza que estas
constantes se observarán en el estado inicializado, incluso cuando hay un ciclo en el gráfico de
dependencia de inicialización de clase.
https://riptutorial.com/es/home 551
• Las listas de argumentos se evalúan de izquierda a derecha.
Ejemplo simple
En el siguiente ejemplo:
Tenga en cuenta que si los efectos de las llamadas son observables, podrá observar que la
llamada a method1 ocurre antes de la llamada a method2 .
int i = 1;
intArray[i] = ++i + 1;
Tenga en cuenta que dado que el operando de la izquierda de = se evalúa primero, no está
influenciado por el efecto secundario de la subexpresión ++i .
Referencia:
Las expresiones en Java son la construcción primaria para hacer cálculos. Aquí hay unos
ejemplos:
https://riptutorial.com/es/home 552
(i + j) / k // An expression with multiple operations
(flag) ? c : d // An expression using the "conditional" operator
(String) s // A type-cast is an expression
obj.test() // A method call is an expression
new Object() // Creation of an object is an expression
new int[] // Creation of an object is an expression
Los detalles de las diferentes formas de expresiones se pueden encontrar en otros temas.
El tipo de expresión
En la mayoría de los casos, una expresión tiene un tipo estático que se puede determinar en
tiempo de compilación mediante el examen y sus subexpresiones. Estos se conocen como
expresiones independientes .
Sin embargo, (en Java 8 y posteriores) los siguientes tipos de expresiones pueden ser
expresiones poli :
https://riptutorial.com/es/home 553
• Expresiones de creación de instancia de clase
• Expresiones de invocación de métodos
• Expresiones de referencia del método
• Expresiones condicionales
• Expresiones lambda
Cuando una expresión es una expresión poli, su tipo puede verse influido por el tipo de destino de
la expresión; Es decir, para qué se está utilizando.
Declaraciones de Expresión
A diferencia de muchos otros lenguajes, Java generalmente no permite que las expresiones se
usen como declaraciones. Por ejemplo:
Dado que el resultado de evaluar una expresión como no se puede usar, y como no puede afectar
la ejecución del programa de ninguna otra manera, los diseñadores de Java tomaron la posición
de que tal uso es un error o está equivocado.
Sin embargo, esto no se aplica a todas las expresiones. Un subconjunto de expresiones son (de
hecho) legales como declaraciones. El conjunto comprende:
https://riptutorial.com/es/home 554
Capítulo 79: Expresiones lambda
Introducción
Las expresiones Lambda proporcionan una forma clara y concisa de implementar una interfaz de
un solo método utilizando una expresión. Le permiten reducir la cantidad de código que tiene que
crear y mantener. Aunque son similares a las clases anónimas, no tienen información de tipo por
sí mismas. La inferencia de tipos debe suceder.
Sintaxis
• () -> {return expresión; } // Zero-arity con el cuerpo de la función para devolver un valor.
• () -> expresión // taquigrafía para la declaración anterior; No hay punto y coma para las
expresiones.
• () -> {function-body} // Efecto lateral en la expresión lambda para realizar operaciones.
• parámetroName -> expresión // expresión lambda de una aridad. En las expresiones lambda
con un solo argumento, se puede eliminar el paréntesis.
• (Escriba ParameterName, Escriba secondParameterName, ...) -> expresión // lambda
evaluando una expresión con los parámetros listados a la izquierda
• (nombre de parámetro, segundo Nombre de parámetro, ...) -> expresión // Taquigrafía que
elimina los tipos de parámetros para los nombres de parámetros. Solo se puede usar en
contextos que pueden ser deducidos por el compilador donde el tamaño de lista de
parámetros dado coincide con uno (y solo uno) del tamaño de las interfaces funcionales
esperadas.
Examples
Usando expresiones Lambda para ordenar una colección
Listas de clasificación
Antes de Java 8, era necesario implementar la interfaz java.util.Comparator con una clase
anónima (o nombrada) al ordenar una lista 1 :
Java SE 1.2
https://riptutorial.com/es/home 555
return p1.getFirstName().compareTo(p2.getFirstName());
}
}
);
A partir de Java 8, la clase anónima se puede reemplazar con una expresión lambda. Tenga en
cuenta que los tipos para los parámetros p1 y p2 se pueden omitir, ya que el compilador los
deducirá automáticamente:
Collections.sort(
people,
(p1, p2) -> p1.getFirstName().compareTo(p2.getFirstName())
);
Collections.sort(
people,
Comparator.comparing(Person::getFirstName)
);
Una importación estática nos permite expresar esto de manera más concisa, pero es discutible si
esto mejora la legibilidad general:
Los comparadores construidos de esta manera también se pueden encadenar juntos. Por
ejemplo, después de comparar personas por su primer nombre, si hay personas con el mismo
nombre, el método thenComparing también se compara por apellido:
sort(people, comparing(Person::getFirstName).thenComparing(Person::getLastName));
1: tenga en cuenta que Collections.sort (...) solo funciona en colecciones que son subtipos de List . Las API de Set y
Collection no implican ningún orden de los elementos.
Clasificando mapas
Puede ordenar las entradas de un HashMap por valor de una manera similar. (Tenga en cuenta que
debe utilizarse un LinkedHashMap como destino. Las claves en un HashMap normal no están
ordenadas).
Map<String, Integer> map = new HashMap(); // ... or any other Map class
// populate the map
map = map.entrySet()
https://riptutorial.com/es/home 556
.stream()
.sorted(Map.Entry.<String, Integer>comparingByValue())
.collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue(),
(k, v) -> k, LinkedHashMap::new));
Interfaces funcionales
Lambdas solo puede operar en una interfaz funcional, que es una interfaz con solo un método
abstracto. Las interfaces funcionales pueden tener cualquier número de métodos default o static
. (Por esta razón, a veces se les conoce como interfaces de método abstracto único o interfaces
SAM).
interface Foo1 {
void bar();
}
interface Foo2 {
int bar(boolean baz);
}
interface Foo3 {
String bar(Object baz, int mink);
}
interface Foo4 {
default String bar() { // default so not counted
return "baz";
}
void quux();
}
@FunctionalInterface
interface Foo5 {
void bar();
}
@FunctionalInterface
interface BlankFoo1 extends Foo3 { // inherits abstract method from Foo3
}
@FunctionalInterface
interface Foo6 {
void bar();
boolean equals(Object obj); // overrides one of Object's method so not counted
}
https://riptutorial.com/es/home 557
A la inversa, esta no es una interfaz funcional, ya que tiene más de un método abstracto :
interface BadFoo {
void bar();
void quux(); // <-- Second method prevents lambda: which one should
// be considered as lambda?
}
interface BlankFoo2 { }
Entonces, Child no puede ser una interfaz funcional ya que tiene dos métodos especificados.
Expresiones lambda
La estructura básica de una expresión Lambda es:
fi entonces tendrá una instancia de singleton de una clase, similar a una clase anónima, que
implementa FunctionalInterface y donde la definición de un método es {
System.out.println("Hello"); } . En otras palabras, lo anterior es mayormente equivalente a:
https://riptutorial.com/es/home 558
La lambda solo es "mayormente equivalente" a la clase anónima porque en lambda, el significado
de expresiones como this , super o toString() referencia a la clase dentro de la cual se realiza la
asignación, no al objeto recién creado.
No puede especificar el nombre del método cuando usa un lambda, pero no debería necesitarlo,
ya que una interfaz funcional solo debe tener un método abstracto, por lo que Java anula ese
método.
En los casos en que el tipo de la lambda no es seguro, (por ejemplo, los métodos sobrecargados)
puede agregar una conversión a la lambda para decirle al compilador cuál debería ser su tipo, así:
Si el método único de la interfaz funcional toma parámetros, los nombres formales locales de
estos deberían aparecer entre los paréntesis de la lambda. No es necesario declarar el tipo de
parámetro o retorno, ya que estos se toman de la interfaz (aunque no es un error declarar los
tipos de parámetros si lo desea). Por lo tanto, estos dos ejemplos son equivalentes:
Los paréntesis alrededor del argumento se pueden omitir si la función solo tiene un argumento:
Devoluciones implícitas
Si el código colocado dentro de un lambda es una expresión de Java en lugar de una declaración
, se trata como un método que devuelve el valor de la expresión. Por lo tanto, los siguientes dos
son equivalentes:
https://riptutorial.com/es/home 559
tratadas como final y no modificadas dentro de la lambda.
Si es necesario envolver una variable cambiante de esta manera, se debe usar un objeto normal
que mantenga una copia de la variable. Lea más en Java Closures con expresiones lambda.
Aceptando Lambdas
Debido a que una lambda es una implementación de una interfaz, no se necesita hacer nada
especial para que un método acepte una lambda: cualquier función que tome una interfaz
funcional también puede aceptar una lambda.
Hasta que se realice una asignación de este tipo a un tipo funcional, la lambda no tiene un tipo
definido. Para ilustrar, considere la expresión lambda o -> o.isEmpty() . La misma expresión
lambda se puede asignar a muchos tipos funcionales diferentes:
https://riptutorial.com/es/home 560
Ahora que están asignados, los ejemplos que se muestran son de tipos completamente
diferentes, aunque las expresiones lambda tienen el mismo aspecto y no pueden asignarse entre
sí.
Las referencias de método permiten que los métodos estáticos o de instancia predefinidos que se
adhieran a una interfaz funcional compatible se pasen como argumentos en lugar de una
expresión lambda anónima.
class Person {
private final String name;
private final String surname;
people.stream().map(Person::getName)
La lambda equivalente:
En este ejemplo, se está pasando una referencia de método al método de instancia getName() de
tipo Person . Como se sabe que es del tipo de colección, se invocará el método en la instancia
(conocido más adelante).
people.forEach(System.out::println);
Dado que System.out es una instancia de PrintStream , una referencia de método a esta instancia
https://riptutorial.com/es/home 561
específica se pasa como un argumento.
La lambda equivalente:
Este ejemplo pasa una referencia al método static valueOf() en el tipo String . Por lo tanto, el
objeto de instancia en la colección se pasa como un argumento a valueOf() .
La lambda equivalente:
Referencia a un constructor
Lea Recopilar elementos de un flujo en una colección para ver cómo recopilar elementos para
recopilar.
El constructor de argumento de cadena única del tipo Integer se está utilizando aquí, para
construir un entero dado la cadena proporcionada como el argumento. En este caso, siempre que
la cadena represente un número, el flujo se asignará a enteros. La lambda equivalente:
Hoja de trucos
https://riptutorial.com/es/home 562
Formato de referencia del
Código Equivalente lambda
método
* instancepuede ser cualquier expresión que evalúe una referencia a una instancia, por ejemplo,
getInstance()::method , this::method
**Si TypeName es una clase interna no estática, la referencia del constructor solo es válida dentro
del alcance de una instancia de clase externa
A veces es posible que desee tener una expresión lambda implementando más de una interfaz.
Esto es principalmente útil con interfaces de marcadores (como java.io.Serializable ) ya que no
agregan métodos abstractos.
Por ejemplo, desea crear un TreeSet con un Comparator personalizado y luego serializarlo y
enviarlo a través de la red. El enfoque trivial:
Si usa con frecuencia tipos de intersección (por ejemplo, si usa un marco como Apache Spark,
donde casi todo tiene que ser serializable), puede crear interfaces vacías y usarlas en su código:
Hay varios buenos ejemplos del uso de lambdas como FunctionalInterface en escenarios simples.
https://riptutorial.com/es/home 563
Un caso de uso bastante común que puede ser mejorado por las lambdas es lo que se denomina
patrón de ejecución. En este patrón, tiene un conjunto de código de configuración / desmontaje
estándar que se necesita para múltiples escenarios que rodean el código específico de caso de
uso. Algunos ejemplos comunes de esto son los archivos io, database io, try / catch blocks.
interface DataProcessor {
void process( Connection connection ) throws SQLException;;
}
Luego, para llamar a este método con un lambda, podría verse así:
Lambdas está diseñado para proporcionar código de implementación en línea para interfaces de
un solo método y la capacidad de pasarlas como lo hemos estado haciendo con las variables
normales. Los llamamos interfaz funcional.
Por ejemplo, escribir un Runnable en una clase anónima y comenzar un Thread se ve así:
//Old way
new Thread(
new Runnable(){
public void run(){
System.out.println("run logic...");
}
}
).start();
Ahora, en línea con lo anterior, digamos que tiene alguna interfaz personalizada:
interface TwoArgInterface {
int operate(int a, int b);
}
https://riptutorial.com/es/home 564
¿Cómo utiliza lambda para implementar esta interfaz en su código? Igual que el ejemplo de
Runnable que se muestra arriba. Vea el programa del conductor a continuación:
}
}
void threeTimes(IntConsumer r) {
for (int i = 0; i < 3; i++) {
r.accept(i);
}
}
void demo() {
threeTimes(i -> {
System.out.println(i);
return; // Return from lambda to threeTimes only!
});
}
void demo2() {
for (int i = 0; i < 3; i++) {
System.out.println(i);
return; // Return from 'demo2' entirely
}
}
En Scala y Kotlin, demo y demo2 solo imprimirían 0 . Pero esto no es más consistente. El enfoque de
Java es consistente con la refactorización y el uso de clases: el return en el código en la parte
superior y el siguiente código se comporta de la misma manera:
void demo3() {
https://riptutorial.com/es/home 565
threeTimes(new MyIntConsumer());
}
Por lo tanto, el Java return es más coherente con los métodos de clase y refactorización, pero
menos con el for y while las órdenes internas, éstas siguen siendo especial.
IntStream.range(1, 4)
.map(x -> x * x)
.forEach(System.out::println);
IntStream.range(1, 4)
.map(x -> { return x * x; })
.forEach(System.out::println);
void executeAround(Consumer<Resource> f) {
try (Resource r = new Resource()) {
System.out.print("before ");
f.accept(r);
System.out.print("after ");
}
}
void demo4() {
executeAround(r -> {
System.out.print("accept() ");
return; // Does not return from demo4, but frees the resource.
});
}
se imprimirá before accept() after close() . En la semántica de Scala y Kotlin, el intento con
recursos no se cerraría, pero se imprimiría before accept() solamente.
Un cierre lambda se crea cuando una expresión lambda hace referencia a las variables de un
ámbito de distribución (global o local). Las reglas para hacer esto son las mismas que para los
métodos en línea y las clases anónimas.
Las variables locales de un ámbito que se usan dentro de un lambda tienen que ser final . Con
Java 8 (la versión más antigua que admite lambdas), no necesitan ser declarados final en el
https://riptutorial.com/es/home 566
contexto externo, sino que deben ser tratados de esa manera. Por ejemplo:
Esto es legal siempre que no se cambie el valor de la variable n . Si intenta cambiar la variable,
dentro o fuera de la lambda, obtendrá el siguiente error de compilación:
"las variables locales referenciadas desde una expresión lambda deben ser finales o
efectivamente finales ".
Por ejemplo:
int n = 0;
Runnable r = () -> { // Using lambda
int i = n;
// do something
};
n++; // Will generate an error.
Si es necesario usar una variable cambiante dentro de un lambda, el enfoque normal es declarar
una copia final de la variable y usar la copia. Por ejemplo
int n = 0;
final int k = n; // With Java 8 there is no need to explicit final
Runnable r = () -> { // Using lambda
int i = k;
// do something
};
n++; // Now will not generate an error
r.run(); // Will run with i = 0 because k was 0 when the lambda was created
Tenga en cuenta que Java no admite cierres verdaderos. Un lambda de Java no se puede crear
de manera que le permita ver los cambios en el entorno en el que se creó la instancia. Si desea
implementar un cierre que observe o realice cambios en su entorno, debe simularlo utilizando una
clase regular. Por ejemplo:
https://riptutorial.com/es/home 567
// Compiles, but is incorrect ...
public class AccumulatorGenerator {
private int value = 0;
El problema es que esto rompe el contrato de diseño para la interfaz IntUnaryOperator que
establece que las instancias deben ser funcionales y sin estado. Si dicho cierre se pasa a
funciones integradas que aceptan objetos funcionales, es probable que cause bloqueos o
comportamientos erróneos. Los cierres que encapsulan el estado mutable deben implementarse
como clases regulares. Por ejemplo.
// Correct ...
public class Accumulator {
private int value = 0;
Antes de Java 8, es muy común que se use una clase anónima para manejar el evento de clic de
un JButton, como se muestra en el siguiente código. Este ejemplo muestra cómo implementar
una escucha anónima dentro del alcance de btn.addActionListener .
Oyente lambda
Debido a que la interfaz ActionListener define solo un método actionPerformed() , es una interfaz
funcional que significa que hay un lugar para usar expresiones Lambda para reemplazar el código
repetitivo. El ejemplo anterior se puede reescribir usando expresiones Lambda de la siguiente
manera:
https://riptutorial.com/es/home 568
Estilo tradicional al estilo Lambda.
Forma tradicional
interface MathOperation{
boolean unaryOperation(int num);
}
System.out.println(isEven.unaryOperation(25));
System.out.println(isEven.unaryOperation(20));
}
}
Estilo lambda
System.out.println(isEven.unaryOperation(25));
System.out.println(isEven.unaryOperation(20));
}
}
https://riptutorial.com/es/home 569
Lambdas y utilización de memoria.
Como los lambdas de Java son cierres, pueden "capturar" los valores de las variables en el
ámbito léxico adjunto. Si bien no todos los lambdas capturan nada, los lambdas simples como s -
> s.length() no capturan nada y se llaman sin estado , la captura de los lambdas requiere un
objeto temporal para contener las variables capturadas. En este fragmento de código, la lambda
() -> j es una lambda de captura, y puede hacer que se asigne un objeto cuando se evalúa:
Aunque podría no ser inmediatamente obvio, ya que la new palabra clave no aparece en ningún
lugar del fragmento de código, este código puede crear 1,000,000,000 objetos separados para
representar las instancias de la expresión () -> j lambda. Sin embargo, también se debe tener en
cuenta que las versiones futuras de Java 1 pueden ser capaces de optimizar esto para que en el
tiempo de ejecución las instancias de lambda se reutilizaran o se representaran de alguna otra
manera.
1 - Por ejemplo, Java 9 introduce una fase de "enlace" opcional a la secuencia de compilación de Java que brindará
la oportunidad de realizar optimizaciones globales como esta.
Ejemplo: Use una expresión lambda y un predicado para obtener un determinado valor de una
lista. En este ejemplo, todas las personas se imprimirán con el hecho si tienen 18 años o más o
no.
Clase de persona:
https://riptutorial.com/es/home 570
funcional con un método de boolean test(T t) .
Ejemplo de uso:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
The print(personList, p -> p.getAge() >= 18); el método toma una expresión lambda (porque el
Predicado se usa como un parámetro) donde puede definir la expresión que se necesita. El
método de prueba del verificador comprueba si esta expresión es correcta o no:
checker.test(person) .
Puede cambiar esto fácilmente a otra cosa, por ejemplo, para print(personList, p ->
p.getName().startsWith("J")); . Esto verificará si el nombre de la persona comienza con una "J".
https://riptutorial.com/es/home 571
Capítulo 80: Expresiones regulares
Introducción
Una expresión regular es una secuencia especial de caracteres que ayuda a hacer coincidir o
encontrar otras cadenas o conjuntos de cadenas, utilizando una sintaxis especializada contenida
en un patrón. Java tiene soporte para el uso de expresiones regulares a través del paquete
java.util.regex . Este tema es presentar y ayudar a los desarrolladores a comprender más con
ejemplos sobre cómo se deben usar las expresiones regulares en Java.
Sintaxis
• Pattern patternName = Pattern.compile (regex);
• Matcher MatcherName = patternName.matcher (textToSearch);
• matcherName.matches () // Devuelve true si el textToSearch coincide exactamente con la
expresión regular
• matcherName.find () // Busca en textToSearch la primera instancia de una subcadena que
coincida con la expresión regular. Las llamadas subsiguientes buscarán el resto de la
cadena.
• matcherName.group (groupNum) // Devuelve la subcadena dentro de un grupo de captura
• matcherName.group (groupName) // Devuelve la subcadena dentro de un grupo de captura
con nombre (Java 7+)
Observaciones
Importaciones
Deberá agregar las siguientes importaciones antes de poder usar Regex:
import java.util.regex.Matcher
import java.util.regex.Pattern
Escollos
En java, una barra diagonal inversa se escapa con una barra diagonal inversa doble, por lo que
una barra diagonal inversa en la cadena de expresiones regulares debe ingresarse como una
barra diagonal inversa doble. Si necesita escapar de una barra diagonal inversa doble (para hacer
coincidir una barra diagonal inversa única con la expresión regular, debe ingresarla como una
barra diagonal inversa cuádruple).
https://riptutorial.com/es/home 572
Símbolos importantes explicados
Personaje Descripción
Otras lecturas
El tema de expresiones regulares contiene más información sobre expresiones regulares.
Examples
Utilizando grupos de captura
Si necesita extraer una parte de la cadena de la cadena de entrada, podemos usar grupos de
captura de expresiones regulares.
Para este ejemplo, comenzaremos con una expresión regular de número de teléfono simple:
\d{3}-\d{3}-\d{4}
(\d{3})-(\d{3})-(\d{4})
^-----^ ^-----^ ^-----^
Group 1 Group 2 Group 3
Antes de que podamos usarlo en Java, no debemos olvidar seguir las reglas de las Cadenas,
escapando de las barras invertidas, resultando en el siguiente patrón:
"(\\d{3})-(\\d{3})-(\\d{4})"
Primero necesitamos compilar el patrón de expresiones regulares para hacer un Pattern y luego
necesitamos un Matcher para hacer coincidir nuestra cadena de entrada con el patrón:
A continuación, el Matcher debe encontrar la primera subsecuencia que coincida con la expresión
https://riptutorial.com/es/home 573
regular:
phoneMatcher.find();
Java SE 7
Java 7 introdujo los grupos de captura nombrados. Los grupos de captura nombrados funcionan
igual que los grupos de captura numerados (pero con un nombre en lugar de un número), aunque
hay cambios leves de sintaxis. El uso de grupos de captura con nombre mejora la legibilidad.
(?<AreaCode>\d{3})-(\d{3})-(\d{4})
^----------------^ ^-----^ ^-----^
AreaCode Group 2 Group 3
Un Pattern se puede compilar con indicadores, si la expresión regular se utiliza como una String
literal, use modificadores en línea:
/* Had the regex not been compiled case insensitively and singlelined,
* it would fail because FOO does not match /foo/ and \n (newline)
* does not match /./.
*/
Personajes de escape
https://riptutorial.com/es/home 574
Generalmente
Para usar caracteres específicos de expresiones regulares ( ?+| Etc.) en su significado literal,
deben escaparse. En expresiones regulares comunes esto se hace mediante una barra invertida \
. Sin embargo, como tiene un significado especial en Java Strings, debes usar una doble barra
invertida \\ .
"\\".matches("\\"); // PatternSyntaxException
"\\".matches("\\\"); // Syntax Error
Esto funciona:
"\\".matches("\\\\"); // true
Si necesita hacer coincidir caracteres que forman parte de la sintaxis de expresiones regulares,
puede marcar todo o parte del patrón como un literal de expresiones regulares.
// wrapping the bracket in \Q and \E allows the pattern to match as you would expect.
"[123".matches("\\Q[\\E123"); // returns true
https://riptutorial.com/es/home 575
Una forma más fácil de hacerlo sin tener que recordar las secuencias de escape \Q y \E es usar
Pattern.quote()
Para hacer coincidir algo que no contiene una cadena dada, uno puede usar lookahead negativo:
Ejemplo:
Salida:
[popcorn] nope!
[unicorn] matched!
Si quieres hacer coincidir una barra invertida en tu expresión regular, tendrás que escapar de ella.
La barra invertida es un carácter de escape en expresiones regulares. Puede usar '\\' para
referirse a una sola barra invertida en una expresión regular.
Sin embargo, la barra invertida también es un carácter de escape en las cadenas literales de
Java. Para hacer una expresión regular a partir de una cadena literal, debes escapar de cada una
de sus barras invertidas. En una cadena, se puede usar el literal '\\\\' para crear una expresión
regular con '\\', que a su vez puede coincidir con '\'.
Por ejemplo, considere cadenas coincidentes como "C: \ dir \ myfile.txt". Una expresión regular
([A-Za-z]):\\(.*) Coincidirá y proporcionará la letra de la unidad como un grupo de captura.
Tenga en cuenta la barra invertida doble.
Para expresar ese patrón en un literal de cadena de Java, cada una de las barras invertidas en la
expresión regular debe escaparse.
https://riptutorial.com/es/home 576
System.out.println( "This path is on drive " + matcher.group( 1 ) + ":.");
// This path is on drive C:.
}
Si desea hacer coincidir dos barras diagonales inversas, se encontrará usando ocho en una
cadena literal, para representar cuatro en la expresión regular, para hacer coincidir dos.
if ( matcher.matches()) {
System.out.println( "This path is on host '" + matcher.group( 1 ) + "'.");
// This path is on host 'myhost'.
}
https://riptutorial.com/es/home 577
Capítulo 81: Fechas y hora (java.time. *)
Examples
Manipulaciones de fecha simple
LocalDate.now()
LocalDate y = LocalDate.now().minusDays(1);
LocalDate t = LocalDate.now().plusDays(1);
Además de los métodos de plus y minus , hay un conjunto de métodos "con" que se pueden usar
para establecer un campo particular en una instancia de LocalDate .
LocalDate.now().withMonth(6);
El ejemplo anterior devuelve una nueva instancia con el mes establecido en junio (esto difiere de
java.util.Date donde setMonth fue indexado a 0 hasta el 5 de junio).
LocalDate ld = LocalDate.now().plusDays(1).plusYears(1);
Fecha y hora
https://riptutorial.com/es/home 578
Fecha y hora con información de zona horaria.
Fecha y hora con información de compensación (es decir, no se tienen en cuenta los cambios de
horario de verano)
Instante
Representa un instante en el tiempo. Puede considerarse como una envoltura alrededor de una
marca de tiempo Unix.
El siguiente ejemplo también tiene una explicación requerida para comprender el ejemplo dentro
de él.
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.TimeZone;
public class SomeMethodsExamples {
https://riptutorial.com/es/home 579
/**
* Has the methods of the class {@link LocalDateTime}
*/
public static void checkLocalDateTime() {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("Local Date time using static now() method ::: >>> "
+ localDateTime);
System.out
.println("Following is a static map in ZoneId class which has mapping of short
timezone names to their Actual timezone names");
System.out.println(ZoneId.SHORT_IDS);
/**
* This has the methods of the class {@link LocalDate}
*/
public static void checkLocalDate() {
LocalDate localDate = LocalDate.now();
System.out.println("Gives date without Time using now() method. >> "
+ localDate);
LocalDate localDate2 = LocalDate.now(ZoneId.of(ZoneId.SHORT_IDS
.get("ECT")));
System.out
.println("now() is overridden to take ZoneID as parametere using this we can get
the same date under different timezones. >> "
+ localDate2);
}
/**
* This has the methods of abstract class {@link Clock}. Clock can be used
* for time which has time with {@link TimeZone}.
*/
public static void checkClock() {
Clock clock = Clock.systemUTC();
// Represents time according to ISO 8601
System.out.println("Time using Clock class : " + clock.instant());
}
/**
* This has the {@link Instant} class methods.
*/
public static void checkInstant() {
Instant instant = Instant.now();
https://riptutorial.com/es/home 580
System.out.println("Instants using now(Clock clock) :: " + ins1);
/**
* This class checks the methods of the {@link Duration} class.
*/
public static void checkDuration() {
// toString() converts the duration to PTnHnMnS format according to ISO
// 8601 standard. If a field is zero its ignored.
System.out.println(Duration.ofDays(2));
}
/**
* Shows Local time without date. It doesn't store or represenet a date and
* time. Instead its a representation of Time like clock on the wall.
*/
public static void checkLocalTime() {
LocalTime localTime = LocalTime.now();
System.out.println("LocalTime :: " + localTime);
}
/**
* A date time with Time zone details in ISO-8601 standards.
*/
public static void checkZonedDateTime() {
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId
.of(ZoneId.SHORT_IDS.get("CST")));
System.out.println(zonedDateTime);
}
}
Antes de Java 8, existían las clases DateFormat y SimpleDateFormat en el paquete java.text y este
código heredado se seguirá utilizando durante algún tiempo.
https://riptutorial.com/es/home 581
Pero, Java 8 ofrece un enfoque moderno para manejar el formateo y el análisis.
import java.time.*;
import java.time.format.*;
class DateTimeFormat
{
public static void main(String[] args) {
//Parsing
String pattern = "d-MM-yyyy HH:mm";
DateTimeFormatter dtF1 = DateTimeFormatter.ofPattern(pattern);
//Formatting
DateTimeFormatter dtF2 = DateTimeFormatter.ofPattern("EEE d, MMMM, yyyy HH:mm");
System.out.println(ldtf1.format(dtF2) +"\n"+ldtf1.format(dtF3));
}
}
Un aviso importante, en lugar de usar patrones personalizados, es una buena práctica usar
formateadores predefinidos. Su código se ve más claro y el uso de ISO8061 definitivamente lo
ayudará a largo plazo.
ahora, ya que el método between el enumerador ChronoUnit toma 2 Temporal s como parámetros
para que pueda pasar sin problemas las instancias de LocalDate
https://riptutorial.com/es/home 582
Capítulo 82: FileUpload a AWS
Introducción
Cargue el archivo a AWS s3 bucket utilizando la API spring rest.
Examples
Subir archivo a s3 bucket
Requisito : - secreta la clave y la clave de acceso para el cubo s3 donde desea cargar su
archivo.
código: - DocumentController.java
@RestController
@RequestMapping("/api/v2")
public class DocumentController {
System.out.println("*****************************");
https://riptutorial.com/es/home 583
AWSCredentials credentials = new BasicAWSCredentials("AKIA*************",
"zr**********************");
/****************** DocumentController.uploadfile(credentials);
***************************/
return url;
return null;
Función frontal
var settings = {
"async": true,
"crossDomain": true,
"url": "http://url/",
"method": "POST",
https://riptutorial.com/es/home 584
"headers": {
"cache-control": "no-cache"
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
}
$.ajax(settings).done(function (response) {
console.log(response);
});
https://riptutorial.com/es/home 585
Capítulo 83: Formato numérico
Examples
Formato numérico
Los diferentes países tienen diferentes formatos numéricos y, teniendo en cuenta esto, podemos
tener diferentes formatos utilizando Locale of java. Usar locale puede ayudar en el formateo
1. Número de formato
numberFormat.format(10000000.99);
2. Formato de moneda
3. Formato Porcentaje
numberFormat.setMinimumIntegerDigits(int digits)
numberFormat.setMaximumIntegerDigits(int digits)
numberFormat.setMinimumFractionDigits(int digits)
numberFormat.setMaximumFractionDigits(int digits)
https://riptutorial.com/es/home 586
Capítulo 84: FTP (Protocolo de transferencia
de archivos)
Sintaxis
• FTPClient connect (host InetAddress, puerto int)
• Inicio de sesión de FTPClient (nombre de usuario de String, contraseña de String)
• FTPClient desconectar ()
• FTPReply getReplyStrings ()
• boolean storeFile (cadena remota, InputStream local)
• OutputStream storeFileStream (cadena remota)
• boolean setFileType (int fileType)
• boolean completePendingCommand ()
Parámetros
Parámetros Detalles
Examples
Conexión e inicio de sesión en un servidor FTP
Para comenzar a usar FTP con Java, deberá crear un nuevo FTPClient y luego conectarse e
iniciar sesión en el servidor utilizando .connect(String server, int port) y .login(String username,
String password) .
import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
//Import all the required resource for this project.
https://riptutorial.com/es/home 587
String pass = "Password";
Ahora tenemos lo básico hecho. ¿Pero qué pasa si tenemos un error de conexión al servidor?
Queremos saber cuándo algo sale mal y aparece el mensaje de error. Agreguemos algo de
código para detectar errores mientras se conecta.
try {
ftp.connect(server, port);
showServerReply(ftp);
int replyCode = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.printIn("Operation failed. Server reply code: " + replyCode)
return;
}
ftp.login(user, pass);
} catch {
showServerReply(ftp);
Esto toma el código de respuesta / error del servidor y lo almacena como un entero.
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.printIn("Operation failed. Server reply code: " + replyCode)
return;
}
Esto verifica el código de respuesta para ver si hubo un error. Si hubo un error, simplemente
imprimirá "Error en la operación. Código de respuesta del servidor:" seguido del código de error.
También agregamos un bloque try / catch que agregaremos en el siguiente paso. A continuación,
también creamos una función que verifique si ftp.login() errores en ftp.login() .
https://riptutorial.com/es/home 588
Vamos a romper este bloque también.
Esto no solo intentará iniciar sesión en el servidor FTP, sino que también almacenará el resultado
como un valor booleano.
showServerReply(ftp);
Esto comprobará si el servidor nos envió algún mensaje, pero primero tendremos que crear la
función en el siguiente paso.
if (!success) {
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}
import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
https://riptutorial.com/es/home 589
}
}
Ahora, a continuación, vamos a crear el bloque Catch completo en caso de que encontremos
algún error en todo el proceso.
El bloque de captura completado ahora se imprimirá "¡Vaya! Algo salió mal". y el stacktrace si hay
un error. Ahora nuestro último paso es crear el showServerReply() que hemos estado usando por
un tiempo.
Esta función toma un FTPClient como una variable, y lo llama "ftp". Después de eso, almacena
todas las respuestas del servidor desde una matriz de cadenas. A continuación, comprueba si los
mensajes fueron almacenados. Si hay alguno, imprime cada uno de ellos como "SERVIDOR:
[respuesta]". Ahora que hemos terminado esa función, este es el script completo:
import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
https://riptutorial.com/es/home 590
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("Operation failed. Server reply code: " + replyCode);
return;
}
boolean success = ftp.login(user, pass);
showServerReply(ftp);
if (!success) {
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}
} catch (IOException ex) {
System.out.println("Oops! Something went wrong.");
ex.printStackTrace();
}
}
}
Primero debemos crear un nuevo FTPClient e intentar conectarlo al servidor e iniciar sesión
usando .connect(String server, int port) y .login(String username, String password) . Es
importante conectarse e iniciar sesión con un bloque try / catch en caso de que nuestro código no
pueda conectarse con el servidor. También necesitaremos crear una función que verifique y
muestre cualquier mensaje que recibamos del servidor cuando intentemos conectarnos e iniciar
sesión. Llamaremos a esta función " showServerReply(FTPClient ftp) ".
import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
https://riptutorial.com/es/home 591
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}
} catch (IOException ex) {
System.out.println("Oops! Something went wrong.");
ex.printStackTrace();
}
}
}
Después de esto, ahora debería tener su servidor FTP conectado a su script Java.
https://riptutorial.com/es/home 592
Capítulo 85: Generación de números
aleatorios
Observaciones
Nada es realmente aleatorio y, por lo tanto, el javadoc llama a esos números pseudoaleatorios.
Esos números se crean con un generador de números pseudoaleatorios .
Examples
Números pseudoaleatorios
Java proporciona, como parte del paquete utils , un generador básico de números
pseudoaleatorios, denominado apropiadamente Random . Este objeto se puede usar para generar
un valor pseudoaleatorio como cualquiera de los tipos de datos numéricos incorporados ( int ,
float , etc.). También puede usarlo para generar un valor booleano aleatorio, o una matriz
aleatoria de bytes. Un ejemplo de uso es el siguiente:
import java.util.Random;
...
double randDouble = random.nextDouble(); //This returns a value between 0.0 and 1.0
float randFloat = random.nextFloat(); //Same as nextDouble
NOTA: Esta clase solo produce números pseudoaleatorios de baja calidad, y nunca debe usarse
para generar números aleatorios para operaciones criptográficas u otras situaciones en las que la
aleatoriedad de mayor calidad es crítica (para eso, desearía usar la clase SecureRandom , como se
indica a continuación). Una explicación para la distinción entre aleatoriedad "segura" e "insegura"
está fuera del alcance de este ejemplo.
El método nextInt(int bound) de Random acepta un límite exclusivo superior, es decir, un número
que el valor aleatorio devuelto debe ser menor que. Sin embargo, solo el método nextInt acepta
un límite; nextLong , nextDouble etc no lo hacen.
https://riptutorial.com/es/home 593
int number = 10 + random.nextInt(100); // number is in the range of 10 to 109
A partir de Java 1.7, también puede utilizar ThreadLocalRandom ( fuente ). Esta clase proporciona un
PRNG seguro para subprocesos (generador de números pseudoaleatorios). Tenga en cuenta que
el método nextInt de esta clase acepta un límite superior e inferior.
import java.util.concurrent.ThreadLocalRandom;
Tenga en cuenta que la documentación oficial indica que nextInt(int bound) puede hacer cosas
raras cuando el bound está cerca de 2 30 +1 (énfasis agregado):
En otras palabras, especificar un límite disminuirá (levemente) el rendimiento del método nextInt ,
y esta disminución del rendimiento será más pronunciada a medida que el bound aproxime a la
mitad del valor int máximo.
Random y ThreadLocalRandom son lo suficientemente buenos para el uso diario, pero tienen un gran
problema: se basan en un generador lineal congruente , un algoritmo cuya salida se puede
predecir con bastante facilidad. Por lo tanto, estas dos clases no son adecuadas para usos
criptográficos (como la generación de claves).
Uno puede usar java.security.SecureRandom en situaciones donde se requiere un PRNG con una
salida que sea muy difícil de predecir. Predecir los números aleatorios creados por las instancias
de esta clase es lo suficientemente difícil como para etiquetar la clase como criptográficamente
segura .
import java.security.SecureRandom;
import java.util.Arrays;
https://riptutorial.com/es/home 594
Además de ser criptográficamente seguro, SecureRandom tiene un período gigantesco de 2 160 ,
comparado con el período de Random de 2 48 . Sin embargo, tiene un inconveniente de ser
considerablemente más lento que el Random y otros PRNG lineales como Mersenne Twister y
Xorshift .
/**
* returns a array of random numbers with no duplicates
* @param range the range of possible numbers for ex. if 100 then it can be anywhere from 1-
100
* @param length the length of the array of random numbers
* @return array of random numbers with no duplicates.
*/
public static int[] getRandomNumbersWithNoDuplicates(int range, int length){
if (length<range){
// this is where all the random numbers
int[] randomNumbers = new int[length];
newRandSpot++;
// if we have gone though all the spots then set the value
if (newRandSpot==0){
randomNumbers[q] = t;
}
https://riptutorial.com/es/home 595
}
}
}
return randomNumbers;
} else {
// invalid can't have a length larger then the range of possible numbers
}
return null;
}
El método funciona en bucle a través de una matriz que tiene el tamaño de la longitud solicitada y
encuentra la longitud restante de los números posibles. Establece un número aleatorio de esos
posibles números newRandSpot y encuentra ese número dentro del número no tomado que queda.
Lo hace recorriendo el rango y comprobando si ese número ya se ha tomado.
Ahora digamos que el siguiente número elegido entre 1 y 4 es 3. En el primer bucle obtenemos 1
que aún no se ha tomado, por lo que podemos eliminar 1 de 3, lo que hace que sea 2. Ahora, en
el segundo bucle obtenemos 2 que ha sido tomado así que no hacemos nada. Seguimos este
patrón hasta que llegamos a 4, donde una vez que eliminamos 1, se convierte en 0, por lo que
establecemos el nuevo número aleatorio en 4.
Usar la misma semilla para generar números aleatorios devolverá los mismos números cada vez,
por lo que establecer una semilla diferente para cada instancia Random es una buena idea si no
quiere terminar con números duplicados.
Un buen método para obtener un Long que es diferente para cada llamada es
System.currentTimeMillis() :
https://riptutorial.com/es/home 596
sola línea.
Aparte de int, podemos generar aleatorios long , double , float y bytes utilizando esta clase.
https://riptutorial.com/es/home 597
Capítulo 86: Generando Código Java
Examples
Generar POJO desde JSON
• Ingrese el campo de UI como se muestra a continuación (se requiere '' Ruta '' Fuente '、'
Paquete '):
https://riptutorial.com/es/home 598
Capítulo 87: Genéricos
Introducción
Los genéricos son una instalación de programación genérica que extienden el sistema de tipos de
Java para permitir que un tipo o método opere en objetos de varios tipos mientras proporciona
seguridad de tipo de tiempo de compilación. En particular, el marco de colecciones Java es
compatible con los genéricos para especificar el tipo de objetos almacenados en una instancia de
colección.
Sintaxis
• class ArrayList <E> {} // una clase genérica con parámetro de tipo E
• clase HashMap <K, V> {} // una clase genérica con dos parámetros de tipo K y V
• <E> void print (elemento E) {} // un método genérico con el parámetro de tipo E
• ArrayList <String> nombres; // declaración de una clase genérica
• ArrayList <?> Objetos; // declaración de una clase genérica con un parámetro de tipo
desconocido
• nueva ArrayList <String> () // creación de instancias de una clase genérica
• nueva ArrayList <> () // creación de instancias con inferencia de tipo "diamante" (Java 7 o
posterior)
Observaciones
Los genéricos se implementan en Java a través del borrado de tipos, lo que significa que durante
el tiempo de ejecución la información de tipo especificada en la creación de instancias de una
clase genérica no está disponible. Por ejemplo, la declaración List<String> names = new
ArrayList<>(); produce un objeto de lista desde el cual el tipo de elemento String no se puede
recuperar en tiempo de ejecución. Sin embargo, si la lista se almacena en un campo de tipo
List<String> , o se pasa a un parámetro de método / constructor de este mismo tipo, o se
devuelve desde un método de ese tipo de retorno, entonces la información de tipo completo se
puede recuperar en tiempo de ejecución a través de la API de reflexión de Java.
Esto también significa que cuando se realiza la conversión a un tipo genérico (por ejemplo:
(List<String>) list ), la conversión es una conversión sin verificar . Debido a que el parámetro
<String> se borra, la JVM no puede verificar si una conversión de una List<?> una List<String> es
correcta; La JVM solo ve un reparto de List a List en tiempo de ejecución.
Examples
Creando una clase genérica
Los genéricos permiten que las clases, interfaces y métodos tomen otras clases e interfaces
como parámetros de tipo.
https://riptutorial.com/es/home 599
Este ejemplo utiliza la clase genérica Param para tomar un solo tipo de parámetro T , delimitado
por corchetes angulares ( <> ):
public T getValue() {
return value;
}
Para crear una instancia de esta clase, proporcione un argumento de tipo en lugar de T Por
ejemplo, Integer :
El argumento de tipo puede ser cualquier tipo de referencia, incluidas las matrices y otros tipos
genéricos:
Param<String[]> stringArrayParam;
Param<int[][]> int2dArrayParam;
Param<Param<Object>> objectNestedParam;
Java SE 7
public T getValue() {
return value;
}
https://riptutorial.com/es/home 600
this.value = value;
}
}
AbstractParam es una clase abstracta declarada con un parámetro de tipo de T Al extender esta
clase, ese parámetro de tipo puede reemplazarse por un argumento de tipo escrito dentro de <> ,
o el parámetro de tipo puede permanecer sin cambios. En el primer y segundo ejemplo a
continuación, String y Integer reemplazan el parámetro de tipo. En el tercer ejemplo, el parámetro
de tipo permanece sin cambios. El cuarto ejemplo no usa genéricos en absoluto, por lo que es
similar a si la clase tuviera un parámetro Object . El compilador advertirá que AbstractParam es un
tipo sin ObjectParam , pero compilará la clase ObjectParam . El quinto ejemplo tiene 2 parámetros de
tipo (consulte "parámetros de tipo múltiple" a continuación), seleccionando el segundo parámetro
como el parámetro de tipo pasado a la superclase.
El siguiente es el uso:
Observe que en la clase de Email , el método T getValue() actúa como si tuviera una firma de
https://riptutorial.com/es/home 601
String getValue() , y el método void setValue(T) actúa como si fuera declarado void
setValue(String) .
También es posible crear una instancia con una clase interna anónima con llaves vacías ( {} ):
Tenga en cuenta que no se permite usar el diamante con clases internas anónimas.
public T getFirstParam() {
return firstParam;
}
public S getSecondParam() {
return secondParam;
}
https://riptutorial.com/es/home 602
Los métodos también pueden tener parámetros de tipo genérico .
Tenga en cuenta que no tenemos que pasar un argumento de tipo real a un método genérico. El
compilador infiere el argumento de tipo para nosotros, basado en el tipo de destino (por ejemplo,
la variable a la que asignamos el resultado), o en los tipos de los argumentos reales. Por lo
general, inferirá el argumento de tipo más específico que hará que la llamada sea correcta.
A veces, aunque rara vez, puede ser necesario anular esta inferencia de tipo con argumentos de
tipo explícito:
void usage() {
consumeObjects(this.<Object>makeList("Jeff", "Atwood").stream());
}
Es necesario en este ejemplo porque el compilador no puede "mirar hacia adelante" para ver que
el Object se desea para T después de llamar a stream() y, de lo contrario, makeList String función
de los argumentos de la lista de elementos. Tenga en cuenta que el lenguaje Java no admite
omitir la clase u objeto en el que se llama al método ( this en el ejemplo anterior) cuando se
proporcionan explícitamente argumentos de tipo.
El diamante
Java SE 7
Java 7 introdujo el Diamond 1 para eliminar algunas placas de calderas en torno a la creación de
instancias de clase genérica. Con Java 7+ puedes escribir:
https://riptutorial.com/es/home 603
Una limitación es para las clases anónimas , donde aún debe proporcionar el parámetro de tipo
en la creación de instancias:
Java SE 8
Aunque el uso de Diamond con Anonymous Inner Classes no es compatible con Java 7 y 8, se
incluirá como una nueva función en Java 9 .
Nota:
1 - Algunas personas llaman al uso <> el " operador de diamante". Esto es incorrecto. El diamante no se comporta
como un operador, y no se describe ni se enumera en ningún lugar en el JLS o en los Tutoriales de Java (oficiales)
como operador. De hecho, <> ni siquiera es un token de Java distinto. Más bien, es un < token seguido de un > token,
y es legal (aunque mal estilo) tener espacios en blanco o comentarios entre los dos. El JLS y los Tutoriales se
refieren constantemente a <> como "el diamante", y ese es el término correcto para ello.
Ejemplo: queremos ordenar una lista de números, pero Number no implementa Comparable .
En este ejemplo, T debe extender el Number e implementar Comparable<T> que debe ajustarse a
todas las implementaciones de números incorporados "normales" como Integer o BigDecimal pero
no se ajusta a las más exóticas como Striped64 .
Dado que no se permite la herencia múltiple, puede usar como máximo una clase como límite y
debe ser la primera en la lista. Por ejemplo, <T extends Comparable<T> & Number> no está permitido
porque Comparable es una interfaz y no una clase.
https://riptutorial.com/es/home 604
Creando una clase genérica limitada
Puede restringir los tipos válidos utilizados en una clase genérica al delimitar ese tipo en la
definición de clase. Dada la siguiente jerarquía de tipos simple:
Sin genéricos limitados , no podemos crear una clase de contenedor que sea genérica y que
sepa que cada elemento es un animal:
public AnimalContainer() {
col = new ArrayList<T>();
}
public BoundedAnimalContainer() {
col = new ArrayList<T>();
}
https://riptutorial.com/es/home 605
col.add(t);
}
// Legal
AnimalContainer<Cat> a = new AnimalContainer<Cat>();
// Legal
AnimalContainer<String> a = new AnimalContainer<String>();
La sintaxis de los comodines delimitados de los genéricos de Java, que representa el tipo
desconocido por ? es:
• ? super Trepresenta un comodín acotado más bajo. El tipo desconocido representa un tipo
que debe ser un supertipo de T o el mismo tipo de T.
El uso de extends o super es generalmente mejor porque hace que su código sea más flexible
(como en: permite el uso de subtipos y supertipos), como verá a continuación.
class Shoe {}
class IPhone {}
interface Fruit {}
class Apple implements Fruit {}
class Banana implements Fruit {}
class GrannySmith extends Apple {}
https://riptutorial.com/es/home 606
public void eatAll(Collection<? extends Fruit> fruits) {}
(El productor solo tiene acceso de escritura y el consumidor solo tiene acceso de lectura)
El código que utiliza genéricos tiene muchos beneficios sobre el código no genérico. A
continuación se presentan los principales beneficios.
https://riptutorial.com/es/home 607
Controles de tipo más fuertes en tiempo de
compilación
Un compilador de Java aplica una comprobación de tipo segura al código genérico y emite errores
si el código viola la seguridad del tipo. Reparar errores de tiempo de compilación es más fácil que
corregir errores de tiempo de ejecución, que pueden ser difíciles de encontrar.
Eliminación de moldes
El siguiente fragmento de código sin genéricos requiere el lanzamiento:
Los parámetros genéricos también pueden vincularse a más de un tipo utilizando la sintaxis T
extends Type1 & Type2 & ...
Digamos que desea crear una clase cuyo tipo debe implementar tanto Genérico Flushable y
Closeable , se puede escribir
https://riptutorial.com/es/home 608
Ahora, el ExampleClass sólo acepta como parámetros genéricos, tipos que implementan tanto
Flushable y Closeable .
ExampleClass<Console> arg4; // Does NOT work because Console only implements Flushable
ExampleClass<ZipFile> arg5; // Does NOT work because ZipFile only implements Closeable
ExampleClass<Flushable> arg2; // Does NOT work because Closeable bound is not satisfied.
ExampleClass<Closeable> arg3; // Does NOT work because Flushable bound is not satisfied.
Los métodos de clase pueden optar por deducir argumentos de tipo genérico como tampoco
Closeable o Flushable .
/* You can even invoke the methods of any valid type directly. */
public void test2 (T param) {
param.flush(); // Method of Flushable called on T and works fine.
param.close(); // Method of Closeable called on T and works fine too.
}
}
Nota:
No puede enlazar el parámetro genérico a ninguno de los tipos usando la cláusula OR ( | ). Solo
se admite la cláusula AND ( & ). El tipo genérico puede extender solo una clase y muchas
interfaces. La clase debe colocarse al principio de la lista.
El tipo T se borra. Dado que, en el tiempo de ejecución, la JVM no sabe qué era T originalmente,
no sabe a qué constructor llamar.
Soluciones
1. Pasando la clase de T al llamar a genericMethod :
https://riptutorial.com/es/home 609
public <T> void genericMethod(Class<T> cls) {
try {
T t = cls.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
System.err.println("Could not instantiate: " + cls.getName());
}
}
genericMethod(String.class);
Lo que genera excepciones, ya que no hay forma de saber si la clase pasada tiene un
constructor predeterminado accesible.
Java SE 8
genericMethod(String::new);
¿Cómo se utiliza una instancia de un tipo genérico heredado (posiblemente más) dentro de una
declaración de método en el tipo genérico que se está declarando? Este es uno de los problemas
a los que se enfrentará cuando profundice un poco en los genéricos, pero sigue siendo bastante
común.
Supongamos que tenemos un tipo DataSeries<T> (interfaz aquí), que define una serie de datos
genéricos que contienen valores de tipo T Es complicado trabajar con este tipo directamente
cuando queremos realizar muchas operaciones con, por ejemplo, valores dobles, por lo que
definimos DoubleSeries extends DataSeries<Double> . Ahora supongamos que el tipo original
DataSeries<T> tiene un método add(values) que agrega otra serie de la misma longitud y devuelve
una nueva. ¿Cómo DoubleSeries el tipo de values y el tipo de retorno para que sea DoubleSeries
lugar de DataSeries<Double> en nuestra clase derivada?
El problema se puede resolver agregando un parámetro de tipo genérico que se refiera y extienda
el tipo que se está declarando (aplicado aquí a una interfaz, pero lo mismo significa clases):
Aquí T representa el tipo de datos que contiene la serie, por ejemplo, Double y DS la propia serie.
Un tipo (o tipos) heredado ahora se puede implementar fácilmente sustituyendo el parámetro
mencionado anteriormente por un tipo derivado correspondiente, dando así una definición
https://riptutorial.com/es/home 610
concreta de Double base de la forma:
En este momento, incluso un IDE implementará la interfaz anterior con los tipos correctos en su
lugar, que, después de un poco de llenado de contenido, pueden tener este aspecto:
DoubleSeriesImpl(Collection<Double> data) {
this.data = new ArrayList<>(data);
}
@Override
public DoubleSeries add(DoubleSeries values) {
List<Double> incoming = values != null ? values.data() : null;
if (incoming == null || incoming.size() != data.size()) {
throw new IllegalArgumentException("bad series");
}
List<Double> newdata = new ArrayList<>(data.size());
for (int i = 0; i < data.size(); i++) {
newdata.add(this.data.get(i) + incoming.get(i)); // beware autoboxing
}
return DoubleSeries.instance(newdata);
}
@Override
public List<Double> data() {
return Collections.unmodifiableList(data);
}
}
Como puede ver, el método de add se declara como DoubleSeries add(DoubleSeries values) y el
compilador está contento.
Considere el siguiente Example clase genérica declarado con el parámetro formal <T> :
class Example<T> {
public boolean isTypeAString(String s) {
return s instanceof T; // Compilation error, cannot use T as class type here
}
}
Esto siempre dará un error de compilación porque en cuanto el compilador compila la fuente Java
https://riptutorial.com/es/home 611
en el código de bytes de Java , aplica un proceso conocido como borrado de tipo , que convierte
todo el código genérico en código no genérico, lo que hace imposible distinguir entre los tipos T
en tiempo de ejecución. El tipo utilizado con instanceof tiene que ser verificable , lo que significa
que toda la información sobre el tipo debe estar disponible en tiempo de ejecución, y esto no
suele ser el caso para los tipos genéricos.
Dado que los tipos han desaparecido, no es posible que la JVM sepa qué tipo es T
Siempre puede usar un comodín ilimitado (?) Para especificar un tipo en el instanceof siguiente
manera:
Esto puede ser útil para evaluar si una instancia obj es una List o no:
El otro lado de la moneda es que usar una instancia t de T con instanceof es legal, como se
muestra en el siguiente ejemplo:
class Example<T> {
public boolean isTypeAString(T t) {
return t instanceof String; // No compilation error this time
}
}
https://riptutorial.com/es/home 612
return t instanceof String; // No compilation error this time
}
}
Dado que, incluso si el borrado de tipo ocurre de todos modos, ahora la JVM puede distinguir
entre diferentes tipos en la memoria, incluso si usan el mismo tipo de referencia ( Object ), como
muestra el siguiente fragmento de código:
Object obj1 = new String("foo"); // reference type Object, object type String
Object obj2 = new Integer(11); // reference type Object, object type Integer
System.out.println(obj1 instanceof String); // true
System.out.println(obj2 instanceof String); // false, it's an Integer, not a String
Elija un tipo específico para reemplazar el parámetro de tipo formal <T> de MyGenericClass e
implementarlo, como lo hace el siguiente ejemplo:
Esta clase solo trata con String , y esto significa que el uso de MyGenericInterface con diferentes
parámetros (por ejemplo, Integer , Object , etc.) no se compilará, como muestra el siguiente
fragmento de código:
Declare otra interfaz genérica con el parámetro de tipo formal <T> que implementa
MyGenericInterface , de la siguiente manera:
https://riptutorial.com/es/home 613
public void foo(T t) { } // type T is still the same
// other methods...
}
Tenga en cuenta que se puede haber utilizado un parámetro de tipo formal diferente, de la
siguiente manera:
Declare una clase no genérica que implementa MyGenericInteface como un tipo sin
MyGenericInteface (sin usar genérico en absoluto), como sigue:
También se permiten todas las formas enumeradas anteriormente cuando se utiliza una clase
genérica como supertipo en lugar de una interfaz genérica.
Con los genéricos, es posible devolver lo que la persona que llama espera:
El método se compilará con una advertencia. El código es en realidad más seguro de lo que
parece porque el tiempo de ejecución de Java se convertirá en una conversión cuando lo uses:
https://riptutorial.com/es/home 614
List<Bar> bars = foo.get("bars");
Aquí, la conversión funcionará cuando el tipo devuelto sea cualquier tipo de List (es decir,
devolver la List<String> no ClassCastException una ClassCastException ; finalmente la obtendría al
eliminar elementos de la lista).
Para solucionar este problema, puede crear una API que use claves escritas:
Con este enfoque, no puede poner el tipo incorrecto en el mapa, por lo que el resultado siempre
será correcto (a menos que cree accidentalmente dos claves con el mismo nombre pero tipos
diferentes).
Relacionado:
Muchos parámetros genéricos no vinculados, como los que se utilizan en un método estático, no
se pueden recuperar en tiempo de ejecución (consulte Otros subprocesos en Erasure ). Sin
embargo, hay una estrategia común empleada para acceder al tipo que satisface un parámetro
genérico en una clase en tiempo de ejecución. Esto permite un código genérico que depende del
acceso al tipo sin tener que pasar información de tipo a través de cada llamada.
Fondo
La parametrización genérica en una clase se puede inspeccionar creando una clase interna
anónima. Esta clase capturará la información de tipo. En general, este mecanismo se conoce
como tokens de tipo super , que se detallan en la publicación del blog de Neal Gafter .
Implementaciones
Ejemplo de uso
https://riptutorial.com/es/home 615
private final Class<MODEL_TYPE> type = (Class<MODEL_TYPE>) new TypeToken<MODEL_TYPE>
(getClass()){}.getRawType();
public List<MODEL_TYPE> getAll() {
return dataDao.getAllOfType(type);
}
}
https://riptutorial.com/es/home 616
Capítulo 88: Gerente de seguridad
Examples
Habilitando el SecurityManager
Las máquinas virtuales Java (JVM) se pueden ejecutar con un SecurityManager instalado. El
SecurityManager gobierna lo que se permite que haga el código que se ejecuta en la JVM, en
función de factores tales como desde dónde se cargó el código y qué certificados se usaron para
firmar el código.
System.setSecurityManager(new SecurityManager())
El Java SecurityManager estándar otorga permisos sobre la base de una Política, que se define
en un archivo de políticas. Si no se especifica ningún archivo de políticas, se utilizará el archivo
de políticas predeterminado en $JAVA_HOME/lib/security/java.policy .
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classDef = provider.getClass(name);
Class<?> clazz = defineClass(name, classDef, 0, classDef.length, pd);
return clazz;
}
}
https://riptutorial.com/es/home 617
PluginClassLoader primero consultará el sistema y el cargador de clases principal para las
definiciones de clase.
public PluginSecurityPolicy() {
// amend this as appropriate
appPermissions.add(new AllPermission());
// add any permissions plugins should have to pluginPermissions
}
@Override
public Provider getProvider() {
return super.getProvider();
}
@Override
public String getType() {
return super.getType();
}
@Override
public Parameters getParameters() {
return super.getParameters();
}
@Override
public PermissionCollection getPermissions(CodeSource codesource) {
return new Permissions();
}
@Override
public PermissionCollection getPermissions(ProtectionDomain domain) {
return isPlugin(domain)?pluginPermissions:appPermissions;
}
Policy.setPolicy(new PluginSecurityPolicy());
System.setSecurityManager(new SecurityManager());
https://riptutorial.com/es/home 618
solo uno de todos los enfoques posibles para satisfacer este tipo de requisitos. Introduce una
clase de permiso "negativa", junto con un envoltorio que permite que la Policy predeterminada se
reutilice como un repositorio de dichos permisos.
Notas:
La clase de DeniedPermission
package com.example;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.security.BasicPermission;
import java.security.Permission;
import java.security.UnresolvedPermission;
import java.text.MessageFormat;
/**
* A representation of a "negative" privilege.
* <p>
* A <code>DeniedPermission</code>, when "granted" (to some <code>ProtectionDomain</code>
and/or
* <code>Principal</code>), represents a privilege which <em>cannot</em> be exercised,
regardless of
* any positive permissions (<code>AllPermission</code> included) possessed. In other words,
if a
* set of granted permissions, <em>P</em>, contains a permission of this class, <em>D</em>,
then the
* set of effectively granted permissions is<br/>
* <br/>
* <em>{ P<sub>implied</sub> - D<sub>implied</sub> }</em>.
* </p>
* <p>
* Each instance of this class encapsulates a <em>target permission</em>, representing the
* "positive" permission being denied.
* </p>
* Denied permissions employ the following naming scheme:<br/>
* <br/>
*
<em><target_class_name>:<target_name>(:<target_actions>)</em>
* <br/>
* where:
* <ul>
* <li><em>target_class_name</em> is the name of the target permission's class,</li>
https://riptutorial.com/es/home 619
* <li><em>target_name</em> is the name of the target permission, and</li>
* <li><em>target_actions</em> is, optionally, the actions string of the target
permission.</li>
* </ul>
* A denied permission, having a target permission <em>t</em>, is said to <em>imply</em>
another
* permission <em>p</em>, if:
* <ul>
* <li>p <em>is not</em> itself a denied permission, and <code>(t.implies(p) == true)</code>,
* or</li>
* <li>p <em>is</em> a denied permission, with a target <em>t1</em>, and
* <code>(t.implies(t1) == true)</code>.
* </ul>
* <p>
* It is the responsibility of the policy decision point (e.g., the <code>Policy</code>
provider) to
* take denied permission semantics into account when issuing authorization statements.
* </p>
*/
public final class DeniedPermission extends BasicPermission {
/**
* Instantiates a <code>DeniedPermission</code> that encapsulates a target permission of
the
* indicated class, specified name and, optionally, actions.
*
* @throws IllegalArgumentException
* if:
* <ul>
* <li><code>targetClassName</code> is <code>null</code>, the empty string,
does not
* refer to a concrete <code>Permission</code> descendant, or refers to
* <code>DeniedPermission.class</code> or
<code>UnresolvedPermission.class</code>.</li>
* <li><code>targetName</code> is <code>null</code>.</li>
* <li><code>targetClassName</code> cannot be instantiated, and it's the
caller's fault;
* e.g., because <code>targetName</code> and/or <code>targetActions</code> do
not adhere
* to the naming constraints of the target class; or due to the target class
not
* exposing a <code>(String name)</code>, or <code>(String name, String
actions)</code>
* constructor, depending on whether <code>targetActions</code> is
<code>null</code> or
* not.</li>
* </ul>
*/
public static DeniedPermission newDeniedPermission(String targetClassName, String
targetName,
String targetActions) {
if (targetClassName == null || targetClassName.trim().isEmpty() || targetName == null)
{
throw new IllegalArgumentException(
"Null or empty [targetClassName], or null [targetName] argument was
supplied.");
}
StringBuilder sb = new StringBuilder(targetClassName).append(":").append(targetName);
https://riptutorial.com/es/home 620
if (targetName != null) {
sb.append(":").append(targetName);
}
return new DeniedPermission(sb.toString());
}
/**
* Instantiates a <code>DeniedPermission</code> that encapsulates a target permission of
the class,
* name and, optionally, actions, collectively provided as the <code>name</code> argument.
*
* @throws IllegalArgumentException
* if:
* <ul>
* <li><code>name</code>'s target permission class name component is empty,
does not
* refer to a concrete <code>Permission</code> descendant, or refers to
* <code>DeniedPermission.class</code> or
<code>UnresolvedPermission.class</code>.</li>
* <li><code>name</code>'s target name component is <code>empty</code></li>
* <li>the target permission class cannot be instantiated, and it's the
caller's fault;
* e.g., because <code>name</code>'s target name and/or target actions
component(s) do
* not adhere to the naming constraints of the target class; or due to the
target class
* not exposing a <code>(String name)</code>, or
* <code>(String name, String actions)</code> constructor, depending on
whether the
* target actions component is empty or not.</li>
* </ul>
*/
public DeniedPermission(String name) {
super(name);
String[] comps = name.split(":");
if (comps.length < 2) {
throw new IllegalArgumentException(MessageFormat.format("Malformed name [{0}]
argument.", name));
}
this.target = initTarget(comps[0], comps[1], ((comps.length < 3) ? null : comps[2]));
}
/**
* Instantiates a <code>DeniedPermission</code> that encapsulates the given target
permission.
*
* @throws IllegalArgumentException
* if <code>target</code> is <code>null</code>, a
<code>DeniedPermission</code>, or an
* <code>UnresolvedPermission</code>.
*/
public static DeniedPermission newDeniedPermission(Permission target) {
if (target == null) {
throw new IllegalArgumentException("Null [target] argument.");
}
if (target instanceof DeniedPermission || target instanceof UnresolvedPermission) {
throw new IllegalArgumentException("[target] must not be a DeniedPermission or an
UnresolvedPermission.");
}
StringBuilder sb = new
StringBuilder(target.getClass().getName()).append(":").append(target.getName());
https://riptutorial.com/es/home 621
String targetActions = target.getActions();
if (targetActions != null) {
sb.append(":").append(targetActions);
}
return new DeniedPermission(sb.toString(), target);
}
https://riptutorial.com/es/home 622
targetName = "<null>";
}
else if (targetName.trim().isEmpty()) {
targetName = "<empty>";
}
if (targetActions == null) {
targetActions = "<null>";
}
else if (targetActions.trim().isEmpty()) {
targetActions = "<empty>";
}
throw new IllegalArgumentException(MessageFormat.format(
"Could not instantiate target Permission class [{0}]; provided target
name [{1}] and/or target actions [{2}] potentially erroneous.",
targetClassName, targetName, targetActions), roe);
}
throw new RuntimeException(
"Could not instantiate target Permission class [{0}]; an unforeseen error
occurred - see attached cause for details",
roe);
}
}
/**
* Checks whether the given permission is implied by this one, as per the {@link
DeniedPermission
* overview}.
*/
@Override
public boolean implies(Permission p) {
if (p instanceof DeniedPermission) {
return target.implies(((DeniedPermission) p).target);
}
return target.implies(p);
}
/**
* Returns this denied permission's target permission (the actual positive permission
which is not
* to be granted).
*/
public Permission getTargetPermission() {
return target;
}
La clase DenyingPolicy
package com.example;
import java.security.CodeSource;
import java.security.NoSuchAlgorithmException;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.security.UnresolvedPermission;
import java.util.Enumeration;
https://riptutorial.com/es/home 623
/**
* Wrapper that adds rudimentary {@link DeniedPermission} processing capabilities to the
standard
* file-backed <code>Policy</code>.
*/
public final class DenyingPolicy extends Policy {
{
try {
defaultPolicy = Policy.getInstance("javaPolicy", null);
}
catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("Could not acquire default Policy.", nsae);
}
}
@Override
public PermissionCollection getPermissions(CodeSource codesource) {
return defaultPolicy.getPermissions(codesource);
}
@Override
public PermissionCollection getPermissions(ProtectionDomain domain) {
return defaultPolicy.getPermissions(domain);
}
/**
* @return
* <ul>
* <li><code>true</code> if:</li>
* <ul>
* <li><code>permission</code> <em>is not</em> an instance of
* <code>DeniedPermission</code>,</li>
* <li>an <code>implies(domain, permission)</code> invocation on the system-
default
* <code>Policy</code> yields <code>true</code>, and</li>
* <li><code>permission</code> <em>is not</em> implied by any
<code>DeniedPermission</code>s
* having potentially been assigned to <code>domain</code>.</li>
* </ul>
* <li><code>false</code>, otherwise.
* </ul>
*/
@Override
public boolean implies(ProtectionDomain domain, Permission permission) {
if (permission instanceof DeniedPermission) {
/*
* At the policy decision level, DeniedPermissions can only themselves imply, not
be implied (as
* they take away, rather than grant, privileges). Furthermore, clients aren't
supposed to use this
* method for checking whether some domain _does not_ have a permission (which is
what
* DeniedPermissions express after all).
*/
return false;
}
https://riptutorial.com/es/home 624
if (!defaultPolicy.implies(domain, permission)) {
// permission not granted, so no need to check whether denied
return false;
}
/*
* Permission granted--now check whether there's an overriding DeniedPermission. The
following
* assumes that previousPolicy is a sun.security.provider.PolicyFile (different
implementations
* might not support #getPermissions(ProtectionDomain) and/or handle
UnresolvedPermissions
* differently).
*/
@Override
public void refresh() {
defaultPolicy.refresh();
}
Manifestación
package com.example;
import java.security.Policy;
https://riptutorial.com/es/home 625
// should fail
System.getProperty("foo.bar");
}
Por último, ejecute el Main y observe cómo falla, debido a la regla de "denegar" ( DeniedPermission )
que DeniedPermission la grant (su PropertyPermission ). Tenga en cuenta que una
setProperty("foo.baz", "xyz") lugar habría tenido éxito, ya que el permiso denegado solo cubre la
acción "leer", y solo para la propiedad "foo.bar".
https://riptutorial.com/es/home 626
Capítulo 89: Gestión de memoria de Java
Observaciones
En Java, los objetos se asignan en el montón y la memoria del montón se reclama mediante la
recolección automática de basura. Un programa de aplicación no puede eliminar explícitamente
un objeto Java.
Examples
Finalización
Un objeto Java puede declarar un método de finalize . Este método se llama justo antes de que
Java libere la memoria para el objeto. Normalmente se verá así:
@Override
protected void finalize() throws Throwable {
// Cleanup code
}
}
Las advertencias anteriores significan que es una mala idea confiar en el método de finalize para
realizar acciones de limpieza (u otras) que deben realizarse de manera oportuna. La dependencia
excesiva de la finalización puede provocar fugas de almacenamiento, fugas de memoria y otros
problemas.
En resumen, hay muy pocas situaciones en las que la finalización es realmente una buena
solución.
https://riptutorial.com/es/home 627
Los finalizadores solo se ejecutan una vez.
Normalmente, un objeto se elimina después de que se ha finalizado. Sin embargo, esto no
sucede todo el tiempo. Considere el siguiente ejemplo 1 :
Respuesta: No.
El problema es que la JVM solo ejecutará un finalizador en un objeto una vez en su vida. Si
asigna null a notDeadYet hace que una instancia resurectada no sea accesible una vez más, el
recolector de basura no llamará a finalize() en el objeto.
1 - Ver https://en.wikipedia.org/wiki/Jack_Harkness .
Activación manual de GC
System.gc();
Sin embargo, Java no garantiza que el recolector de basura se haya ejecutado cuando se
devuelva la llamada. Este método simplemente "sugiere" a la JVM (Java Virtual Machine) que
desea que ejecute el recolector de basura, pero no lo obliga a hacerlo.
Recolección de basura
https://riptutorial.com/es/home 628
En un lenguaje como C ++, el programa de aplicación es responsable de administrar la memoria
utilizada por la memoria asignada dinámicamente. Cuando se crea un objeto en el ++ montón
usando el C new operador, es necesario que haya un uso correspondiente de la delete operador
para disponer del objeto:
• Por otro lado, si una aplicación intenta delete el mismo objeto dos veces, o usar un objeto
después de que se haya eliminado, la aplicación puede fallar debido a problemas con la
corrupción de la memoria.
En la práctica, esto significa que hay una cadena de referencias a partir de una variable
local dentro del alcance o una variable static por la cual algún código podría alcanzar el
objeto.
• Los objetos inalcanzables son objetos a los que no se puede acceder como se mencionó
anteriormente.
Cualquier objeto que sea inalcanzable es elegible para la recolección de basura. Esto no significa
que serán recolectados en la basura. De hecho:
La especificación del lenguaje Java le da mucha latitud a una implementación de JVM para
decidir cuándo recoger objetos inalcanzables. También (en la práctica) otorga permiso para que
https://riptutorial.com/es/home 629
una implementación de JVM sea conservadora en la forma en que detecta objetos inalcanzables.
Lo único que garantiza el JLS es que nunca se recogerá la basura en ningún objeto accesible .
1. Si hay objetos de Reference que se refieren al objeto, esas referencias se borrarán antes de
que se elimine el objeto.
2. Si el objeto es finalizable , entonces será finalizado. Esto sucede antes de que se elimine el
objeto.
Tenga en cuenta que hay una secuencia clara en la que pueden ocurrir los eventos anteriores,
pero nada requiere que el recolector de basura realice la eliminación final de cualquier objeto
específico en un período de tiempo específico.
https://riptutorial.com/es/home 630
Examinemos lo que sucede cuando se llama test() . Las declaraciones T1, T2 y T3 crean objetos
de Node , y todos los objetos son accesibles a través de las variables n1 , n2 y n3 , respectivamente.
La declaración T4 asigna la referencia al objeto del segundo Node al next campo del primero.
Cuando se hace eso, se puede Node al 2do Node a través de dos rutas:
n2 -> Node2
n1 -> Node1, Node1.next -> Node2
En la declaración T6, asignamos null a n3 . Esto rompe la única cadena de accesibilidad para
Node3 , lo que hace que Node3 sea inalcanzable. Sin embargo, Node1 y Node2 aún son accesibles a
través de la variable n1 .
Finalmente, cuando el método test() regresa, sus variables locales n1 , n2 y n3 quedan fuera del
alcance y, por lo tanto, nadie puede acceder a ellas. Esto rompe las cadenas de accesibilidad
restantes para Node1 y Node2 , y todos los objetos de Node son inalcanzables y son elegibles para la
recolección de basura.
1 - Esta es una simplificación que ignora la finalización y las clases de Reference . 2 - Hipotéticamente, una
implementación de Java podría hacer esto, pero el costo de rendimiento de hacerlo lo hace impráctico.
Cuando se inicia una máquina virtual Java, necesita saber qué tan grande es el Heap y el tamaño
predeterminado para las pilas de hilos. Estos se pueden especificar usando las opciones de línea
de comando en el comando java . Para las versiones de Java anteriores a Java 8, también puede
especificar el tamaño de la región PermGen del montón.
Si no especifica explícitamente los tamaños de pila y pila, la JVM utilizará los valores
predeterminados que se calculan de una manera específica de la versión y la plataforma. Esto
puede hacer que su aplicación use muy poca o demasiada memoria. Esto suele ser correcto para
las pilas de hilos, pero puede ser problemático para un programa que utiliza mucha memoria.
https://riptutorial.com/es/home 631
El parámetro <size> puede ser un número de bytes, o puede tener un sufijo de k , m o g . Los
últimos especifican el tamaño en kilobytes, megabytes y gigabytes respectivamente.
Ejemplos:
La -XX:+printFlagsFinal se puede usar para imprimir los valores de todas las banderas antes de
iniciar la JVM. Esto se puede usar para imprimir los valores predeterminados para las
configuraciones de tamaño de pila y pila de la siguiente manera:
• Para ventanas:
En el ejemplo de recolección de basura , implicamos que Java resuelve el problema de las fugas
de memoria. Esto no es realmente cierto. Un programa Java puede perder memoria, aunque las
causas de las fugas son bastante diferentes.
https://riptutorial.com/es/home 632
}
stack[top++] = obj;
}
Cuando push un objeto y luego lo haces pop , todavía habrá una referencia al objeto en la matriz
de la stack .
Esta estrategia puede ser muy efectiva si se implementa adecuadamente. Sin embargo, si se
implementa incorrectamente, un caché puede ser una pérdida de memoria. Considere el siguiente
ejemplo:
https://riptutorial.com/es/home 633
public class RequestHandler {
private Map<Task, Result> cache = new HashMap<>();
El problema con este código es que, si bien cualquier llamada a doRequest puede agregar una
nueva entrada al caché, no hay nada para eliminarlos. Si el servicio obtiene continuamente
diferentes tareas, la memoria caché consumirá toda la memoria disponible. Esta es una forma de
pérdida de memoria.
Un método para resolver esto es utilizar un caché con un tamaño máximo y eliminar las entradas
antiguas cuando el caché excede el máximo. (Lanzar la entrada menos utilizada recientemente es
una buena estrategia). Otro método consiste en crear la memoria caché utilizando WeakHashMap
para que JVM pueda expulsar las entradas de la memoria caché si el montón comienza a llenarse
demasiado.
https://riptutorial.com/es/home 634
Capítulo 90: Gráficos 2D en Java
Introducción
Los gráficos son imágenes visuales o diseños en alguna superficie, como una pared, lienzo,
pantalla, papel o piedra para informar, ilustrar o entretener. Incluye: representación gráfica de
datos, como en el diseño y fabricación asistidos por computadora, en la composición tipográfica y
las artes gráficas, y en software educativo y recreativo. Las imágenes que son generadas por una
computadora se llaman gráficos de computadora.
La API Java 2D es potente y compleja. Hay varias formas de hacer gráficos 2D en Java.
Examples
Ejemplo 1: dibujar y rellenar un rectángulo utilizando Java
https://i.stack.imgur.com/dlC5v.jpg
La mayoría de los métodos de la clase Gráficos se pueden dividir en dos grupos básicos:
1. Dibuje y complete métodos, que le permiten representar formas básicas, texto e imágenes.
2. Métodos de configuración de atributos, que afectan la forma en que aparecen los dibujos y
rellenos.
https://riptutorial.com/es/home 635
MyPanel usamos mathods drawRect () & fillRect () para dibujar un rectángulo y colorear en él.
Establecemos el color mediante el método setColor (Color.blue). En Segunda clase, probamos
nuestro gráfico, que es la clase de prueba, creamos un cuadro y colocamos MyPanel con p =
nuevo objeto MyPanel (). Al ejecutar la clase de prueba, vemos un rectángulo y un rectángulo de
color azul.
import javax.swing.*;
import java.awt.*;
// MyPanel extends JPanel, which will eventually be placed in a JFrame
public class MyPanel extends JPanel {
// custom painting is performed by the paintComponent method
@Override
public void paintComponent(Graphics g){
// clear the previous painting
super.paintComponent(g);
// cast Graphics to Graphics2D
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red); // sets Graphics2D color
// draw the rectangle
g2.drawRect(0,0,100,100); // drawRect(x-position, y-position, width, height)
g2.setColor(Color.blue);
g2.fillRect(200,0,100,100); // fill new rectangle with color blue
}
}
import javax.swing.;
import java.awt.;
public class Test { //the Class by which we display our rectangle
JFrame f;
MyPanel p;
public Test(){
f = new JFrame();
// get the content area of Panel.
Container c = f.getContentPane();
// set the LayoutManager
c.setLayout(new BorderLayout());
p = new MyPanel();
// add MyPanel object into container
c.add(p);
// set the size of the JFrame
f.setSize(400,400);
// make the JFrame visible
f.setVisible(true);
// sets close behavior; EXIT_ON_CLOSE invokes System.exit(0) on closing the JFrame
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
https://riptutorial.com/es/home 636
https://docs.oracle.com/javase/tutorial/uiswing/layout/border.html
paintComponent ()
import javax.swing.*;
import java.awt.*;
g2.fillOval (int x, int y, int height, int ancho); Este método llenará un óvalo en las posiciones x e
y especificadas con la altura y el ancho dados.
https://riptutorial.com/es/home 637
Capítulo 91: Hechiceros y Setters
Introducción
Este artículo analiza los captadores y setters; La forma estándar de proporcionar acceso a los
datos en las clases de Java.
Examples
Adición de Getters y Setters
No se puede acceder a estas variables privadas directamente desde fuera de la clase. Por lo
tanto, están protegidos contra el acceso no autorizado. Pero si desea verlos o modificarlos, puede
usar los Getters y Setters.
getXxx()método getXxx() devolverá el valor actual de la variable xxx , mientras que puede
establecer el valor de la variable xxx utilizando setXxx() .
https://riptutorial.com/es/home 638
• variables boolean
Setters y Getters permiten que un objeto contenga variables privadas a las que se puede acceder
y cambiar con restricciones. Por ejemplo,
En esta clase de Person , hay una sola variable: name . Se puede acceder a esta variable usando el
método getName() y cambiarla usando el setName(String) , sin embargo, establecer un nombre
requiere que el nuevo nombre tenga una longitud mayor que 2 caracteres y no sea nulo. El uso de
un método de establecimiento en lugar de hacer público el name la variable permite a otros
establecer el valor del name con ciertas restricciones. Lo mismo se puede aplicar al método getter:
Considere una clase básica que contiene un objeto con captadores y definidores en Java:
https://riptutorial.com/es/home 639
public int getCount() { return count; }
public void setCount(int c) { count = c; }
}
No podemos acceder a la variable de count porque es privada. Pero podemos acceder a los
getCount() y setCount(int) porque son públicos. Para algunos, esto podría plantear la cuestión;
¿Por qué introducir el intermediario? ¿Por qué no simplemente hacer que cuenten público?
Para todos los efectos, estos dos son exactamente iguales, en cuanto a funcionalidad. La
diferencia entre ellos es la extensibilidad. Considera lo que dice cada clase:
• Primero : "Tengo un método que le dará un valor int , y un método que establecerá ese
valor en otro int ".
• Segundo : "Tengo un int que puedes configurar y obtener como desees".
Estos pueden sonar similares, pero el primero es en realidad mucho más protegido en su
naturaleza; solo te permite interactuar con su naturaleza interna según lo dicte. Esto deja el balón
en su corte; Se llega a elegir cómo se producen las interacciones internas. El segundo ha
expuesto su implementación interna externamente, y ahora no solo es propenso a usuarios
externos, sino que, en el caso de una API, se compromete a mantener esa implementación (o,
de lo contrario, a liberar una API no compatible con versiones anteriores).
pero en el segundo ejemplo, esto es ahora casi imposible sin pasar por y modificar cada lugar
donde se hace referencia a la variable de count . Peor aún, si este es un elemento que está
proporcionando en una biblioteca para que otros lo consuman, no tiene una forma de realizar esa
modificación y se ve obligado a tomar la decisión difícil mencionada anteriormente.
Así que plantea la pregunta; ¿Son las variables públicas algo bueno (o, al menos, no malvado)?
No estoy seguro Por un lado, puede ver ejemplos de variables públicas que han pasado la prueba
del tiempo (IE: la variable de out referenciada en System.out ). Por otro lado, proporcionar una
variable pública no ofrece beneficios más allá de los gastos generales extremadamente mínimos
y la posible reducción de la notoriedad. Mi pauta aquí sería que, si planea hacer pública una
variable, debe juzgarla con estos criterios con un prejuicio extremo :
https://riptutorial.com/es/home 640
1. La variable debe tener ninguna razón concebible cambiar nunca en su aplicación. Esto es
algo que es extremadamente fácil de arruinar (y, aunque lo hagas bien, los requisitos
pueden cambiar), por lo que el método común es el método común. Si va a tener una
variable pública, esto realmente debe ser pensado, especialmente si se publica en una
biblioteca / framework / API.
2. La variable debe ser referenciada con la frecuencia suficiente para que las ganancias
mínimas de reducir la verbosidad lo justifiquen. Ni siquiera creo que la sobrecarga para usar
un método en lugar de una referencia directa deba considerarse aquí. Es demasiado
insignificante para lo que estimaría de manera conservadora que es el 99.9% de las
aplicaciones.
Probablemente hay más de lo que no he considerado de la cabeza. Si alguna vez tienes dudas,
usa siempre getters / setters.
https://riptutorial.com/es/home 641
Capítulo 92: Herencia
Introducción
La herencia es una característica básica orientada a objetos en la que una clase adquiere y se
extiende sobre las propiedades de otra clase, utilizando la palabra clave extends . Para Interfaces
y los implements palabras clave, vea interfaces .
Sintaxis
• clase ClassB extiende ClassA {...}
• clase ClassB implementa InterfaceA {...}
• interface InterfaceB extiende InterfaceA {...}
• clase ClassB extiende ClassA implementa InterfaceC, InterfaceD {...}
• clase abstracta AbstractClassB extiende ClassA {...}
• clase abstracta AbstractClassB extiende AbstractClassA {...}
• clase abstracta AbstractClassB extiende ClassA implementa InterfaceC, InterfaceD {...}
Observaciones
La herencia a menudo se combina con los genéricos de modo que la clase base tenga uno o más
parámetros de tipo. Consulte Creación de una clase genérica .
Examples
Clases abstractas
Una clase abstracta es una clase marcada con la palabra clave abstract . Contrariamente a la
clase no abstracta, puede contener métodos abstractos sin implementación. Sin embargo, es
válido crear una clase abstracta sin métodos abstractos.
Una clase abstracta no puede ser instanciada. Puede ser subclasificado (extendido) siempre que
la subclase sea abstracta, o implemente todos los métodos marcados como abstractos por súper
clases.
https://riptutorial.com/es/home 642
}
La clase debe estar marcada como abstracta, cuando tiene al menos un método abstracto. Un
método abstracto es un método que no tiene implementación. Se pueden declarar otros métodos
dentro de una clase abstracta que tiene implementación para proporcionar código común para
cualquier subclase.
Sin embargo, una clase que amplía el Component y proporciona una implementación para todos sus
métodos abstractos y se puede instanciar.
@Override
public void render() {
//render a button
}
}
@Override
public void render() {
//render a textbox
}
}
Las instancias de clases heredadas también se pueden convertir como la clase principal (herencia
normal) y proporcionan un efecto polimórfico cuando se llama al método abstracto.
Tanto las clases abstractas como las interfaces proporcionan una forma de definir firmas de
métodos al tiempo que requieren que la clase extendida / implementada proporcione la
implementación.
Hay dos diferencias clave entre las clases abstractas y las interfaces:
• Una clase solo puede extender una sola clase, pero puede implementar muchas interfaces.
• Una clase abstracta puede contener campos de instancia (no static ), pero las interfaces
solo pueden contener campos static .
Java SE 8
https://riptutorial.com/es/home 643
Los métodos declarados en las interfaces no pueden contener implementaciones, por lo que se
usaron clases abstractas cuando fue útil proporcionar métodos adicionales que las
implementaciones llamaron métodos abstractos.
Java SE 8
Como conveniencia, java permite crear instancias anónimas de subclases de clases abstractas,
que proporcionan implementaciones para los métodos abstractos al crear el nuevo objeto.
Usando el ejemplo anterior, esto podría verse así:
Herencia estática
El método estático se puede heredar de forma similar a los métodos normales, sin embargo, a
diferencia de los métodos normales, es imposible crear métodos " abstractos " para forzar la
anulación del método estático. Escribir un método con la misma firma que un método estático en
una súper clase parece ser una forma de anulación, pero en realidad esto simplemente crea una
nueva función que oculta a la otra.
SubClass.sayHello();
//This will be different than the above statement's output, since it runs
//A different method
SubClass.sayHello(true);
StaticOverride.sayHello();
System.out.println("StaticOverride's num: " + StaticOverride.num);
}
}
https://riptutorial.com/es/home 644
//Inherits the sayHello function, but does not override it
public static void sayHello(boolean test) {
System.out.println("Hey");
}
}
Hello
BaseClass's num: 5
Hello
Hey
Static says Hi
StaticOverride's num: test
Tenga en cuenta que, a diferencia de la herencia normal, en los métodos de herencia estática no
están ocultos. Siempre puede llamar al método base sayHello usando BaseClass.sayHello() . Pero
las clases heredan métodos estáticos si no se encuentran métodos con la misma firma en la
subclase. Si las firmas de dos métodos varían, ambos métodos pueden ejecutarse desde la
subclase, incluso si el nombre es el mismo.
Clases finales
Cuando se usa en una declaración de class , el modificador final evita que se declaren otras
clases que extend la clase. Una clase final es una clase "hoja" en la jerarquía de clases de
herencia.
https://riptutorial.com/es/home 645
}
Las clases inmutables también deben ser declaradas como final . (Una clase inmutable es
aquella cuyas instancias no se pueden cambiar después de haber sido creadas; consulte el tema
Imutables de objetos ). Al hacer esto, hace imposible crear una subclase mutable de una clase
inmutable. Eso violaría el principio de sustitución de Liskov, que exige que un subtipo obedezca el
"contrato de comportamiento" de sus supertipos.
Desde una perspectiva práctica, declarar que una clase inmutable es final hace que sea más
fácil razonar sobre el comportamiento del programa. También aborda los problemas de seguridad
en el escenario donde el código no confiable se ejecuta en un entorno limitado de seguridad. (Por
ejemplo, como String se declara como final , una clase confiable no tiene que preocuparse de
que pueda ser engañada para que acepte una subclase mutable, que la persona que llama no de
confianza podría cambiar de manera subrepticia).
Una desventaja de las clases final es que no funcionan con algunos marcos burlones como
Mockito. Actualización: la versión 2 de Mockito ahora admite la burla de las clases finales.
Métodos finales
El modificador final también se puede aplicar a los métodos para evitar que se sobrescriban en
las subclases:
@Override
https://riptutorial.com/es/home 646
public void someMethod() { // Compiler error (overridden method is final)
}
}
Los métodos finales se usan normalmente cuando se quiere restringir lo que una subclase puede
cambiar en una clase sin prohibir por completo las subclases.
El modificador final también se puede aplicar a las variables, pero el significado de final para las
variables no está relacionado con la herencia.
class A {...}
class B extends A {...}
Esto también se aplica cuando el tipo es una interfaz, donde no se necesita ninguna relación
jerárquica entre los objetos:
interface Foo {
void bar();
}
Herencia
Con el uso de la extends palabra clave entre las clases, todas las propiedades de la superclase
(también conocido como la clase padre o Clase Base) están presentes en la subclase (también
conocida como la clase hija o clase derivada)
https://riptutorial.com/es/home 647
public class BaseClass {
public int x;
public SubClassWithField(int x) {
this.x = x; //Can access fields
}
}
private campos y métodos private aún existen dentro de la subclase, pero no son accesibles:
private int x = 5;
https://riptutorial.com/es/home 648
}
Esto se conoce como herencia múltiple, y si bien es legal en algunos idiomas, Java no lo permite
con clases.
Como resultado de esto, cada clase tiene una cadena de clases ancestrales no ramificadas que
conducen a Object , de la que descienden todas las clases.
En Java, las clases padre e hijo pueden tener métodos estáticos con el mismo nombre. Pero en
tales casos, la implementación del método estático en hijo oculta la implementación de la clase
padre, no se trata de una anulación del método. Por ejemplo:
class StaticMethodTest {
Los métodos estáticos se unen a una clase y no a una instancia y este enlace de método ocurre
en tiempo de compilación. Dado que en la primera llamada a staticMethod() , matriz de referencia
https://riptutorial.com/es/home 649
de clase p se utilizó, Parent versión 's de staticMethod() se invoca. En el segundo caso, hicimos p
en Child clase Child , se ejecutó staticMethod() Child .
Sombreado variable
Las variables están SOMBRADAS y los métodos son ANULADOS. La variable que se utilizará
depende de la clase de la que se declara la variable. El método que se utilizará depende de la
clase real del objeto al que hace referencia la variable.
class Car {
public int gearRatio = 8;
Convertir una instancia de una clase base en una subclase como en: b = (B) a; se denomina
estrechamiento (cuando intenta restringir el objeto de clase base a un objeto de clase más
específico) y necesita una conversión de tipos explícita.
Convertir una instancia de una subclase en una clase base como en: A a = b; Se llama
ampliación y no necesita una conversión de tipo.
class Vehicle {
}
https://riptutorial.com/es/home 650
}
class Test {
La declaración Vehicle vehicle = new Car(); Es una declaración válida de Java. Cada instancia de
Car es también un Vehicle . Por lo tanto, la asignación es legal sin la necesidad de una conversión
de tipos explícita.
Por otro lado, Car c = vehicle; no es válido. El tipo estático de la variable de vehicle es Vehicle
que significa que podría referirse a una instancia de Car , Camión , Motocicleta , or any other
current or future subclass of Vehículo . (Or indeed, an instance of Vehículo en itself, since we
did not declare it as an class.) The assignment cannot be allowed, since that might lead to
abstracta class.) The assignment cannot be allowed, since that might lead to automóvil se
referring to a instancia de referring to a Camión.
Para evitar esta situación, necesitamos agregar una conversión de tipos explícita:
La conversión de tipos le dice al compilador que esperamos que el valor del vehicle sea un Car o
una subclase de Car . Si es necesario, el compilador insertará el código para realizar una
verificación de tipo en tiempo de ejecución. Si la comprobación falla, se emitirá una
ClassCastException cuando se ejecute el código.
Tenga en cuenta que no todos los tipos de conversión son válidos. Por ejemplo:
El compilador de Java sabe que una instancia que es compatible con Type con Vehicle no puede
ser compatible con String . La conversión de tipos nunca podría tener éxito, y JLS exige que esto
dé un error de compilación.
https://riptutorial.com/es/home 651
buen código que se ocupa, por ejemplo, de las colecciones de Java se verá así:
No solo los primeros se pueden aplicar a una variedad más amplia de argumentos, sino que sus
resultados serán más compatibles con el código proporcionado por otros desarrolladores que
generalmente se adhieren al concepto de programación para una interfaz. Sin embargo, las
razones más importantes para usar el primero son:
El siguiente ejemplo basado en estos principios es una versión simplificada y truncada de una
implementación RPC escrita para varios protocolos diferentes:
Se supone que la interfaz anterior no debe crearse una instancia directamente a través de una
fábrica, en su lugar derivamos interfaces más concretas, una para la invocación HTTP y otra para
AMQP, cada una con una fábrica y un constructor para construir instancias, que a su vez también
son instancias de la interfaz anterior:
https://riptutorial.com/es/home 652
Las instancias de RemoteInvoker para el uso con AMQP ahora pueden construirse tan fácilmente (o
más involucradas según el constructor):
El generador utilizado anteriormente podría tener este aspecto (aunque esto es una
simplificación, ya que el actual permite definir hasta 15 parámetros que se desvían de los valores
predeterminados). Tenga en cuenta que la construcción no es pública, por lo que solo se puede
utilizar específicamente desde la interfaz AmqpInvoker anterior:
https://riptutorial.com/es/home 653
En general, un generador también se puede generar utilizando una herramienta como
FreeBuilder.
Finalmente, la implementación estándar (y la única esperada) de esta interfaz se define como una
clase de paquete local para imponer el uso de la interfaz, la fábrica y el constructor:
@Override
public <RQ, RS> CompletableFuture<RS> invoke(final RQ request, final Class<RS> respClass) {
...
}
}
Mientras tanto, este patrón demostró ser muy eficiente en el desarrollo de todo nuestro nuevo
código, sin importar cuán simple o compleja sea la funcionalidad.
Cuándo usar clases abstractas: implementar el mismo comportamiento o diferente entre múltiples
objetos relacionados
Cuándo usar interfaces: para implementar un contrato por múltiples objetos no relacionados
Las clases abstractas crean que "es una" relación mientras que las interfaces proporcionan "tiene
una" capacidad.
System.out.println("Dog:"+dog);
System.out.println("Cat:"+cat);
dog.remember();
dog.protectOwner();
Learn dl = dog;
dl.learn();
cat.remember();
cat.protectOwner();
Climb c = cat;
c.climb();
https://riptutorial.com/es/home 654
Climb cm = man;
cm.climb();
Think t = man;
t.think();
Learn l = man;
l.learn();
Apply a = man;
a.apply();
}
}
https://riptutorial.com/es/home 655
interface Learn {
void learn();
}
interface Apply{
void apply();
}
salida:
Dog:Dog:Jack:16
Cat:Cat:Joe:20
Dog can remember for 5 minutes
Dog will protect owner
Dog can learn:
Cat can remember for 16 hours
Cat won't protect owner
Cat can climb
Man :Ravindra:Age:40
I can climb:Man
I can think:Man
I can learn:Man
I can apply:Man
Notas clave:
1. Animal es una clase abstracta con atributos compartidos: name y lifeExpectancy y métodos
abstractos: remember() y protectOwner() . Dog y Cat son Animals que han implementado los
métodos remember() y protectOwner() .
2. Cat puede climb() pero el Dog no puede. Dog puede think() pero el Cat no puede. Estas
capacidades específicas se agregan a Cat y Dog por implementación.
3. Man
https://riptutorial.com/es/home 656
no es un Animal pero puede Think , Learn , Apply y Climb .
6. Man no es ni un Cat ni un Dog pero puede tener algunas de las capacidades de los dos últimos
sin extender Animal , Cat o Dog . Esto se hace con interfaces.
7. Aunque Animal es una clase abstracta, tiene un constructor, a diferencia de una interfaz.
TL; DR:
Las clases no relacionadas pueden tener capacidades a través de interfaces, pero las clases
relacionadas cambian el comportamiento a través de la extensión de las clases base.
Consulte la página de documentación de Java para comprender cuál usar en un caso de uso
específico.
1. Usted espera que las clases no relacionadas implementen su interfaz. Por ejemplo, muchos
objetos no relacionados pueden implementar la interfaz Serializable .
2. Desea especificar el comportamiento de un tipo de datos en particular, pero no le preocupa
quién implementa su comportamiento.
3. Desea aprovechar la herencia de tipo múltiple.
Anulando en herencia
La anulación de herencia se usa cuando se usa un método ya definido de una superclase en una
subclase, pero de una manera diferente a como se diseñó originalmente el método en la
superclase. La anulación permite al usuario reutilizar el código utilizando el material existente y
modificándolo para que se adapte mejor a las necesidades del usuario.
El siguiente ejemplo muestra cómo ClassB anula la funcionalidad de ClassA al cambiar lo que se
envía a través del método de impresión:
Ejemplo:
https://riptutorial.com/es/home 657
ClassA b = new ClassB();
a.printing();
b.printing();
}
class ClassA {
public void printing() {
System.out.println("A");
}
}
Salida:
UNA
segundo
https://riptutorial.com/es/home 658
Capítulo 93: Hora local
Sintaxis
• LocalTime time = LocalTime.now (); // Inicializa con el reloj del sistema actual
• LocalTime time = LocalTime.MIDNIGHT; // 00:00
• LocalTime time = LocalTime.NOON; // 12:00
• LocalTime time = LocalTime.of (12, 12, 45); // 12:12:45
Parámetros
Método Salida
LocalTime.MIDNIGHT 00:00
LocalTime.NOON 12:00
Observaciones
Como el nombre de la clase indica, LocalTime representa una hora sin una zona horaria. No
representa una fecha. Es una etiqueta simple para un tiempo dado.
La clase está basada en valores y el método equals se debe usar al hacer comparaciones.
Examples
Modificación de tiempo
https://riptutorial.com/es/home 659
LocalTime addHours = time.plusHours(5); // Add 5 hours
LocaLTime addMinutes = time.plusMinutes(15) // Add 15 minutes
LocalTime addSeconds = time.plusSeconds(30) // Add 30 seconds
LocalTime addNanoseconds = time.plusNanos(150_000_000) // Add 150.000.000ns (150ms)
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
Hay dos formas equivalentes de calcular la cantidad de unidad de tiempo entre dos LocalTime : (1)
until(Temporal, TemporalUnit) método until(Temporal, TemporalUnit) y (2)
TemporalUnit.between(Temporal, Temporal) .
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
https://riptutorial.com/es/home 660
long seconds1 = start.until(end, ChronoUnit.SECONDS); // 4220
long seconds2 = ChronoUnit.SECONDS.between(start, end); // 4220
Introducción
LocalTime es una clase inmutable y segura para subprocesos, utilizada para representar el
tiempo, a menudo vista como hora-min-seg. El tiempo está representado en nanosegundos de
precisión. Por ejemplo, el valor "13: 45.30.123456789" se puede almacenar en un LocalTime.
Esta clase no almacena ni representa una fecha o zona horaria. En cambio, es una descripción
de la hora local como se ve en un reloj de pared. No puede representar un instante en la línea de
tiempo sin información adicional, como un desplazamiento o una zona horaria. Esta es una clase
basada en valores, el método igual debe usarse para comparaciones.
Campos
MAX: el tiempo local máximo admitido, '23: 59: 59.999999999 '. Medianoche, min, mediodía
now (), now (Clock clock), now (ZoneId zone), parse (CharSequence text)
https://riptutorial.com/es/home 661
También puede agregar / restar horas, minutos o segundos de cualquier objeto de LocalTime.
now.plusHours(1L);
now1.minusMinutes(20L);
https://riptutorial.com/es/home 662
Capítulo 94: HttpURLConnection
Observaciones
• El uso de HttpUrlConnection en Android requiere que agregue el permiso de Internet a su
aplicación (en AndroidManifest.xml ).
• También hay otros clientes y bibliotecas HTTP de Java, como OkHttp de Square, que son
más fáciles de usar y pueden ofrecer un mejor rendimiento o más funciones.
Examples
Obtener el cuerpo de respuesta de una URL como una cadena
in.close();
return response.toString();
}
Esto descargará los datos de texto de la URL especificada y los devolverá como una cadena.
https://riptutorial.com/es/home 663
• Luego, cree InputStream basándose en el código de respuesta (para el manejo de errores)
• Luego, cree un BufferedReader que nos permita leer el texto de InputStream que obtenemos
de la conexión.
Notas:
• Este método arrojará una IoException en caso de error (como un error de red o sin conexión
a Internet), y también lanzará una excepción MalformedUrlException no verificada si la URL
dada no es válida.
• Puede utilizarse para leer desde cualquier URL que devuelva texto, como páginas web
(HTML), API REST que devuelvan JSON o XML, etc.
Uso:
Es muy simple:
Datos POST
public static void post(String url, byte [] data, String contentType) throws IOException {
HttpURLConnection connection = null;
OutputStream out = null;
InputStream in = null;
try {
connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestProperty("Content-Type", contentType);
connection.setDoOutput(true);
out = connection.getOutputStream();
out.write(data);
out.close();
in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
in.close();
} finally {
if (connection != null) connection.disconnect();
if (out != null) out.close();
https://riptutorial.com/es/home 664
if (in != null) in.close();
}
}
Esto enviará los datos a la URL especificada y luego leerá la respuesta línea por línea.
Cómo funciona
• Como de costumbre obtenemos el HttpURLConnection desde una URL .
• Establezca el tipo de contenido usando setRequestProperty , por defecto es application/x-
www-form-urlencoded
• setDoOutput(true) le dice a la conexión que enviaremos datos.
• Luego obtenemos el OutputStream llamando a getOutputStream() y escribimos datos en él. No
olvides cerrarla una vez que hayas terminado.
• Por fin leemos la respuesta del servidor.
Eliminar recurso
public static void delete (String urlString, String contentType) throws IOException {
HttpURLConnection connection = null;
try {
URL url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setRequestMethod("DELETE");
connection.setRequestProperty("Content-Type", contentType);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) connection.disconnect();
}
}
https://riptutorial.com/es/home 665
Cómo funciona
• obtenemos la HttpURLConnection desde una URL .
• Establezca el tipo de contenido usando setRequestProperty , por defecto es application/x-
www-form-urlencoded
• setDoInput(true) le dice a la conexión que tenemos la intención de usar la conexión URL
para la entrada.
• setRequestMethod("DELETE") para realizar HTTP DELETE
/**
* Checks if a resource exists by sending a HEAD-Request.
* @param url The url of a resource which has to be checked.
* @return true if the response code is 200 OK.
*/
public static final boolean checkIfResourceExists(URL url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("HEAD");
int code = conn.getResponseCode();
conn.disconnect();
return code == 200;
}
Explicación:
Si solo está comprobando si existe un recurso, es mejor usar una solicitud HEAD que un GET.
Esto evita la sobrecarga de transferir el recurso.
Tenga en cuenta que el método solo devuelve true si el código de respuesta es 200 . Si anticipa
respuestas de redireccionamiento (es decir, 3XX), entonces es posible que el método deba
mejorarse para cumplirlas.
Ejemplo:
checkIfResourceExists(new URL("http://images.google.com/")); // true
checkIfResourceExists(new URL("http://pictures.google.com/")); // false
https://riptutorial.com/es/home 666
Capítulo 95: Implementaciones del sistema
de plugin Java
Observaciones
Si usa un IDE y / o un sistema de compilación, es mucho más fácil configurar este tipo de
proyecto. Crea un módulo de aplicación principal, luego el módulo API, luego crea un módulo de
complemento y lo hace dependiente del módulo API o de ambos. A continuación, configure dónde
se colocarán los artefactos del proyecto; en nuestro caso, los archivos compilados de
complementos se pueden enviar directamente al directorio de "complementos", evitando así
realizar movimientos manuales.
Examples
Utilizando URLClassLoader
Hay varias formas de implementar un sistema de complementos para una aplicación Java. Una
de las más sencillas es usar URLClassLoader . El siguiente ejemplo involucrará un poco de
código JavaFX.
Supongamos que tenemos un módulo de una aplicación principal. Se supone que este módulo
carga complementos en forma de archivos jar de la carpeta 'complementos'. Código inicial:
package main;
package main;
https://riptutorial.com/es/home 667
public interface Plugin
{
default void initialize()
{
System.out.println("Initialized "+this.getClass().getName());
}
default String name(){return getClass().getSimpleName();}
}
Queremos cargar clases que implementen esta interfaz, así que primero necesitamos filtrar los
archivos que tienen una extensión '.jar':
A continuación, creamos una instancia de URLClassLoader e iteramos sobre los nombres de las
clases, creando instancias que implementan la interfaz del complemento :
https://riptutorial.com/es/home 668
Plugin plugin=(Plugin) cls.newInstance(); //instantiating the Plugin
plugins.add(plugin);
break;
}
}
}
catch (Exception e){e.printStackTrace();}
});
package main;
public class MainApplication extends Application
{
static HashSet<Plugin> plugins=new HashSet<>();
@Override
public void start(Stage primaryStage) throws Exception
{
File pluginDirectory=new File("plugins");
if(!pluginDirectory.exists())pluginDirectory.mkdir();
File[] files=pluginDirectory.listFiles((dir, name) -> name.endsWith(".jar"));
VBox loadedPlugins=new VBox(6);
loadedPlugins.setAlignment(Pos.CENTER);
if(files!=null && files.length>0)
{
ArrayList<String> classes=new ArrayList<>();
ArrayList<URL> urls=new ArrayList<>(files.length);
for(File file:files)
{
JarFile jar=new JarFile(file);
jar.stream().forEach(jarEntry -> {
if(jarEntry.getName().endsWith(".class"))
{
classes.add(jarEntry.getName());
}
});
URL url=file.toURI().toURL();
urls.add(url);
}
URLClassLoader urlClassLoader=new URLClassLoader(urls.toArray(new
URL[urls.size()]));
classes.forEach(className->{
try
{
Class
cls=urlClassLoader.loadClass(className.replaceAll("/",".").replace(".class",""));
Class[] interfaces=cls.getInterfaces();
for(Class intface:interfaces)
{
if(intface.equals(Plugin.class))
{
https://riptutorial.com/es/home 669
Plugin plugin=(Plugin) cls.newInstance();
plugins.add(plugin);
break;
}
}
}
catch (Exception e){e.printStackTrace();}
});
if(!plugins.isEmpty())loadedPlugins.getChildren().add(new Label("Loaded
plugins:"));
plugins.forEach(plugin -> {
plugin.initialize();
loadedPlugins.getChildren().add(new Label(plugin.name()));
});
}
Rectangle2D screenbounds=Screen.getPrimary().getVisualBounds();
Scene scene=new
Scene(loadedPlugins,screenbounds.getWidth()/2,screenbounds.getHeight()/2);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] a)
{
launch(a);
}
}
Vamos a crear dos complementos. Obviamente, la fuente del complemento debe estar en un
módulo separado.
package plugins;
import main.Plugin;
Segundo complemento:
package plugins;
import main.Plugin;
Estos complementos deben estar empaquetados en tarros estándar: este proceso depende de su
IDE u otras herramientas.
https://riptutorial.com/es/home 670
Cuando Jars se coloque en 'plugins' directamente, MainApplication los detectará y creará las
clases apropiadas.
https://riptutorial.com/es/home 671
Capítulo 96: InputStreams y OutputStreams
Sintaxis
• int read (byte [] b) lanza IOException
Observaciones
Tenga en cuenta que la mayoría de las veces NO usa InputStream s directamente, sino que usa
BufferedStream s, o similar. Esto se debe a que InputStream lee desde la fuente cada vez que se
llama al método de lectura. Esto puede causar un uso significativo de la CPU en contextos que
entran y salen del kernel.
Examples
Leyendo InputStream en una cadena
A veces es posible que desee leer la entrada de bytes en una cadena. Para hacer esto, tendrá
que encontrar algo que convierta entre byte y los puntos de código UTF-16 "Java nativos"
utilizados como caracteres char . Eso se hace con un InputStreamReader .
Para acelerar un poco el proceso, es "habitual" asignar un búfer, de modo que no tengamos
demasiada sobrecarga al leer desde la entrada.
Java SE 7
https://riptutorial.com/es/home 672
OutputStream stream = object.getOutputStream();
byte b = 0x00;
stream.write( b );
stream.write( bytes );
int offset = 1;
int length = 2;
byte[] bytes = new byte[] { 0xFF, 0x00, 0x00, 0xFF };
Cierre de arroyos
La mayoría de las transmisiones deben cerrarse cuando haya terminado con ellas, de lo contrario
podría introducir una pérdida de memoria o dejar un archivo abierto. Es importante que las
transmisiones estén cerradas incluso si se lanza una excepción.
Java SE 7
Recuerde: try-with-resources garantiza que los recursos se han cerrado cuando se sale del
bloque, ya sea que ocurra con el flujo de control habitual o debido a una excepción.
Java SE 6
A veces, intentar con recursos no es una opción, o quizás esté soportando una versión anterior de
Java 6 o anterior. En este caso, el manejo adecuado es utilizar un finally de bloque:
FileWriter fw = null;
BufferedWriter bw = null;
PrintWriter out = null;
try {
fw = new FileWriter("myfile.txt");
bw = new BufferedWriter(fw);
https://riptutorial.com/es/home 673
out = new PrintWriter(bw);
out.println("the text");
out.close();
} catch (IOException e) {
//handle this however you want
}
finally {
try {
if(out != null)
out.close();
} catch (IOException e) {
//typically not much you can do here...
}
}
Tenga en cuenta que cerrar una secuencia de envoltura también cerrará su secuencia
subyacente. Esto significa que no puede envolver una secuencia, cerrar la envoltura y luego
continuar usando la secuencia original.
Ejemplo -
OutputStream y InputStream tienen muchas clases diferentes, cada una de ellas con una
funcionalidad única. Al envolver un flujo alrededor de otro, obtiene la funcionalidad de ambos
flujos.
Puedes envolver un flujo cualquier cantidad de veces, solo toma nota del pedido.
Combinaciones utiles
Escribir caracteres en un archivo mientras se usa un búfer
https://riptutorial.com/es/home 674
Comprimir y cifrar datos antes de escribir en un archivo mientras se usa un búfer
DeflaterOutputStream /
Realiza la compresión de datos.
DeflaterInputStream
InflaterOutputStream /
Realiza descompresión de datos.
InflaterInputStream
CipherOutputStream /
Cifra / descifra datos.
CipherInputStream
https://riptutorial.com/es/home 675
Ejemplo de DataInputStream
package com.streams;
import java.io.*;
public class DataStreamDemo {
public static void main(String[] args) throws IOException {
InputStream input = new FileInputStream("D:\\datastreamdemo.txt");
DataInputStream inst = new DataInputStream(input);
int count = input.available();
byte[] arr = new byte[count];
inst.read(arr);
for (byte byt : arr) {
char ki = (char) byt;
System.out.print(ki+"-");
}
}
}
https://riptutorial.com/es/home 676
Capítulo 97: Instalando Java (Edición
Estándar)
Introducción
Esta página de documentación brinda acceso a las instrucciones para instalar java standard
edition en Windows con Windows , Linux y macOS .
Examples
Configurando% PATH% y% JAVA_HOME% después de instalar en Windows
Suposiciones
• Se ha instalado un JDK de Oracle.
• El JDK se instaló en el directorio predeterminado.
Pasos de configuración
1. Abra el Explorador de Windows.
3. En la ventana recién abierta del Panel de control, haga clic izquierdo en Configuración
avanzada del sistema que debería estar en la esquina superior izquierda. Esto abrirá la
ventana Propiedades del sistema .
https://riptutorial.com/es/home 677
4. En la pestaña Avanzado de Propiedades del sistema, seleccione el botón Variables de
entorno ... en la esquina inferior derecha de la ventana.
5. Agregue una Nueva Variable del Sistema haciendo clic en el botón Nuevo ... en Variables
del Sistema con el nombre JAVA_HOME y cuyo valor es la ruta al directorio donde se instaló el
JDK. Después de ingresar estos valores, presione OK .
6. Desplácese hacia abajo en la lista de Variables del sistema y seleccione la variable Path .
Es mejor agregarlo al principio de la línea porque el software de Oracle se utiliza para registrar su
propia versión de Java en la Path . Esto hará que su versión sea ignorada si ocurre después de la
declaración de Oracle.
Revisa tu trabajo
1. Abra el símbolo del sistema haciendo clic en Inicio, luego escriba cmd y presione Enter .
2. Introduzca javac -version en el indicador. Si tuvo éxito, la versión del JDK se imprimirá en la
pantalla.
Nota: Si tiene que volver a intentarlo, cierre el indicador antes de verificar su trabajo. Esto obligará
a las ventanas a obtener la nueva versión de Path .
Ha habido muchas versiones de Java desde la versión original de Java 1.0 en 1995. (Consulte el
historial de la versión de Java para obtener un resumen). Sin embargo, la mayoría de las
versiones han pasado sus fechas oficiales de fin de vida. Esto significa que el proveedor
(generalmente Oracle ahora) ha dejado de desarrollar un nuevo desarrollo para la versión y ya no
proporciona parches públicos / gratuitos para cualquier error o problema de seguridad. (Las
versiones de parches privados suelen estar disponibles para personas / organizaciones con un
contrato de soporte; póngase en contacto con la oficina de ventas de su proveedor).
https://riptutorial.com/es/home 678
En general, la versión de Java SE recomendada para uso será la última actualización de la última
versión pública. Actualmente, esto significa la última versión disponible de Java 8. El lanzamiento
público de Java 9 está programado para 2017. (Java 7 ha pasado su fin de vida y el último
lanzamiento público fue en abril de 2015. No se recomiendan los lanzamientos de Java 7 y
anteriores).
Esta recomendación se aplica a todos los nuevos desarrollos de Java, y cualquiera que esté
aprendiendo Java. También se aplica a las personas que solo desean ejecutar el software Java
proporcionado por un tercero. En términos generales, el código Java bien escrito funcionará en
una versión más nueva de Java. (Pero consulte las notas de la versión del software y póngase en
contacto con el autor / proveedor / proveedor si tiene dudas).
Si está trabajando en una base de código Java más antigua, le recomendamos que se asegure
de que su código se ejecute en la última versión de Java. Decidir cuándo comenzar a usar las
características de las nuevas versiones de Java es más difícil, ya que esto afectará su capacidad
para brindar asistencia a los clientes que no pueden o no quieren su instalación de Java.
El nombre de la versión de Java es un poco confuso. En realidad, hay dos sistemas de nombres y
numeración, como se muestra en esta tabla:
... ...
jdk-1.6 Java SE 6
jdk-1.7 Java SE 7
jdk-1.8 Java SE 8
1 - Parece que Oracle intenta romper su práctica anterior de usar un esquema de "número de versión semántica" en
las cadenas de la versión de Java. Queda por ver si van a seguir con esto.
La "SE" en los nombres de marketing se refiere a la edición estándar. Esta es la versión base
para ejecutar Java en la mayoría de las computadoras portátiles, PC y servidores (aparte de
Android).
https://riptutorial.com/es/home 679
Hay otras dos ediciones oficiales de Java: "Java ME" es la Micro Edition, y "Java EE" es la
Enterprise Edition. El Android de Java también es significativamente diferente de Java SE. Java
ME, Java EE y Android Java están fuera del alcance de este tema.
1.8.0_101-b13
Esto dice JDK 1.8.0, Actualización 101, Compilación # 13. Oracle se refiere a esto en las notas de
la versión como:
Una instalación de JDK y un editor de texto son lo mínimo para el desarrollo de Java. (Es bueno
tener un editor de texto que pueda resaltar la sintaxis de Java, pero puede prescindir).
Sin embargo, para trabajos de desarrollo serio, se recomienda que también use lo siguiente:
Como regla general, el procedimiento es abrir la ventana del terminal y ejecutar los comandos
que se muestran a continuación. (Se supone que tiene acceso suficiente para ejecutar comandos
como usuario "raíz" ... que es lo que hace el comando sudo . Si no lo hace, hable con los
administradores de su sistema.)
Se recomienda usar el administrador de paquetes porque (generalmente) hace que sea más fácil
mantener su instalación de Java actualizada.
apt-get
https://riptutorial.com/es/home 680
, distribuciones de Linux basadas en Debian (Ubuntu, etc.)
Nota: para configurar automáticamente las variables de entorno de Java 8, puede instalar el
siguiente paquete:
Si prefiere crear el archivo .deb desde el archivo .tar.gz descargado desde Oracle, haga lo
siguiente (suponiendo que haya descargado el ./<jdk>.tar.gz .tar.gz a ./<jdk>.tar.gz ):
dnf , fedora
En las últimas versiones de Fedora, no hay paquetes para instalar Java 7 y versiones anteriores.
Gentoo Linux
La guía de Gentoo Java es mantenida por el equipo de Gentoo Java y mantiene una página wiki
https://riptutorial.com/es/home 681
actualizada que incluye los paquetes de portage correctos y los indicadores USE necesarios.
1. Descargue el archivo de archivo de Oracle apropiado ("tar.gz") para la versión deseada del
sitio de descargas de Oracle Java .
Solo los JDK y JRE de Oracle están disponibles para las plataformas Windows. El procedimiento
de instalación es sencillo:
Una forma alternativa de instalar Java en Windows usando el símbolo del sistema es usar
Chocolately:
2. Abra una instancia de cmd, por ejemplo, presione Win + R y luego escriba "cmd" en la
ventana "Ejecutar" seguido de una entrada.
https://riptutorial.com/es/home 682
3. En su instancia de cmd, ejecute el siguiente comando para descargar e instalar un JDK de
Java 8:
Hay casos en los que es posible que desee instalar JDK / JRE en un sistema con privilegios
limitados, como una máquina virtual, o tal vez desee instalar y utilizar múltiples versiones o
arquitecturas (x64 / x86) de JDK / JRE. Los pasos siguen siendo los mismos hasta el momento en
que descarga el instalador (.EXE). Los pasos posteriores son los siguientes (los pasos son
aplicables para JDK / JRE 7 y versiones posteriores, para versiones anteriores son ligeramente
diferentes en los nombres de carpetas y archivos):
1. Mueva el archivo a una ubicación adecuada donde desee que sus archivos binarios de Java
residan permanentemente.
3. Con 7-Zip, extraiga los archivos del instalador de Java EXE a la ubicación.
cd .rsrc\JAVA_CAB10
extrac32 111
6. Esto creará un archivo tools.zip en esa ubicación. Extraiga el tools.zip con 7-Zip para que
los archivos que contiene se creen ahora en las tools del mismo directorio.
cd tools
De esta manera, puede instalar cualquier versión de JDK / JRE que necesite instalar
simultáneamente.
https://riptutorial.com/es/home 683
Oracle Java 7 y Java 8
Java 7 y Java 8 para macOS están disponibles en Oracle. Esta página de Oracle responde
muchas preguntas sobre Java para Mac. Tenga en cuenta que Java 7 anterior a 7u25 ha sido
deshabilitado por Apple por razones de seguridad.
En general, Oracle Java (versión 7 y posterior) requiere un Mac basado en Intel que ejecute
macOS 10.7.3 o posterior.
Los instaladores Java 7 & 8 JDK y JRE para macOS se pueden descargar desde el sitio web de
Oracle:
/Library/Java/JavaVirtualMachines/<version>.jdk/Contents/Home
Las siguientes funciones se pueden agregar al ~/.bash_profile (si usa el shell Bash
predeterminado) para facilitar su uso:
function java_version {
echo 'java -version';
}
function java_set {
if [[ $1 == "6" ]]
then
export JAVA_HOME='/usr/libexec/java_home -v 1.6';
echo "Setting Java to version 6..."
echo "$JAVA_HOME"
elif [[ $1 == "7" ]]
then
export JAVA_HOME='/usr/libexec/java_home -v 1.7';
echo "Setting Java to version 7..."
echo "$JAVA_HOME"
elif [[ $1 == "8" ]]
then
export JAVA_HOME='/usr/libexec/java_home -v 1.8';
echo "Setting Java to version 8..."
https://riptutorial.com/es/home 684
echo "$JAVA_HOME"
fi
}
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
Tenga en cuenta que Java 6 pasó su final de vida hace mucho tiempo, por lo que se recomienda
actualizar a una versión más nueva. Hay más información sobre la reinstalación de Apple Java 6
en el sitio web de Oracle.
Usando Alternativas
Muchas distribuciones de Linux utilizan el comando de alternatives para cambiar entre diferentes
versiones de un comando. Puede usar esto para cambiar entre diferentes versiones de Java
instaladas en una máquina.
$ JDK=/Data/jdk1.8.0_67
2. Use alternatives --install para agregar los comandos en el SDK de Java a las alternativas:
Y así.
Ahora puede cambiar entre diferentes versiones de un comando de Java de la siguiente manera:
Selection Command
-----------------------------------------------
*+ 1 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.101-1.b14.fc23.x86_64/bin/javac
2 /Data/jdk1.8.0_67/bin/javac
https://riptutorial.com/es/home 685
Para obtener más información sobre el uso de alternatives , consulte la entrada manual de
alternativas (8) .
$ archlinux-java status
Available Java environments:
java-7-openjdk (default)
java-8-openjdk/jre
P.ej:
Después de instalar un SDK de Java, es recomendable verificar que esté listo para usar. Puede
hacer esto ejecutando estos dos comandos, usando su cuenta de usuario normal:
$ java -version
$ javac -version
https://riptutorial.com/es/home 686
Configurando PATH directamente
Si no hay java o javac en la ruta de búsqueda en este momento, la solución simple es agregarla a
la ruta de búsqueda.
Primero, encuentre dónde instaló Java; ver ¿Dónde se instaló Java? Abajo si tienes dudas.
Luego, asumiendo que bash es su shell de comando, use un editor de texto para agregar las
siguientes líneas al final de ~/.bash_profile o ~/.bashrc (si usa Bash como su shell).
JAVA_HOME=<installation directory>
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME
export PATH
... reemplazando <installation directory> con la ruta para su directorio de instalación de Java.
Tenga en cuenta que lo anterior supone que el directorio de instalación contiene un directorio bin
y que el directorio bin contiene los comandos java y javac que está intentando usar.
A continuación, busque el archivo que acaba de editar para que se actualicen las variables de
entorno para su shell actual.
$ source ~/.bash_profile
A continuación, repita las comprobaciones de las versiones java y javac . Si todavía hay
problemas, utilice which java y which javac para verificar que ha actualizado correctamente las
variables de entorno.
Finalmente, cierre la sesión y vuelva a iniciar sesión para que las variables de entorno
actualizadas coincidan con todos sus shells. Ahora deberías haber terminado.
Comprobando Alternativas
Si java -version o javac -version funcionó pero dio un número de versión inesperado, debe
verificar de dónde provienen los comandos. Usa which y ls -l para encontrar esto como sigue:
$ ls -l `which java`
Si la salida se ve así,
entonces se está utilizando la alternatives cambio de versión. Debe decidir si continuar usándolo
o simplemente anularlo configurando la PATH directamente.
https://riptutorial.com/es/home 687
¿Dónde se instaló Java?
Java puede instalarse en una variedad de lugares, dependiendo del método de instalación.
Si tiene dificultades para encontrar el directorio de instalación, le sugerimos que use find (o
slocate ) para encontrar el comando. Por ejemplo:
Esto le proporciona las rutas para todos los archivos llamados java en su sistema. (La redirección
del error estándar a "/ dev / null" suprime los mensajes sobre archivos y directorios a los que no
puede acceder).
Siga los pasos a continuación para instalar Oracle JDK desde el último archivo tar:
1. Descargue el último archivo tar desde aquí : la última versión actual es Java SE
Development Kit 8u112.
sudo su
mkdir /opt/jdk
ls /opt/jdk
https://riptutorial.com/es/home 688
update-alternatives --install /usr/bin/javac javac /opt/jdk/jdk1.8.0_05/bin/javac 100
java -version
Rendimiento esperado:
https://riptutorial.com/es/home 689
Capítulo 98: Instrumentos de cuerda
Introducción
Las cadenas ( java.lang.String ) son fragmentos de texto almacenados en su programa. Las
cadenas no son un tipo de datos primitivo en Java , sin embargo, son muy comunes en los
programas Java.
En Java, las cadenas son inmutables, lo que significa que no se pueden cambiar. (Haga clic aquí
para obtener una explicación más detallada de la inmutabilidad.)
Observaciones
Como las cadenas de Java son inmutables , todos los métodos que manipulen una String
devolverán un nuevo objeto de String . No cambian la String original. Esto incluye los métodos
de subcadena y reemplazo que los programadores de C y C ++ esperan que muten el objeto
String destino.
Utilice un StringBuilder lugar de String si desea concatenar más de dos objetos String cuyos
valores no se pueden determinar en tiempo de compilación. Esta técnica es más eficaz que crear
nuevos objetos String y concatenarlos porque StringBuilder es mutable.
StringBuffertambién se puede utilizar para concatenar objetos String . Sin embargo, esta clase
tiene menos rendimiento porque está diseñada para ser segura para subprocesos y adquiere un
mutex antes de cada operación. Dado que casi nunca necesita seguridad para subprocesos al
concatenar cadenas, es mejor usar StringBuilder .
Si puede expresar una concatenación de cadenas como una sola expresión, entonces es mejor
usar el operador + . El compilador de Java convertirá una expresión que contenga +
concatenaciones en una secuencia eficiente de operaciones usando String.concat(...) o
StringBuilder . El consejo para usar StringBuilder solo se aplica explícitamente cuando la
concatenación involucra expresiones múltiples.
Todas las instancias de String se crean en el montón, incluso las instancias que corresponden a
https://riptutorial.com/es/home 690
literales de cadena. Lo especial de los literales de cadena es que la JVM garantiza que todos los
literales que son iguales (es decir, que constan de los mismos caracteres) estén representados
por un solo objeto de String (este comportamiento se especifica en JLS). Esto es implementado
por los cargadores de clases JVM. Cuando un cargador de clases carga una clase, explora los
literales de cadena que se utilizan en la definición de la clase, cada vez que ve una, comprueba si
ya existe un registro en el conjunto de cadenas para este literal (utilizando el literal como una
clave) . Si ya existe una entrada para el literal, se usa la referencia a una instancia de String
almacenada como el par para ese literal. De lo contrario, se crea una nueva instancia de String y
se almacena una referencia a la instancia para el literal (utilizado como clave) en el conjunto de
cadenas. (Véase también internado de cadena ).
Java SE 7
En las versiones de Java anteriores a Java 7, el grupo de cadenas se mantuvo en una parte
especial del montón conocido como "PermGen". Esta parte solo fue recogida ocasionalmente.
Java SE 7
Tenga en cuenta que los literales de cadena son implícitamente accesibles desde cualquier
método que los use. Esto significa que los objetos String correspondientes solo se pueden
recolectar si el código en sí es recolectado.
Hasta que Java 8, los objetos String se implementan como una matriz de caracteres UTF-16 (2
bytes por carácter). Hay una propuesta en Java 9 para implementar la String como una matriz de
bytes con un campo de marca de codificación para observar si la cadena está codificada como
bytes (LATIN-1) o caracteres (UTF-16).
Examples
Comparando cuerdas
Con el fin de comparar las cadenas para la igualdad, debe utilizar los métodos equals o equals
equalsIgnoreCase .
Por ejemplo, el siguiente fragmento de código determinará si las dos instancias de String son
iguales en todos los caracteres:
if (firstString.equals(secondString)) {
// Both Strings have the same content.
}
https://riptutorial.com/es/home 691
Demo en vivo
if (firstString.equalsIgnoreCase(secondString)) {
// Both Strings are equal, ignoring the case of the individual characters.
}
Demo en vivo
Tenga en cuenta que equalsIgnoreCase no le permite especificar una equalsIgnoreCase Locale . Por
ejemplo, si comparas las dos palabras "Taki" y "TAKI" en inglés, son iguales; sin embargo, en
turco son diferentes (en turco, la minúscula I es ı ). Para casos como este, convertir ambas
cadenas en minúsculas (o mayúsculas) con Locale y luego compararlas con equals es la solución.
System.out.println(firstString.toLowerCase(locale).equals(
secondString.toLowerCase(locale))); //prints false
Demo en vivo
En su lugar, use el String.equals(Object) , que comparará los objetos String en función de sus
valores. Para obtener una explicación detallada, consulte Pitfall: usar == para comparar cadenas .
https://riptutorial.com/es/home 692
A partir de Java 1.7, es posible comparar una variable de cadena con literales en una instrucción
de switch . Asegúrese de que la Cadena no sea nula, de lo contrario siempre lanzará una
NullPointerException . Los valores se comparan utilizando String.equals , es decir, String.equals
mayúsculas y minúsculas.
switch (stringToSwitch) {
case "a":
System.out.println("a");
break;
case "A":
System.out.println("A"); //the code goes here
break;
case "B":
System.out.println("B");
break;
default:
break;
}
Demo en vivo
"baz".equals(foo)
Java SE 7
Una alternativa más legible es usar Objects.equals() , que realiza una comprobación nula de
ambos parámetros: Objects.equals(foo, "baz") .
( Nota: es discutible si es mejor evitar las NullPointerExceptions en general, o dejar que ocurran y
luego corregir la causa raíz; ver aquí y aquí . Ciertamente, calificar de "mejor práctica" a la
estrategia de evitación no es justificable).
Ordenaciones de cuerdas
La clase String implementa Comparable<String> con el método String.compareTo (como se describe
https://riptutorial.com/es/home 693
al comienzo de este ejemplo). Esto hace que el orden natural de los objetos String sea sensible a
mayúsculas y minúsculas. La clase String proporciona una constante Comparator<String>
denominada CASE_INSENSITIVE_ORDER adecuada para una clasificación que no distingue entre
mayúsculas y minúsculas.
Esto significa que es seguro comparar referencias a dos literales de cadena utilizando == .
Además, lo mismo es cierto para las referencias a objetos String que se han producido utilizando
el método String.intern() .
Por ejemplo:
// The two string references point two strings that are equal
if (strObj.equals(str)) {
System.out.println("The strings are equal");
}
if (internedStr == str) {
System.out.println("The interned string and the literal are the same object");
}
Detrás de escena, el mecanismo de internado mantiene una tabla hash que contiene todas las
cadenas internadas que aún son accesibles . Cuando llama a intern() en una String , el método
busca el objeto en la tabla hash:
Es posible utilizar interning para permitir la comparación de cadenas utilizando == . Sin embargo,
hay problemas significativos al hacer esto; Vea Pitfall - Interning Strings para que pueda usar ==
https://riptutorial.com/es/home 694
es una mala idea para obtener detalles. No se recomienda en la mayoría de los casos.
El tipo de String proporciona dos métodos para convertir cadenas entre mayúsculas y
minúsculas:
Estos dos métodos devuelven las cadenas convertidas como nuevas instancias de String : los
objetos de String originales no se modifican porque la String es inmutable en Java. Vea esto para
más información sobre la inmutabilidad: Inmutabilidad de las cadenas en Java
Los caracteres no alfabéticos, como los dígitos y los signos de puntuación, no se ven afectados
por estos métodos. Tenga en cuenta que estos métodos también pueden tratar incorrectamente
con ciertos caracteres Unicode bajo ciertas condiciones.
Nota : estos métodos son sensibles a la configuración regional y pueden producir resultados
inesperados si se utilizan en cadenas que deben interpretarse independientemente de la
configuración regional. Algunos ejemplos son los identificadores de lenguaje de programación, las
claves de protocolo y las etiquetas HTML .
Por ejemplo, "TITLE".toLowerCase() en una configuración regional turca devuelve " tıtle ", donde ı
(\u0131) es el carácter LATIN SMALL LETTER DOTLESS I. Para obtener resultados correctos
para las cadenas no sensibles al entorno local, pase Locale.ROOT como parámetro al método de
conversión de casos correspondiente (por ejemplo, toLowerCase(Locale.ROOT) o
toUpperCase(Locale.ROOT) ).
Aunque el uso de Locale.ENGLISH también es correcto para la mayoría de los casos, el idioma
invariable es Locale.ROOT .
Puede encontrar una lista detallada de los caracteres Unicode que requieren una carcasa
especial en el sitio web de Unicode Consortium .
Para cambiar el caso de un carácter específico de una cadena ASCII, se puede utilizar el
siguiente algoritmo:
Pasos:
https://riptutorial.com/es/home 695
1. Declara una cuerda.
2. Introduzca la cadena.
3. Convertir la cadena en una matriz de caracteres.
4. Introduzca el carácter que se va a buscar.
5. Busque el carácter en la matriz de caracteres.
6. Si lo encuentra, verifique si el carácter está en minúscula o en mayúscula.
• Si está en mayúsculas, agregue 32 al código ASCII del carácter.
• Si es minúscula, resta 32 del código ASCII del carácter.
7. Cambiar el carácter original de la matriz de caracteres.
8. Convertir la matriz de caracteres de nuevo en la cadena.
Para verificar si una cadena en particular a está contenida en una cadena b o no, podemos usar el
método String.contains() con la siguiente sintaxis:
https://riptutorial.com/es/home 696
System.out.println(str1.contains(str2)); //prints true
System.out.println(str1.contains(str3)); //prints false
Para encontrar la posición exacta donde comienza una cadena dentro de otra cadena, use
String.indexOf() :
Para obtener la longitud de un objeto String , llame al método length() . La longitud es igual al
número de unidades de código UTF-16 (caracteres) en la cadena.
Un char en una cadena es el valor UTF-16. Los puntos de código Unicode cuyos valores son ≥
0x1000 (por ejemplo, la mayoría de los emojis) usan dos posiciones char. Para contar el número
de puntos de código Unicode en una cadena, independientemente de si cada punto de código se
ajusta a un valor de char UTF-16, puede usar el método codePointCount :
https://riptutorial.com/es/home 697
También puede usar un flujo de puntos de código, a partir de Java 8:
Subcadenas
Las subcadenas también se pueden aplicar para dividir y agregar / reemplazar caracteres en su
Cadena original. Por ejemplo, se enfrentó a una fecha china que contenía caracteres chinos, pero
desea almacenarla como una cadena de fecha de formato correcto.
Java SE 7
En las versiones JDK <7u6, el método de substring crea una instancia de una String que
comparte el mismo char[] respaldo char[] que la String original y tiene los campos internos de
offset y count establecidos en el inicio y la longitud del resultado. Dicha compartición puede
provocar pérdidas de memoria, que pueden evitarse llamando a la new String(s.substring(...))
para forzar la creación de una copia, después de lo cual el char[] puede ser recolectado como
basura.
Java SE 7
Desde JDK 7u6, el método de la substring siempre copia la matriz char[] subyacente completa,
haciendo que la complejidad sea lineal en comparación con la constante anterior pero
garantizando la ausencia de pérdidas de memoria al mismo tiempo.
https://riptutorial.com/es/home 698
System.out.println(str.charAt(0)); // "M"
System.out.println(str.charAt(1)); // "y"
System.out.println(str.charAt(2)); // " "
System.out.println(str.charAt(str.length-1)); // Last character "g"
Para obtener el enésimo carácter de una cadena, simplemente llame a charAt(n) en una String ,
donde n es el índice del carácter que desea recuperar
Dado que el nuevo separador de línea varía de una plataforma a otra (por ejemplo, \n en
sistemas similares a Unix o \r\n en Windows) a menudo es necesario tener una forma de acceso
independiente de la plataforma. En Java se puede recuperar de una propiedad del sistema:
System.getProperty("line.separator")
Java SE 7
Debido a que el nuevo separador de línea es tan comúnmente necesario, desde Java 7 en un
método de acceso directo que devuelve exactamente el mismo resultado que el código anterior,
está disponible:
System.lineSeparator()
Nota : ya que es muy poco probable que el nuevo separador de línea cambie durante la ejecución
del programa, es una buena idea almacenarlo en una variable final estática en lugar de
recuperarlo de la propiedad del sistema cada vez que sea necesario.
Cuando use String.format , use %n lugar de \n o '\ r \ n' para generar un nuevo separador de línea
independiente de la plataforma.
String name;
int age;
https://riptutorial.com/es/home 699
Si creas un nuevo objeto Person :
System.out.println(person.toString());
Person@7ab89d
Este es el resultado de la implementación del método toString() definido en la clase Object , una
superclase de Person . La documentación de Object.toString() establece:
El método toString para la clase Object devuelve una cadena que consiste en el
nombre de la clase de la que el objeto es una instancia, el carácter de signo at '@' y la
representación hexadecimal sin signo del código hash del objeto. En otras palabras,
este método devuelve una cadena igual al valor de:
Por lo tanto, para obtener resultados significativos, deberá anular el método toString() :
@Override
public String toString() {
return "My name is " + this.name + " and my age is " + this.age;
}
System.out.println(person);
Dividir cuerdas
Puede dividir una String en un carácter delimitador particular o una expresión regular , puede usar
el método String.split() que tiene la siguiente firma:
https://riptutorial.com/es/home 700
public String[] split(String regex)
Advertencia : No olvide que el parámetro siempre se trata como una expresión regular.
En el ejemplo anterior . se trata como el comodín de expresión regular que coincide con cualquier
carácter, y como cada carácter es un delimitador, el resultado es una matriz vacía.
< > - = ! ( ) [ ] { } \ ^ $ | ? * + .
Para dividir una cadena basada en uno de los delimitadores anteriores, necesita escapar de ellos
usando \\ o usar Pattern.quote() :
• Utilizando Pattern.quote() :
String s = "a|b|c";
String regex = Pattern.quote("|");
String[] arr = s.split(regex);
String s = "a|b|c";
https://riptutorial.com/es/home 701
String[] arr = s.split("\\|");
El parámetro límite controla el número de veces que se aplica el patrón y, por lo tanto, afecta la
longitud de la matriz resultante.
Si el límite n es mayor que cero, entonces el patrón se aplicará a lo sumo n - 1 veces, la longitud
de la matriz no será mayor que n , y la última entrada de la matriz contendrá toda la entrada más
allá del último delimitador coincidente.
Si n es negativo, entonces el patrón se aplicará tantas veces como sea posible y la matriz puede
tener cualquier longitud.
Si n es cero, el patrón se aplicará tantas veces como sea posible, la matriz puede tener cualquier
longitud y las cadenas vacías finales se descartarán.
Además del método split() , las cadenas también se pueden dividir utilizando un StringTokenizer
.
StringTokenizer es incluso más restrictivo que String.split() , y también un poco más difícil de
usar. Básicamente, está diseñado para extraer tokens delimitados por un conjunto fijo de
caracteres (dados como una String ). Cada personaje actuará como separador. Debido a esta
restricción, es aproximadamente el doble de rápido que String.split() .
String str = "the lazy fox jumped over the brown fence";
StringTokenizer tokenizer = new StringTokenizer(str);
while (tokenizer.hasMoreTokens()) {
System.out.println(tokenizer.nextToken());
}
Esto imprimirá:
the
lazy
fox
jumped
over
https://riptutorial.com/es/home 702
the
brown
fence
Esto imprimirá:
j
mp
d ov
r
Java SE 8
Para tener un control preciso sobre las uniones , puede usar la clase StringJoiner :
sj.add("foo");
sj.add("bar");
sj.add("foobar");
https://riptutorial.com/es/home 703
Hay una opción para definir prefijo y sufijo aquí también:
Cuerdas de inversión
Hay un par de maneras en que puedes revertir una cadena para hacerla al revés.
1. StringBuilder / StringBuffer:
System.out.println(code);
2. Matriz de caracteres:
// print reversed
System.out.println(new String(array));
import org.apache.commons.lang3.StringUtils;
String text = "One fish, two fish, red fish, blue fish";
De lo contrario, para lo mismo con las API de Java estándar, puede usar expresiones regulares:
https://riptutorial.com/es/home 704
import java.util.regex.Matcher;
import java.util.regex.Pattern;
String text = "One fish, two fish, red fish, blue fish";
System.out.println(countStringInString("fish", text)); // prints 4
System.out.println(countStringInString(",", text)); // prints 3
int stringOccurrences = 0;
while (matcher.find()) {
stringOccurrences++;
}
return stringOccurrences;
}
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s = s1 + s2 + s3; // abc
StringBuildertiene varios métodos sobrecargados para agregar diferentes tipos, por ejemplo,
para agregar un int lugar de una String . Por ejemplo, una implementación puede convertir:
String s1 = "a";
String s2 = "b";
String s = s1 + s2 + 2; // ab2
a lo siguiente:
Los ejemplos anteriores ilustran una operación de concatenación simple que se realiza
efectivamente en un solo lugar en el código. La concatenación involucra una sola instancia del
StringBuilder . En algunos casos, una concatenación se lleva a cabo de forma acumulativa, como
en un bucle:
https://riptutorial.com/es/home 705
String result = "";
for(int i = 0; i < array.length; i++) {
result += extractElement(array[i]);
}
return result;
En tales casos, la optimización del compilador generalmente no se aplica, y cada iteración creará
un nuevo objeto StringBuilder . Esto se puede optimizar al transformar explícitamente el código
para usar un único StringBuilder :
Si (y solo si) múltiples hilos están escribiendo en el mismo búfer, use StringBuffer , que es una
versión synchronized de StringBuilder . Pero debido a que normalmente solo un único hilo escribe
en un búfer, usualmente es más rápido usar StringBuilder sin sincronización.
Esto devuelve una nueva cadena que es string1 con string2 agregada al final. También puedes
usar el método concat () con cadenas literales, como en:
https://riptutorial.com/es/home 706
Dos formas de reemplazar: por expresiones regulares o por coincidencia exacta.
Nota: el objeto String original no se modificará, el valor de retorno conserva la String modificada.
Coincidencia exacta
Reemplazar el carácter único con otro carácter único:
String s = "popcorn";
System.out.println(s.replace('p','W'));
Resultado:
WoWcorn
Reemplaza cada subcadena de esta cadena que coincida con la secuencia de destino
literal con la secuencia de reemplazo literal especificada.
Resultado:
Regex
Nota : la agrupación utiliza el carácter $ para hacer referencia a los grupos, como $1 .
Reemplaza cada subcadena de esta cadena que coincide con la expresión regular
dada con el reemplazo dado.
https://riptutorial.com/es/home 707
String s = "spiral metal petal et al.";
System.out.println(s.replaceAll("(\\w*etal)","$1lica"));
Resultado:
Resultado:
El método trim() devuelve una nueva Cadena con los espacios en blanco iniciales y finales
eliminados.
Si trim una cadena que no tiene espacios en blanco para eliminar, se le devolverá la misma
instancia de cadena.
Tenga en cuenta que el método trim() tiene su propia noción de espacio en blanco , que difiere
de la noción utilizada por el método Character.isWhitespace() :
• Todos los caracteres de control ASCII con los códigos U+0000 a U+0020 se consideran
espacios en blanco y se eliminan mediante trim() . Esto incluye los caracteres U+0020
'SPACE' , U+0009 'CHARACTER TABULATION' , U+000A 'LINE FEED' y U+000D 'CARRIAGE RETURN' , pero
también los caracteres como U+0007 'BELL' .
• Los espacios en blanco de Unicode, como U+00A0 'NO-BREAK SPACE' o U+2003 'EM SPACE' no
son reconocidos por trim() .
Al igual que muchos objetos Java, todas las instancias de String se crean en el montón, incluso
literales. Cuando la JVM encuentra un literal de String que no tiene una referencia equivalente en
https://riptutorial.com/es/home 708
el montón, la JVM crea una instancia de String correspondiente en el montón y también almacena
una referencia a la instancia de String recién creada en el conjunto de cadenas. Cualquier otra
referencia al mismo literal de String se reemplaza con la instancia de String creada anteriormente
en el montón.
class Strings
{
public static void main (String[] args)
{
String a = "alpha";
String b = "alpha";
String c = new String("alpha");
true
true
true
true
https://riptutorial.com/es/home 709
Cuando usamos comillas dobles para crear una Cadena, primero busca Cadena con el mismo
valor en el conjunto de Cadenas, si se encuentra, simplemente devuelve la referencia, sino que
crea una nueva Cadena en el conjunto y luego devuelve la referencia.
Sin embargo, al utilizar un nuevo operador, obligamos a la clase String a crear un nuevo objeto
String en el espacio de almacenamiento dinámico. Podemos usar el método intern () para ponerlo
en el grupo o referirnos a otro objeto String del grupo de cadenas que tenga el mismo valor.
Java SE 7
Java SE 7
https://riptutorial.com/es/home 710
RFC: 6962931
Java SE 7
switch (myString.toLowerCase()) {
case "case1" :
...
break;
case "case2" :
...
break;
}
Tener cuidado
https://riptutorial.com/es/home 711
Capítulo 99: Interfaces
Introducción
Una interfaz es un tipo de referencia, similar a una clase, que se puede declarar utilizando la
palabra clave de la interface . Las interfaces solo pueden contener constantes, firmas de
métodos, métodos predeterminados, métodos estáticos y tipos anidados. Los cuerpos de los
métodos existen solo para los métodos predeterminados y los métodos estáticos. Al igual que las
clases abstractas, las interfaces no pueden ser instanciadas, solo pueden implementarse por
clases o extenderse por otras interfaces. La interfaz es una forma común de lograr una
abstracción completa en Java.
Sintaxis
• interfaz pública Foo {void foo (); / * cualquier otro método * /}
• interfaz pública Foo1 extiende Foo {void bar (); / * cualquier otro método * /}
• la clase pública Foo2 implementa Foo, Foo1 {/ * implementación de Foo y Foo1 * /}
Examples
Declarar e implementar una interfaz
Anular anotación
@Override
public String getSound() {
// Code goes here...
}
Esto obliga al compilador a verificar que estamos anulando e impide que el programa defina un
nuevo método o arruine la firma del método.
@Override
public String getSound() {
return "meow";
}
}
https://riptutorial.com/es/home 712
public class Dog implements Animal {
@Override
public String getSound() {
return "woof";
}
}
En el ejemplo, las clases Cat y Dog deben definir el método getSound() , ya que los métodos de una
interfaz son inherentemente abstractos (con la excepción de los métodos predeterminados).
@Override
public void eat(Food food) {
System.out.println("meows appreciatively");
}
}
Observe cómo la clase Cat debe implementar los métodos abstract heredados en ambas
interfaces. Además, observe cómo una clase puede implementar prácticamente tantas interfaces
como sea necesario (hay un límite de 65,535 debido a la limitación de JVM ).
https://riptutorial.com/es/home 713
Cat invalid2 = new FoodEater(); // Invalid
Nota:
1. Todas las variables declaradas en una interfaz son public static final
2. Todos los métodos declarados en una interfaz son public abstract (esta declaración es
válida solo a través de Java 7. Desde Java 8, se le permite tener métodos en una interfaz,
que no tienen por qué ser abstractos; estos métodos se conocen como métodos
predeterminados )
3. Las interfaces no pueden ser declaradas como final
4. Si más de una interfaz declara un método que tiene una firma idéntica, efectivamente se
trata como un solo método y no se puede distinguir de qué método de interfaz se
implementa
5. Se generará un archivo InterfaceName.class correspondiente para cada interfaz, luego de
la compilación
Una interfaz puede extender otra interfaz a través de la extends palabra clave.
Ahora, una clase que implemente ExtendedResourceService deberá implementar tanto getResource()
como updateResource() .
A diferencia de las clases, la extends palabra clave puede utilizarse para ampliar varias interfaces
(separados por comas) permitiendo combinaciones de interfaces en una nueva interfaz
https://riptutorial.com/es/home 714
Usando interfaces con genéricos
Supongamos que desea definir una interfaz que permita publicar / consumir datos hacia y desde
diferentes tipos de canales (por ejemplo, AMQP, JMS, etc.), pero desea poder cambiar los
detalles de la implementación ...
Ahora puedo crear una instancia de esa interfaz, pero como no tenemos implementaciones
predeterminadas para esos métodos, necesitará una implementación cuando la creamos:
@Override
public void publish(String data) {
System.out.println("Publishing " + data + " to " + channel);
}
@Override
public String consume() {
System.out.println("Consuming from " + channel);
return "some useful data";
}
@Override
public String RPCSubmit(String data) {
return "received " + data + " just now ";
}
};
También podemos hacer algo más útil con esa interfaz, digamos que queremos usarla para
envolver algunas funciones básicas de RabbitMQ:
https://riptutorial.com/es/home 715
this.queue = queue;
}
@Override
public void publish(String data) {
rabbit.basicPublish(exchange, queue, data.getBytes());
}
@Override
public String consume() {
return rabbit.basicConsume(exchange, queue);
}
@Override
public String RPCSubmit(String data) {
return rabbit.rpcPublish(exchange, queue, data);
}
Digamos que quiero usar esta interfaz de E / S ahora como una forma de contar las visitas a mi
sitio web desde mi último reinicio del sistema y luego poder mostrar el número total de visitas.
Puede hacer algo como esto:
import java.util.concurrent.atomic.AtomicLong;
@Override
public void publish(Integer count) {
websiteCounter.addAndGet(count);
}
@Override
public Long consume() {
return websiteCounter.get();
}
@Override
public Long RPCSubmit(Integer count) {
return websiteCounter.addAndGet(count);
}
https://riptutorial.com/es/home 716
// show data for stats counter page, but include that as a page view
System.out.println(counter.RPCSubmit(1)); // prints 6
Al implementar varias interfaces, no puede implementar la misma interfaz dos veces. Eso también
se aplica a las interfaces genéricas. Por lo tanto, el siguiente código no es válido y generará un
error de compilación:
interface Printer<T> {
void print(T value);
}
// Invalid!
class SystemPrinter implements Printer<Double>, Printer<Integer> {
@Override public void print(Double d){ System.out.println("Decimal: " + d); }
@Override public void print(Integer i){ System.out.println("Discrete: " + i); }
}
Las interfaces pueden ser extremadamente útiles en muchos casos. Por ejemplo, supongamos
que tenía una lista de animales y quería recorrer la lista, cada uno imprimiendo el sonido que
hacen.
Una forma de hacer esto sería usar interfaces. Esto permitiría que se llame al mismo método en
todas las clases
Cualquier clase que implements Animal también debe tener un método getSound() , pero todas
pueden tener implementaciones diferentes
https://riptutorial.com/es/home 717
}
Ahora tenemos tres clases diferentes, cada una de las cuales tiene un método getSound() . Debido
a que todas estas clases implement la interfaz Animal , que declara el método getSound() , cualquier
instancia de un Animal puede tener getSound() llamada.
dog.getSound(); // "Woof"
cat.getSound(); // "Meow"
bird.getSound(); // "Chirp"
Debido a que cada uno de estos es un Animal , incluso podríamos poner a los animales en una
lista, recorrerlos e imprimir sus sonidos.
Debido a que el orden de la matriz es Dog , Cat y luego Bird , "Woof Meow Chirp" se imprimirá en
la consola.
Las interfaces también se pueden utilizar como valor de retorno para las funciones. Por ejemplo,
devolver un Dog si la entrada es "perro" , Cat si la entrada es "gato" y Bird si es "pájaro" , y luego
imprimir el sonido de ese animal se podría hacer usando
https://riptutorial.com/es/home 718
Las interfaces también son útiles para la extensibilidad, porque si quieres agregar un nuevo tipo
de Animal , no necesitarás cambiar nada con las operaciones que realices en ellos.
Un método definido en una interface es por defecto public abstract . Cuando una abstract class
implementa una interface , los métodos que se definen en la interface no tienen que ser
implementado por el abstract class . Esto se debe a que una class que se declara abstract puede
contener declaraciones de métodos abstractos. Por lo tanto, es responsabilidad de la primera
subclase concreta implementar cualquier método abstract heredado de cualquier interfaz y / o la
abstract class .
@Override
public void eat() {
System.out.println("Dog eats some kibble.");
}
}
Desde Java 8 en adelante, es posible que una interface declare implementaciones default de
métodos, lo que significa que el método no será abstract , por lo tanto, no se obligará a ninguna
subclase concreta a implementar el método, sino que heredará la implementación default menos
que se anule.
Métodos predeterminados
Introducido en Java 8, los métodos predeterminados son una forma de especificar una
implementación dentro de una interfaz. Esto podría usarse para evitar la típica clase "Base" o
"Resumen" al proporcionar una implementación parcial de una interfaz y restringir la jerarquía de
subclases.
https://riptutorial.com/es/home 719
interface Observer {
void onAction(String a);
}
interface Observable{
public abstract List<Observer> getObservers();
@Override
public List<Observer> getObservers() {
return myObservers;
}
@Override
public void work(){
notify("Started work");
notify("Completed work");
}
w.addListener(new Observer() {
@Override
public void onAction(String a) {
System.out.println(a + " (" + new Date() + ")");
}
});
w.work();
}
}
https://riptutorial.com/es/home 720
Problema del diamante
El compilador en Java 8 es consciente del problema de diamante que se produce cuando una
clase implementa interfaces que contienen un método con la misma firma.
Para resolverlo, una clase de implementación debe anular el método compartido y proporcionar
su propia implementación.
interface InterfaceA {
public default String getName(){
return "a";
}
}
interface InterfaceB {
public default String getName(){
return "b";
}
}
@Override
public String getName() {
//Must provide its own implementation
return InterfaceA.super.getName() + InterfaceB.super.getName();
}
Todavía existe el problema de tener métodos con el mismo nombre y parámetros con diferentes
tipos de retorno, que no se compilarán.
Para evitar dividir todo el sistema, puede proporcionar una implementación de método
predeterminada cuando agrega un método a una interfaz. De esta manera, el sistema todavía se
compilará y las implementaciones reales se pueden hacer paso a paso.
https://riptutorial.com/es/home 721
Para obtener más información, consulte el tema Métodos predeterminados .
Modificadores en interfaces
(Ver Modificadores en Oracle Official Code Standard para el contexto y un enlace al documento
de Oracle real).
interface I {
public static final int VARIABLE = 0;
Variables
Todas las variables de interfaz son constantes implícitamente con modificadores public
(accesibles para todos), static (accesibles por nombre de interfaz) y final (deben inicializarse
durante la declaración):
Métodos
1. Todos los métodos que no proporcionan implementación son implícitamente public y
abstract .
Java SE 8
2. Todos los métodos con modificador static o default deben proporcionar implementación y
son implícitamente public .
Después de que se hayan aplicado todos los cambios anteriores, obtendremos lo siguiente:
https://riptutorial.com/es/home 722
interface I {
int VARIABLE = 0;
void method();
Los parámetros de tipo limitado le permiten establecer restricciones en los argumentos de tipo
genérico:
class SomeClass {
Un tipo de interfaz se puede vincular a un tipo que ya tenía un enlace. Esto se logra usando el
símbolo & :
interface SomeInterface {
Esto fortalece el enlace, lo que potencialmente requiere que los argumentos de tipo se deriven de
múltiples tipos.
Pero debe utilizarse con precaución. Los enlaces de interfaz múltiples suelen ser un signo de olor
de código , lo que sugiere que se debe crear un nuevo tipo que actúe como un adaptador para los
otros tipos:
https://riptutorial.com/es/home 723
}
https://riptutorial.com/es/home 724
Capítulo 100: Interfaces funcionales
Introducción
En Java 8+, una interfaz funcional es una interfaz que tiene solo un método abstracto (aparte de
los métodos de Object). Ver JLS §9.8. Interfaces funcionales .
Examples
Lista de interfaces funcionales estándar de Java Runtime Library por firma
() vacío Ejecutable
() T Proveedor
() booleano BooleanSupplier
() En t IntSupplier
() largo LongSupplier
() doble DoubleSupplier
https://riptutorial.com/es/home 725
Tipos de parámetros Tipo de retorno Interfaz
(En t) En t IntUnaryOperator
(largo) En t LongToIntFunction
(doble) En t DoubleToIntFunction
https://riptutorial.com/es/home 726
Tipos de parámetros Tipo de retorno Interfaz
https://riptutorial.com/es/home 727
Capítulo 101: Interfaz de herramientas JVM
Observaciones
Interfaz de herramientas JVM TM
Versión 1.2
http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html
Examples
Iterar sobre objetos accesibles desde objeto (Heap 1.0)
#include <vector>
#include <string>
#include "agent_util.hpp"
//this file can be found in Java SE Development Kit 8u101 Demos and Samples
//see http://download.oracle.com/otn-pub/java/jdk/8u101-b13-demos/jdk-8u101-windows-x64-
demos.zip
//jdk1.8.0_101.zip!\demo\jvmti\versionCheck\src\agent_util.h
/*
* Struct used for jvmti->SetTag(object, <pointer to tag>);
* http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#SetTag
*
*/
typedef struct Tag
{
jlong referrer_tag;
jlong size;
char* classSignature;
jint hashCode;
} Tag;
/*
* Utility function: jlong -> Tag*
*/
static Tag* pointerToTag(jlong tag_ptr)
{
if (tag_ptr == 0)
{
return new Tag();
}
return (Tag*)(ptrdiff_t)(void*)tag_ptr;
}
/*
* Utility function: Tag* -> jlong
*/
static jlong tagToPointer(Tag* tag)
{
https://riptutorial.com/es/home 728
return (jlong)(ptrdiff_t)(void*)tag;
}
/*
* Heap 1.0 Callback
* http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#jvmtiObjectReferenceCallback
*/
static jvmtiIterationControl JNICALL heabObjectReferencesCallback(
jvmtiObjectReferenceKind reference_kind,
jlong class_tag,
jlong size,
jlong* tag_ptr,
jlong referrer_tag,
jint referrer_index,
void* user_data)
{
//iterate only over reference field
if (reference_kind != JVMTI_HEAP_REFERENCE_FIELD)
{
return JVMTI_ITERATION_IGNORE;
}
auto tag_ptr_list = (std::vector<jlong>*)(ptrdiff_t)(void*)user_data;
//create and assign tag
auto t = pointerToTag(*tag_ptr);
t->referrer_tag = referrer_tag;
t->size = size;
*tag_ptr = tagToPointer(t);
//collect tag
(*tag_ptr_list).push_back(*tag_ptr);
return JVMTI_ITERATION_CONTINUE;
}
/*
* Main function for demonstration of Iterate Over Objects Reachable From Object
*
http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#IterateOverObjectsReachableFromObject
*
*/
void iterateOverObjectHeapReferences(jvmtiEnv* jvmti, JNIEnv* env, jobject object)
{
std::vector<jlong> tag_ptr_list;
*/
jvmti->IterateOverObjectsReachableFromObject(object, &heabObjectReferencesCallback,
(void*)&tag_ptr_list);
stdout_message("tag list size after call callback: %d\n", tag_ptr_list.size());
if (tag_ptr_list.size() > 0)
{
https://riptutorial.com/es/home 729
jint found_count = 0;
jlong* tags = &tag_ptr_list[0];
jobject* found_objects;
jlong* found_tags;
/*
* collect all tagged object (via *tag_ptr = pointer to tag )
* see
http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#GetObjectsWithTags
*/
jvmti->GetObjectsWithTags(tag_ptr_list.size(), tags, &found_count, &found_objects,
&found_tags);
stdout_message("found %d objects\n", found_count);
char* classSignature;
jclass found_object_class = env->GetObjectClass(found_object);
/*
* Get string representation of found_object_class
* see
http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#GetClassSignature
*/
jvmti->GetClassSignature(found_object_class, &classSignature, nullptr);
jint hashCode;
/*
* Getting hash code for found_object
* see
http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#GetObjectHashCode
*/
jvmti->GetObjectHashCode(found_object, &hashCode);
if (t->referrer_tag != 0)
{
stdout_message("referrer object %s#%d --> object %s#%d (size: %2d)\n",
rt->classSignature, rt->hashCode, t->classSignature, t->hashCode, t-
>size);
}
}
}
}
https://riptutorial.com/es/home 730
jvmtiEnv* jvmti;
/* Get JVMTI environment */
vm->GetEnv(reinterpret_cast<void **>(&jvmti), JVMTI_VERSION);
jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, nullptr);
return JNI_OK;
}
https://riptutorial.com/es/home 731
Capítulo 102: Interfaz de salida de cola
Introducción
Un Deque es una colección lineal que admite la inserción y eliminación de elementos en ambos
extremos.
El nombre deque es corto para "doble cola de espera" y generalmente se pronuncia "deck".
La interfaz de Deque es un tipo de datos abstracto más rico que tanto la Pila como la Cola porque
implementa pilas y colas al mismo tiempo
Observaciones
Los genéricos se pueden utilizar con Deque.
Cuando se utiliza un deque como una cola, se produce el comportamiento FIFO (primero en
entrar, primero en salir).
Para obtener más información sobre los métodos, consulte esta documentación.
Examples
Añadiendo elementos a Deque
https://riptutorial.com/es/home 732
//Retrieves and removes the head of the queue represented by this deque
Object headItem = deque.remove();
//Retrieves, but does not remove, the head of the queue represented by this deque
Object headItem = deque.element();
//Retrieves, but does not remove, the first element of this deque.
Object firstItem = deque.getFirst();
//Retrieves, but does not remove, the last element of this deque.
Object lastItem = deque.getLast();
//Using Iterator
Iterator iterator = deque.iterator();
while(iterator.hasNext(){
String Item = (String) iterator.next();
}
https://riptutorial.com/es/home 733
Capítulo 103: Interfaz fluida
Observaciones
Metas
Cuando se usa para construir objetos, las opciones disponibles para el llamante se pueden hacer
claramente y cumplir mediante controles en tiempo de compilación. Por ejemplo, considere el
siguiente árbol de opciones que representan pasos a lo largo de la ruta para construir un objeto
complejo:
A -> B
-> C -> D -> Done
-> E -> Done
-> F -> Done.
-> G -> H -> I -> Done.
Un constructor que utiliza una interfaz fluida permitiría a la persona que llama ver fácilmente qué
opciones están disponibles en cada paso. Por ejemplo, A -> B es posible, pero A -> C no es y
daría como resultado un error en tiempo de compilación.
Examples
Verdad - Marco de prueba de fluidez
En el estilo de programación fluido, devuelve this desde métodos fluidos (configuradores) que no
devolverían nada en un estilo de programación no fluido.
Esto le permite encadenar las diferentes llamadas de métodos, lo que hace que su código sea
más corto y más fácil de manejar para los desarrolladores.
https://riptutorial.com/es/home 734
public class Person {
private String firstName;
private String lastName;
https://riptutorial.com/es/home 735
return "I am " + firstName + " " + lastName;
}
La idea es devolver siempre algún objeto para permitir la construcción de una cadena de
llamadas a métodos y usar nombres de métodos que reflejen el habla natural. Este estilo fluido
hace que el código sea más legible.
https://riptutorial.com/es/home 736
Capítulo 104: Interfaz nativa de Java
Parámetros
Parámetro Detalles
Observaciones
La configuración de JNI requiere tanto de Java como de un compilador nativo. Dependiendo del
IDE y el sistema operativo, se requiere alguna configuración. Una guía para Eclipse se puede
encontrar aquí . Un tutorial completo se puede encontrar aquí .
• Compile los archivos fuente de Java ( .java ) en clases ( .class ) usando javac .
• Cree archivos de encabezado ( .h ) a partir de las clases de Java que contienen métodos
native utilizando javah . Estos archivos "instruyen" al código nativo de qué métodos es
responsable de implementar.
• Incluya los archivos de encabezado ( #include ) en los archivos fuente de C ++ ( .cpp ) que
implementan los métodos native .
• Compile los archivos fuente de C ++ y cree una biblioteca ( .dll ). Esta biblioteca contiene la
implementación del código nativo.
• Especifique la ruta de la biblioteca ( -Djava.library.path ) y -Djava.library.path en el archivo
fuente de Java ( System.loadLibrary(...) ).
Las devoluciones de llamada (Llamar a métodos Java desde código nativo) requieren especificar
un descriptor de método. Si el descriptor es incorrecto, se produce un error de tiempo de
ejecución. Debido a esto, es útil tener los descriptores creados para nosotros, esto se puede
hacer con javap -s .
Examples
Llamando a los métodos de C ++ desde Java
Los métodos estáticos y de miembro en Java se pueden marcar como nativos para indicar que su
implementación se encuentra en un archivo de biblioteca compartida. Tras la ejecución de un
método nativo, la JVM busca una función correspondiente en las bibliotecas cargadas (consulte
Cómo cargar bibliotecas nativas ), utilizando un esquema simple de identificación de nombres,
https://riptutorial.com/es/home 737
realiza la conversión de argumentos y la configuración de la pila, luego entrega el control al
código nativo.
Código Java
package com.example.jni;
Código C ++
Los archivos de encabezado que contienen declaraciones de funciones nativas deben generarse
utilizando la herramienta javah en las clases de destino. Ejecutando el siguiente comando en el
directorio de compilación:
// com_example_jni_JNIJava.hpp
#ifndef _Included_com_example_jni_JNIJava
#define _Included_com_example_jni_JNIJava
#ifdef __cplusplus
extern "C" { // This is absolutely required if using a C++ compiler
#endif
https://riptutorial.com/es/home 738
#ifdef __cplusplus
}
#endif
#endif
// com_example_jni_JNIJava.cpp
#include <iostream>
#include "com_example_jni_JNIJava.hpp"
Salida
Al ejecutar la clase de ejemplo anterior se obtiene el siguiente resultado:
Código Java
https://riptutorial.com/es/home 739
/*** com.example.jni.JNIJavaCallback.java ***/
package com.example.jni;
Código C ++
// com_example_jni_JNICppCallback.cpp
#include <iostream>
#include "com_example_jni_JNIJavaCallback.h"
Salida
Consiguió flotar desde C ++: 5.221
Obtuvo int desde C ++: 17
Obteniendo el descriptor
https://riptutorial.com/es/home 740
Los descriptores (o firmas de tipo interno ) se obtienen utilizando el programa javap en el archivo
.class compilado. Aquí está la salida de javap -p -s com.example.jni.JNIJavaCallback :
public com.example.jni.JNIJavaCallback();
descriptor: ()V
Las llamadas a System.loadLibrary son casi siempre estáticas para que ocurran durante la carga
de clases, asegurando que ningún método nativo pueda ejecutarse antes de que se haya cargado
la biblioteca compartida. Sin embargo, lo siguiente es posible:
...
Esto permite diferir la carga de la biblioteca compartida hasta que sea necesario, pero requiere un
cuidado especial para evitar java.lang.UnsatisfiedLinkError s.
https://riptutorial.com/es/home 741
Los archivos de la biblioteca compartida se buscan en las rutas definidas por la propiedad del
sistema java.library.path , que se pueden anular utilizando el argumento -Djava.library.path=
JVM en el tiempo de ejecución:
Tenga cuidado con los separadores de ruta del sistema: por ejemplo, Windows usa ; en lugar de
:
Tenga en cuenta que System.loadLibrary resuelve los nombres de archivo de la biblioteca de una
manera dependiente de la plataforma: el fragmento de código anterior espera un archivo llamado
libExample.so en Linux y Example.dll en Windows.
...
https://riptutorial.com/es/home 742
Capítulo 105: Invocación de método remoto
(RMI)
Observaciones
RMI requiere 3 componentes: cliente, servidor y una interfaz remota compartida. La interfaz
remota compartida define el contrato cliente-servidor especificando los métodos que debe
implementar un servidor. La interfaz debe ser visible para el servidor para que pueda implementar
los métodos; la interfaz debe ser visible para el cliente para que sepa qué métodos ("servicios")
proporciona el servidor.
Cualquier objeto que implemente una interfaz remota está destinado a asumir el rol de un
servidor. Como tal, una relación cliente-servidor en la que el servidor también puede invocar
métodos en el cliente es, de hecho, una relación servidor-servidor. Esto se denomina devolución
de llamada ya que el servidor puede devolver la llamada al "cliente". Teniendo esto en cuenta, es
aceptable utilizar el cliente de designación para los servidores que funcionan como tales.
La interfaz remota compartida es cualquier interfaz que se extiende a Remote . Un objeto que
funciona como un servidor experimenta lo siguiente:
En la configuración del proyecto, los proyectos de cliente y servidor no están relacionados, pero
cada uno especifica un proyecto compartido en su ruta de compilación. El proyecto compartido
contiene las interfaces remotas.
Examples
Cliente-Servidor: invocando métodos en una JVM desde otra
package remote;
import java.rmi.Remote;
import java.rmi.RemoteException;
https://riptutorial.com/es/home 743
El servidor que implementa la interfaz remota compartida:
package server;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import remote.RemoteServer;
@Override
public int stringToInt(String string) throws RemoteException {
try {
Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
Server server = new Server();
UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
reg.rebind("ServerName", server);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
package client;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import remote.RemoteServer;
try {
Registry reg = LocateRegistry.getRegistry();
server = (RemoteServer) reg.lookup("ServerName");
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
https://riptutorial.com/es/home 744
}
void callServer() {
try {
int i = server.stringToInt("120");
System.out.println("Client received: " + i);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Salida:
Visión general
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
https://riptutorial.com/es/home 745
public interface RemoteLogin extends Remote {
El servidor:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
El cliente:
package callbackRemote;
import java.rmi.Remote;
import java.rmi.RemoteException;
Las implementaciones
package callbackServer;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
@Override
public RemoteConnection login(String name, RemoteClient client) {
https://riptutorial.com/es/home 746
Connection connection = new Connection(name, client);
clients.put(name, client);
System.out.println(name + " logged in");
return connection;
}
try {
Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
LoginServer server = new LoginServer();
UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
reg.rebind("LoginServerName", server);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
El servidor:
package callbackServer;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
RemoteClient client;
String name;
this.client = client;
this.name = name;
try {
UnicastRemoteObject.exportObject(this, Registry.REGISTRY_PORT);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void unreferenced() {
try {
UnicastRemoteObject.unexportObject(this, true);
} catch (NoSuchObjectException e) {
e.printStackTrace();
}
}
@Override
public void logout() {
https://riptutorial.com/es/home 747
try {
UnicastRemoteObject.unexportObject(this, true);
} catch (NoSuchObjectException e) {
e.printStackTrace();
}
}
@Override
public String passInt(String recipient, int i) {
El cliente:
package callbackClient;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;
RemoteConnection connection;
String name, target;
this.name = name;
this.target = target;
}
https://riptutorial.com/es/home 748
if ("Client1".equals(client.name)) {
try {
client.connection.passInt(client.target, 120);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public void half(int i) throws RemoteException {
Ejecutando el ejemplo:
Las salidas aparecerán en 3 consolas ya que hay 3 JVM. Aquí están agrupados:
Este es un ejemplo simple de RMI con cinco clases Java y dos paquetes, servidor y cliente .
Paquete de servidor
PersonListInterface.java
https://riptutorial.com/es/home 749
*/
ArrayList<String> getPersonList() throws RemoteException;
}
PersonListImplementation.java
/**
* Implementation of "PersonListInterface"
* @throws RemoteException
*/
@Override
public ArrayList<String> getPersonList() throws RemoteException
{
ArrayList<String> personList = new ArrayList<String>();
personList.add("Peter Pan");
personList.add("Pippi Langstrumpf");
// add your name here :)
return personList;
}
}
Servidor.java
/**
* Register servicer to the known public methods
*/
private static void createServer() {
try {
// Register registry with standard port 1099
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
System.out.println("Server : Registry created.");
https://riptutorial.com/es/home 750
}
Paquete de cliente
PersonListLocal.java
/**
* Create a singleton instance
*/
private PersonListLocal() {
try {
// Lookup to the local running server with port 1099
final Registry registry = LocateRegistry.getRegistry("localhost",
Registry.REGISTRY_PORT);
return instance;
}
/**
* Returns the servers PersonList
*/
public ArrayList<String> getPersonList() {
if (instance != null) {
try {
return personList.getPersonList();
} catch (final RemoteException e) {
e.printStackTrace();
}
}
PersonTest.java
https://riptutorial.com/es/home 751
{
// get (local) PersonList
ArrayList<String> personList = PersonListLocal.getInstance().getPersonList();
Prueba tu aplicación
• Iniciar el método principal de Server.java. Salida:
Peter Pan
Pippi Langstrumpf
https://riptutorial.com/es/home 752
Capítulo 106: Iterador e iterable
Introducción
El java.util.Iterator es la interfaz estándar de Java SE para el objeto que implementa el patrón
de diseño del iterador. La interfaz java.lang.Iterable es para objetos que pueden proporcionar un
iterador.
Observaciones
Es posible iterar sobre una matriz utilizando el bucle for -each, aunque las matrices java no
implementan Iterable; la iteración se realiza mediante JVM utilizando un índice no accesible en
segundo plano.
Examples
Usando Iterable en for loop
Las clases que implementan Iterable<> interfaz se pueden utilizar en for bucles. En realidad, esto
es solo azúcar sintáctica para obtener un iterador del objeto y usarlo para obtener todos los
elementos secuencialmente; hace que el código sea más claro, más rápido de escribir, y menos
propenso a errores.
// foreach-like loop
for (Integer i: iterable) {
System.out.println(i);
}
Si bien el uso del bucle foreach (o "bucle extendido para") es simple, a veces es beneficioso usar
el iterador directamente. Por ejemplo, si desea generar un conjunto de valores separados por
https://riptutorial.com/es/home 753
comas, pero no quiere que el último elemento tenga una coma:
Esto es mucho más fácil y claro que tener una variable isLastEntry o hacer cálculos con el índice
de bucle.
Para crear su propio Iterable como con cualquier interfaz, simplemente implemente los métodos
abstractos en la interfaz. Para Iterable solo hay uno que se llama iterator() . Pero su tipo de
retorno Iterator es en sí mismo una interfaz con tres métodos abstractos. Puede devolver un
iterador asociado con alguna colección o crear su propia implementación personalizada:
@Override
public Iterator<Character> iterator() {
return new Iterator<Character>() {
char letter = 'a';
@Override
public boolean hasNext() {
return letter <= 'z';
}
@Override
public Character next() {
return letter++;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Doesn't make sense to remove a
letter");
}
};
}
}
Usar:
https://riptutorial.com/es/home 754
}
}
El nuevo Iterator debe venir con un estado que apunta al primer elemento, y cada llamada a la
siguiente actualiza su estado para apuntar a la siguiente. El hasNext() comprueba si el iterador
está al final. Si el iterador estuviera conectado a una colección modificable, entonces se podría
implementar el método opcional remove() del iterador para eliminar el elemento al que se apunta
actualmente desde la colección subyacente.
Salida:
Old Size : 5
New Size : 3
Tenga en cuenta que el código anterior es la forma segura de eliminar elementos al iterar una
colección típica. Si, por el contrario, intenta eliminar elementos de una colección como esta:
una colección típica (como ArrayList ) que proporciona a los iteradores una semántica de
iteradores de error rápido lanzará una ConcurrentModificationException .
El método remove() solo puede ser llamado (una vez) después de una llamada next() . Si se llama
antes de llamar a next() o si se llama dos veces después de la llamada next() , entonces la
llamada remove() lanzará una IllegalStateException .
https://riptutorial.com/es/home 755
La operación de remove se describe como una operación opcional ; Es decir, no todos los
iteradores lo permitirán. Los ejemplos en los que no se admite incluyen iteradores para
colecciones inmutables, vistas de solo lectura de colecciones o colecciones de tamaño fijo. Si se
llama a remove() cuando el iterador no admite la eliminación, lanzará una
UnsupportedOperationException .
https://riptutorial.com/es/home 756
Capítulo 107: JavaBean
Introducción
JavaBeans (TM) es un patrón para diseñar API de clase Java que permite que las instancias
(beans) se utilicen en diversos contextos y utilicen varias herramientas sin escribir explícitamente
el código Java. Los patrones consisten en convenciones para definir captadores y definidores
para propiedades , para definir constructores y para definir API de escucha de eventos.
Sintaxis
• Reglas de nombre de propiedad de JavaBean
• Si la propiedad no es un valor booleano, se debe obtener el prefijo del método getter. Por
ejemplo, getSize () es un nombre de obtención de JavaBeans válido para una propiedad
llamada "tamaño". Tenga en cuenta que no es necesario tener una variable denominada
tamaño. El nombre de la propiedad se deduce de los captadores y establecedores, no a
través de ninguna variable en su clase. Lo que devuelvas de getSize () depende de ti.
• Si la propiedad es booleana, el prefijo del método getter es get o es. Por ejemplo,
getStopped () o isStopped () son nombres válidos de JavaBeans para una propiedad
booleana.
• El prefijo del método setter debe ser establecido. Por ejemplo, setSize () es el nombre válido
de JavaBean para una propiedad denominada tamaño.
• Para completar el nombre de un método de obtención o establecimiento, cambie la primera
letra del nombre de la propiedad a mayúsculas y luego agréguela al prefijo apropiado
(obtener, es o establecer).
• Las firmas del método Setter deben marcarse como públicas, con un tipo de retorno nulo y
un argumento que represente el tipo de propiedad.
• Las firmas de los métodos de captación deben marcarse como públicas, no aceptar
argumentos y tener un tipo de retorno que coincida con el tipo de argumento del método de
establecimiento para esa propiedad.
• Reglas de nombre de escucha de JavaBean
• Los nombres de los métodos de escucha utilizados para "registrar" una escucha con un
origen de evento deben usar el prefijo agregar, seguido del tipo de escucha. Por ejemplo,
addActionListener () es un nombre válido para un método que un origen de evento tendrá
que permitir que otros se registren para eventos de acción.
• Los nombres de los métodos de escucha utilizados para eliminar ("anular el registro") un
oyente deben usar el prefijo eliminar, seguido del tipo de escucha (usando las mismas
reglas que el método de agregar registro).
• El tipo de escucha que se agregará o eliminará se debe pasar como el argumento al
método.
• Los nombres de los métodos de escucha deben terminar con la palabra "Escucha".
Observaciones
https://riptutorial.com/es/home 757
Para que una clase sea Java Bean debe seguir este estándar , en resumen:
• Todas sus propiedades deben ser privadas y solo accesibles a través de captadores y
configuradores.
• Debe tener un constructor público sin argumentos.
• Debe implementar la interfaz java.io.Serializable .
Examples
Bean Java Básico
public BasicJavaBean(){}
https://riptutorial.com/es/home 758
Capítulo 108: JAXB
Introducción
JAXB o Java Architecture for XML Binding (JAXB) es un marco de software que permite a los
desarrolladores de Java asignar clases de Java a representaciones XML. Esta página presentará
a los lectores a JAXB utilizando ejemplos detallados sobre sus funciones proporcionadas
principalmente para calcular y desalmar los objetos de Java en formato xml y viceversa.
Sintaxis
• JAXB.marshall (objeto, fileObjOfXML);
Parámetros
Parámetro Detalles
Observaciones
Usando la herramienta XJC disponible en el JDK, se puede generar automáticamente el código
Java para una estructura xml descrita en un esquema xml (archivo .xsd ), vea el tema XJC .
Examples
Escribir un archivo XML (ordenando un objeto)
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
Al utilizar la anotación XMLRootElement , podemos marcar una clase como elemento raíz de un
archivo XML.
https://riptutorial.com/es/home 759
import java.io.File;
import javax.xml.bind.JAXB;
try {
JAXB.marshal(user, new File("UserDetails.xml"));
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
} finally {
System.out.println("XML created");
}
}
}
marshal() se utiliza para escribir el contenido del objeto en un archivo XML. Aquí, user objeto de
user y un nuevo objeto de File se pasan como argumentos al marshal() .
En una ejecución exitosa, esto crea un archivo XML llamado UserDetails.xml en la ruta de clase
con el contenido a continuación.
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
Aquí hemos creado las variables y el nombre de la clase de acuerdo con los nodos XML. Para
https://riptutorial.com/es/home 760
XmlRootElement , usamos la anotación XmlRootElement en la clase.
Aquí se utiliza el método unmarshal() para analizar el archivo XML. Toma el nombre del archivo
XML y el tipo de clase como dos argumentos. Luego podemos usar los métodos de obtención del
objeto para imprimir los datos.
Cuando el formato XML deseado difiere del modelo de objeto Java, se puede usar una
implementación de XmlAdapter para transformar el objeto modelo en un objeto de formato xml y
viceversa. Este ejemplo muestra cómo colocar el valor de un campo en un atributo de un
elemento con el nombre del campo.
@XmlAccessorType(XmlAccessType.FIELD)
public static class NodeValueElement {
@XmlAttribute(name="attrValue")
String value;
public NodeValueElement() {
}
@Override
public NodeValueElement marshal(String v) throws Exception {
return new NodeValueElement(v);
}
https://riptutorial.com/es/home 761
@Override
public String unmarshal(NodeValueElement v) throws Exception {
if (v==null) return "";
return v.getValue();
}
}
@XmlRootElement(name="DataObject")
@XmlAccessorType(XmlAccessType.FIELD)
public static class DataObject {
String elementWithValue;
@XmlJavaTypeAdapter(value=ValueAsAttrXmlAdapter.class)
String elementWithAttribute;
}
System.out.println(xmlString);
}
}
@XmlAccessorType(XmlAccessType.FIELD)
static class AccessorExampleField {
public String field="value1";
@XmlAccessorType(XmlAccessType.NONE)
static class AccessorExampleNone {
public String field="value1";
https://riptutorial.com/es/home 762
}
@XmlAccessorType(XmlAccessType.PROPERTY)
static class AccessorExampleProperty {
public String field="value1";
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
static class AccessorExamplePublic {
public String field="value1";
Salida
Field:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleField>
<field>value1</field>
</accessorExampleField>
None:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleNone/>
Property:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleProperty>
<getter>getter</getter>
https://riptutorial.com/es/home 763
</accessorExampleProperty>
Public:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExamplePublic>
<field>value1</field>
<getter>getter</getter>
</accessorExamplePublic>
@XmlElement
private String field="field value";
@XmlAttribute
private String attribute="attr value";
@XmlAttribute(name="differentAttribute")
private String oneAttribute="other attr value";
@XmlElement(name="different name")
private String oneName="different name value";
@XmlTransient
private String transientField = "will not get serialized ever";
@XmlElement
public String getModifiedTransientValue() {
return transientField.replace(" ever", ", unless in a getter");
}
https://riptutorial.com/es/home 764
Es posible especificar un XmlAdapter ejemplo la Unmarshaller debe utilizar, que permite al usuario
utilizar XmlAdapter s con ningún constructor cero-arg y / o pasar los datos al adaptador.
Ejemplo
Clase de usuario
import java.awt.image.BufferedImage;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class User {
@XmlAttribute
public String getName() {
return name;
}
@XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
@XmlAttribute
public BufferedImage getImage() {
return image;
}
public User() {
this("", null);
}
Adaptador
Para evitar crear la misma imagen en la memoria dos veces (además de volver a descargar los
datos), el adaptador almacena las imágenes en un mapa.
Java SE 7
https://riptutorial.com/es/home 765
Para el código Java 7 válido, reemplace el método getImage con
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.xml.bind.annotation.adapters.XmlAdapter;
@Override
public BufferedImage unmarshal(String v) throws Exception {
return getImage(new URL(v));
}
@Override
public String marshal(BufferedImage v) throws Exception {
return reverseIndex.get(v).toExternalForm();
}
https://riptutorial.com/es/home 766
Ejemplos de XML
Los siguientes 2 xmls son para Jon Skeet y su homólogo de Earth 2, que se ven exactamente
iguales y, por lo tanto, usan el mismo avatar.
Usando el adaptador
System.out.println(result1.getName());
System.out.println(result2.getName());
/**
* A package containing serializable classes.
*/
@XmlSchema
(
xmlns =
https://riptutorial.com/es/home 767
{
@XmlNs(prefix = MySerializableClass.NAMESPACE_PREFIX, namespaceURI =
MySerializableClass.NAMESPACE)
},
namespace = MySerializableClass.NAMESPACE,
elementFormDefault = XmlNsForm.QUALIFIED
)
package com.test.jaxb;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
package com.example.xml.adapters;
import javax.xml.bind.annotation.adapters.XmlAdapter;
@Override
public String marshal(String v) throws Exception {
if (v == null)
return null;
return v.trim();
}
}
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
https://riptutorial.com/es/home 768
Capítulo 109: JAX-WS
Examples
Autenticación básica
La forma de realizar una llamada JAX-WS con autenticación básica es algo obvia.
Aquí hay un ejemplo donde Service es la representación de la clase de servicio y Port es el puerto
de servicio al que desea acceder.
port.call();
https://riptutorial.com/es/home 769
Capítulo 110: JMX
Introducción
La tecnología JMX proporciona las herramientas para crear soluciones distribuidas, basadas en
web, modulares y dinámicas para administrar y monitorear dispositivos, aplicaciones y redes
impulsadas por servicios. Por diseño, este estándar es adecuado para adaptar sistemas
heredados, implementar nuevas soluciones de administración y monitoreo, y conectarse a las del
futuro.
Examples
Ejemplo simple con Platform MBean Server
Digamos que tenemos algún servidor que registra nuevos usuarios y los saluda con algún
mensaje. Y queremos monitorear este servidor y cambiar algunos de sus parámetros.
int getUserCount();
String getGreetingString();
void stop();
}
Y una implementación simple que nos permitirá ver cómo está funcionando y cómo lo afectamos.
@Override
public long getSleepTime() {
return sleepTime.get();
}
@Override
public void setSleepTime(long sleepTime) {
this.sleepTime.set(sleepTime);
https://riptutorial.com/es/home 770
}
@Override
public int getUserCount() {
return userCount.get();
}
@Override
public void setUserCount(int userCount) {
this.userCount.set(userCount);
}
@Override
public String getGreetingString() {
return greetingString.get();
}
@Override
public void setGreetingString(String greetingString) {
this.greetingString.set(greetingString);
}
@Override
public void stop() {
this.interrupted.set(true);
}
@Override
public void run() {
while (!interrupted.get()) {
try {
System.out.printf("User %d, %s%n", userCount.incrementAndGet(),
greetingString.get());
Thread.sleep(sleepTime.get());
} catch (InterruptedException ignored) {
}
}
}
}
Para un ejemplo simple con administración local o remota, necesitamos registrar nuestro MBean:
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
https://riptutorial.com/es/home 771
thread.start();
thread.join();
}
}
Después de eso, podemos ejecutar nuestra aplicación y conectarla a través de jConsole, que se
puede encontrar en su directorio $JAVA_HOME/bin . Primero, necesitamos encontrar nuestro proceso
luego cambie a la pestaña MBeans y encuentre el MBean que usamos en nuestra clase Main
como ObjectName (en el ejemplo anterior es ServerManager ). En la sección Attributes podemos ver
los atributos. Si ha especificado solo el método de obtención, el atributo será legible pero no
grabable. Si especificara los métodos get y set, el atributo sería legible y grabable.
https://riptutorial.com/es/home 772
Los métodos especificados se pueden invocar en Operations sección Operations .
https://riptutorial.com/es/home 773
-Dcom.sun.management.jmxremote.ssl=false
Estos parámetros se pueden encontrar en el Capítulo 2 de las guías JMX . Después de eso,
podrá conectarse a su aplicación a través de jConsole de forma remota con jconsole host:port o
con la especificación de host:port o service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi en
jConsole GUI.
Enlaces útiles:
• Guias jmx
• Mejores practicas JMX
https://riptutorial.com/es/home 774
Capítulo 111: JNDI
Examples
RMI a través de JNDI
Este ejemplo muestra cómo funciona JNDI en RMI. Tiene dos roles:
Para hacer esto simple, usaremos java.rmi.registry.CreateRegistry() para crear el Registro RMI.
package com.neohope.jndi.test;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.Hashtable;
/**
* JNDI Server
* 1.create a registry on port 1234
* 2.bind JNDI
* 3.wait for connection
* 4.clean up and end
*/
public class Server {
private static Registry registry;
private static InitialContext ctx;
https://riptutorial.com/es/home 775
public static void bindJNDI(String name, Object obj) throws NamingException {
ctx.bind(name, obj);
}
package com.neohope.jndi.test;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable;
/**
* 1.init context
* 2.lookup registry for the service
* 3.use the service
* 4.end
*/
public class Client {
public static void main(String[] args) throws NamingException {
final Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
jndiProperties.put(Context.PROVIDER_URL, "rmi://localhost:1234");
package com.neohope.jndi.test;
import java.io.Serializable;
import java.rmi.Remote;
https://riptutorial.com/es/home 776
/**
* NMessage
* RMI server class
* must implements Remote and Serializable
*/
public class NMessage implements Remote, Serializable {
public String message = "";
Introducir
La interfaz de nombres y directorios de Java (JNDI) es una API de Java para un servicio de
directorio que permite a los clientes de software de Java descubrir y buscar datos y objetos a
través de un nombre. Está diseñado para ser independiente de cualquier implementación
específica de servicios de nombres o directorios.
La arquitectura JNDI consta de una API (interfaz de programación de aplicaciones) y una SPI
(interfaz de proveedor de servicios). Las aplicaciones Java utilizan esta API para acceder a una
variedad de servicios de nombres y directorios. El SPI permite la conexión transparente de una
variedad de servicios de nombres y directorios, lo que permite que la aplicación Java que utiliza la
API de la tecnología JNDI acceda a sus servicios.
Como puede ver en la imagen de arriba, JNDI admite LDAP, DNS, NIS, NDS, RMI y CORBA. Por
https://riptutorial.com/es/home 777
supuesto, puedes ampliarlo.
Cómo funciona
En este ejemplo, el RMI de Java utiliza la API JNDI para buscar objetos en una red. Si desea
buscar un objeto, necesita al menos dos datos:
El registro de RMI administra los enlaces de nombre, le indica dónde encontrar el objeto.
¿Cuál es el nombre de un objeto? Generalmente es una cadena, también puede ser un objeto
que implementa la interfaz de nombre.
Paso a paso
1. Primero necesita un registro, que administre el enlace de nombre. En este ejemplo, usamos
java.rmi.registry.LocateRegistry .
2. Tanto el cliente como el servidor necesitan un contexto. El servidor utiliza el contexto para
enlazar el nombre y el objeto. El cliente usa el contexto para buscar el nombre y obtener el
objeto.
https://riptutorial.com/es/home 778
ctx.unbind("/neohope/jndi/test01");
ctx.close();
https://riptutorial.com/es/home 779
Capítulo 112: JShell
Introducción
JShell es un REPL interactivo para Java agregado en JDK 9. Permite a los desarrolladores
evaluar instantáneamente expresiones, probar clases y experimentar con el lenguaje Java. El
acceso temprano para jdk 9 se puede obtener en: http://jdk.java.net/9/
Sintaxis
• $ jshell - Inicia el JShell REPL
• jshell> / <comando> - Ejecuta un comando JShell dado
• jshell> / exit - Salir de JShell
• jshell> / help - Ver una lista de comandos de JShell
• jshell> <java_expression> - Evalúa la expresión Java dada (punto y coma opcional)
• jshell> / vars O / métodos O / tipos: vea una lista de variables, métodos o clases,
respectivamente.
• jshell> / open <archivo> - lee un archivo como entrada al shell
• jshell> / edit <identifier> - edita un fragmento en el editor de conjuntos
• jshell> / set editor <comando>: establece el comando que se usará para editar fragmentos
de código usando / editar
• jshell> / drop <identifier> - borra un fragmento
• jshell> / reset - Restablece la JVM y borra todos los fragmentos
Observaciones
JShell requiere el Java 9 JDK, que actualmente se puede descargar (marzo de 2017) como
instantáneas de acceso temprano desde jdk9.java.net . Si, cuando intenta ejecutar el comando
jshell , obtiene un error que comienza con Unable to locate an executable , asegúrese de que
JAVA_HOME esté configurado correctamente.
import java.io.*
import java.math.*
import java.net.*
import java.nio.file.*
import java.util.*
import java.util.concurrent.*
import java.util.function.*
import java.util.prefs.*
import java.util.regex.*
import java.util.stream.*
https://riptutorial.com/es/home 780
Examples
Entrando y saliendo de JShell
A partir de JShell
Antes de intentar iniciar JShell, asegúrese de que la variable de entorno JAVA_HOME apunta a una
instalación JDK 9. Para iniciar JShell, ejecute el siguiente comando:
$ jshell
Saliendo de JShell
Para salir de JShell, ejecute el siguiente comando desde el indicador de JShell:
jshell> /exit
Expresiones
Dentro de JShell, puede evaluar expresiones de Java, con o sin punto y coma. Estos pueden ir
desde expresiones y declaraciones básicas hasta expresiones más complejas:
jshell> 4+2
jshell> System.out.printf("I am %d years old.\n", 421)
Es importante tener en cuenta que las expresiones dentro de los bloques deben tener punto y
coma.
Variables
Tenga en cuenta que las variables se pueden redeclar con diferentes tipos; Esto es
perfectamente válido en JShell:
https://riptutorial.com/es/home 781
jshell> String var = "hi"
jshell> int var = 3
Métodos y Clases
No se requieren modificadores de acceso. Al igual que con otros bloques, se requieren puntos y
coma dentro de los cuerpos de los métodos. Tenga en cuenta que, al igual que con las variables,
es posible redefinir los métodos y las clases. Para ver una lista de métodos o clases, ingrese
/methods o /types en el indicador de JShell, respectivamente.
Editando Fragmentos
La unidad básica de código utilizada por JShell es el fragmento o la entrada de origen . Cada
vez que declara una variable local o define un método o clase local, crea un fragmento de código
cuyo nombre es el identificador de la variable / método / clase. En cualquier momento, puede
editar un fragmento de código que haya creado con el comando /edit . Por ejemplo, digamos que
he creado la clase Foo con una sola bar método:
Ahora, quiero rellenar el cuerpo de mi método. En lugar de reescribir toda la clase, puedo editarla:
De forma predeterminada, aparecerá un editor de swing con las funciones más básicas posibles.
Sin embargo, puedes cambiar el editor que JShell usa:
Tenga en cuenta que si la nueva versión del fragmento de código contiene errores de
sintaxis, es posible que no se guarde. Del mismo modo, un fragmento de código solo se crea si
la declaración / definición original es sintácticamente correcta; lo siguiente no funciona:
https://riptutorial.com/es/home 782
jshell> String st = String 3
//error omitted
jshell> /edit st
| No such snippet: st
Sin embargo, los fragmentos de código pueden compilarse y, por lo tanto, ser editables a pesar
de ciertos errores de tiempo de compilación, como los tipos que no coinciden, los siguientes
trabajos:
jshell> int i = 13
jshell> /drop i
jshell> System.out.println(i)
| Error:
| cannot find symbol
| symbol: variable i
| System.out.println(i)
|
Para eliminar todos los fragmentos de código, restableciendo así el estado de la JVM, use \reset :
jshell> int i = 2
jshell> /reset
| Resetting state.
jshell> i
| Error:
| cannot find symbol
| symbol: variable i
| i
| ^
jshell> s
| Error:
| cannot find symbol
| symbol: variable s
| s
| ^
https://riptutorial.com/es/home 783
Capítulo 113: JSON en Java
Introducción
JSON (JavaScript Object Notation) es un formato de intercambio de datos ligero, basado en texto
e independiente del idioma que es fácil de leer y escribir para los humanos y las máquinas. JSON
puede representar dos tipos estructurados: objetos y matrices. JSON se usa a menudo en
aplicaciones Ajax, configuraciones, bases de datos y servicios web RESTful. La API de Java para
el procesamiento de JSON proporciona API portátiles para analizar, generar, transformar y
consultar JSON.
Observaciones
Este ejemplo se enfoca en analizar y crear JSON en Java usando varias bibliotecas, como la
biblioteca de Google Gson , Jackson Object Mapper y otras.
Los ejemplos que utilizan otras bibliotecas se pueden encontrar aquí: Cómo analizar JSON en
Java
Examples
Codificación de datos como JSON
Si necesita crear un objeto JSONObject y colocar datos en él, considere el siguiente ejemplo:
first.put("foo", "bar");
first.put("temperature", 21.5);
first.put("year", 2016);
// Encode
String json = object.toString();
https://riptutorial.com/es/home 784
/* {
"foo":"bar",
"temperature":21.5,
"year":2016,
"message":{"Hello":"world"},
"months":["January","February","March",null,"May"]
}
*/
String json =
"{\"foo\":\"bar\",\"temperature\":21.5,\"year\":2016,\"message\":{\"Hello\":\"world\"},\"months\":[\"Ja
// Retrieve an array
JSONArray someMonths = object.getJSONArray("months");
// Get some values from the array
int nMonths = someMonths.length();
String february = someMonths.getString(1);
JSONObjecty JSONArray tienen algunos métodos que son muy útiles al tratar con la posibilidad de
que un valor que está tratando de obtener no exista o sea de otro tipo.
// However, if a value cannot be coerced to the required type, the behavior differs
obj.getInt("foo"); // throws JSONException
obj.optInt("foo"); // returns 0
obj.optInt("foo", 123); // returns 123
https://riptutorial.com/es/home 785
obj.optString("undefined", "tux"); // returns "tux"
Asumamos que tienes una clase llamada Person con solo name
Código:
Asumamos que tienes una clase llamada Person con solo name
Código:
https://riptutorial.com/es/home 786
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
System.out.println(jsonObject.get("name").getAsString()); //John
System.out.println(jsonObject.get("age").getAsInt()); //21
Modelo de pojo
Detalles
Declaración de importación necesaria:
import com.fasterxml.jackson.databind.ObjectMapper;
Instancia de ObjectMapper
//creating one
ObjectMapper objectMapper = new ObjectMapper();
Deserialización:
https://riptutorial.com/es/home 787
<T> T readValue(String content, Class<T> valueType)
del objeto
• Arroja
○ JsonProcessingException en caso de error
○ Nota: antes de la versión 2.1, la cláusula throws incluía IOException; 2.1 lo eliminó.
Iteración json
https://riptutorial.com/es/home 788
Ejemplo de JSONObject
JSONArray
JSONObject.NULL
Si necesita agregar una propiedad con un valor null , debe usar el JSONObject.NULL final estático
predefinido y no la referencia null Java estándar.
JSONObject.NULL es un valor centinela utilizado para definir explícitamente una propiedad con un
valor vacío.
Nota
Para cualquier valor de referencia que no sea nulo x, x.equals (nulo) debe devolver
falso
{
"list": [
"Test_String_1",
"Test_String_2"
]
}
Ahora pase la 'lista' de JsonArray al siguiente método que devuelve una ArrayList Java
correspondiente:
https://riptutorial.com/es/home 789
Type listType = new TypeToken<List<String>>() {}.getType();
//make sure the name 'list' matches the name of 'JsonArray' in your 'Json'.
ArrayList<String> list = new Gson().fromJson(jsonList, listType);
return list;
}
Y desea analizarlo en una matriz JSON o en un mapa de objetos Person. Debido al borrado de
tipos, no puede construir clases de List<Person> y Map<String, Person> en tiempo de ejecución
directamente (y, por lo tanto, usarlas para deserializar JSON) . Para superar esta limitación,
jackson proporciona dos enfoques: TypeFactory y TypeReference .
TypeFactory
El enfoque adoptado aquí es utilizar una fábrica (y su función de utilidad estática) para crear su
tipo para usted. Los parámetros que toma son la colección que desea utilizar (lista, conjunto, etc.)
y la clase que desea almacenar en esa colección.
TypeReference
El enfoque de referencia de tipo parece más sencillo porque le ahorra un poco de escritura y se
ve más limpio. TypeReference acepta un parámetro de tipo, donde pasa el tipo de List<Person>
deseado List<Person> . Simplemente crea una instancia de este objeto TypeReference y lo utiliza
como su contenedor de tipo.
Ahora veamos cómo deserializar su JSON en un objeto Java. Si su JSON está formateado como
una matriz, puede deserializarlo como una Lista. Si hay una estructura anidada más compleja,
deseará deserializar a un mapa. Veremos ejemplos de ambos.
https://riptutorial.com/es/home 790
Deserialización de matriz JSON
String jsonString = "[{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]"
Enfoque de TypeFactory
CollectionType listType =
factory.constructCollectionType(List.class, Person.class);
List<Preson> list = mapper.readValue(jsonString, listType);
Enfoque de TypeFactory
CollectionType mapType =
factory.constructMapLikeType(Map.class, String.class, Person.class);
List<Person> list = mapper.readValue(jsonString, mapType);
Detalles
Declaración de importación utilizada:
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
Instancias utilizadas:
https://riptutorial.com/es/home 791
ObjectMapper mapper = new ObjectMapper();
TypeFactory factory = mapper.getTypeFactory();
Nota
Si TypeReference enfoque de TypeReference puede verse mejor, tiene varios inconvenientes:
Si no lo hace, puede provocar la pérdida de un argumento de tipo genérico que llevará a un error
de deserialización.
https://riptutorial.com/es/home 792
Capítulo 114: Just in Time (JIT) compilador
Observaciones
Historia
El compilador JIT de Symantec estaba disponible en Sun Java a partir de 1.1.5 en adelante, pero
tenía problemas.
El compilador JIT de Hotspot se agregó a Sun Java en 1.2.2 como complemento. En Java 1.3, JIT
estaba habilitado por defecto.
Examples
Visión general
https://riptutorial.com/es/home 793
El compilador Just-In-Time (JIT) es un componente de Java ™ Runtime Environment que mejora
el rendimiento de las aplicaciones Java en tiempo de ejecución.
• Los programas Java se componen de clases, que contienen códigos de byte independientes
de la plataforma que pueden ser interpretados por una JVM en diferentes arquitecturas de
computadoras.
• En tiempo de ejecución, la JVM carga los archivos de clase, determina la semántica de cada
bytecode individual y realiza el cálculo apropiado.
https://riptutorial.com/es/home 794
Cuando se ha compilado un método, la JVM llama al código compilado de ese método
directamente en lugar de interpretarlo. Teóricamente, si la compilación no requería tiempo de
procesador y uso de memoria, compilar todos los métodos podría permitir que la velocidad del
programa Java se acerque a la de una aplicación nativa.
La compilación JIT requiere tiempo de procesador y uso de memoria. Cuando se inicia JVM por
primera vez, se llaman miles de métodos. La compilación de todos estos métodos puede afectar
significativamente el tiempo de inicio, incluso si el programa logra un rendimiento máximo muy
bueno.
• En la práctica, los métodos no se compilan la primera vez que se llaman. Para cada método,
la JVM mantiene un call count que se incrementa cada vez que se llama al método.
• La JVM interpreta un método hasta que su recuento de llamadas supera un umbral de
compilación JIT.
• Por lo tanto, los métodos de uso frecuente se compilan poco después de que la JVM haya
comenzado, y los métodos menos utilizados se compilan mucho más tarde, o no se hacen.
• El umbral de compilación JIT ayuda a que la JVM se inicie rápidamente y aún así tenga un
rendimiento mejorado.
• El umbral se ha seleccionado cuidadosamente para obtener un equilibrio óptimo entre los
tiempos de inicio y el rendimiento a largo plazo.
• Después de compilar un método, su cuenta de llamadas se restablece a cero y las llamadas
subsiguientes al método continúan incrementando su cuenta.
• Cuando el recuento de llamadas de un método alcanza un umbral de recompilación JIT, el
compilador JIT lo compila por segunda vez, aplicando una selección más grande de
optimizaciones que en la compilación anterior.
• Este proceso se repite hasta que se alcanza el nivel máximo de optimización.
Los métodos más ocupados de un programa Java siempre se optimizan de forma más
agresiva, maximizando los beneficios de rendimiento del uso del compilador JIT.
El compilador JIT también puede medir operational data at run time , y usar esos datos para
mejorar la calidad de las recompilaciones adicionales.
https://riptutorial.com/es/home 795
Capítulo 115: La clase java.util.Objects
Examples
Uso básico para la comprobación del objeto nulo.
Con el método Objects.nonNull y Java8 Stream API, podemos hacer lo anterior de esta manera:
https://riptutorial.com/es/home 796
Capítulo 116: Las trampas de Java - Hilos y
concurrencia
Examples
Trampa: uso incorrecto de esperar () / notificar ()
La razón por la que esto es incorrecto es que depende de algún otro subproceso para llamar a
lock.notify() o lock.notifyAll() , pero nada garantiza que el otro subproceso no realizó esa
llamada antes del subproceso del consumidor llamado lock.wait() .
lock.notify() y lock.notifyAll() no hacen nada en absoluto si algún otro hilo no está esperando
la notificación. El hilo que llama a myConsumer() en este ejemplo se bloqueará para siempre si es
demasiado tarde para detectar la notificación.
https://riptutorial.com/es/home 797
(El diseño para wait() / notify() requiere que el bloqueo se mantenga porque es necesario para
evitar las condiciones de carrera sistémicas. Si fuera posible llamar a wait() o notify() sin
bloqueo, sería imposible implementar el caso de uso principal de estas primitivas: esperar que
ocurra una condición.)
El javadoc para la clase Thread muestra dos formas de definir y usar un hilo:
Usando un Runnable :
https://riptutorial.com/es/home 798
1. Es incómodo usar PrimeThread en un contexto que usa un grupo de subprocesos clásico, un
ejecutor o el marco de ForkJoin. (No es imposible, porque PrimeThread implementa
indirectamente Runnable , pero usar una clase Thread personalizada como Runnable es
ciertamente torpe y puede que no sea viable ... dependiendo de otros aspectos de la clase).
El enfoque de poner la lógica del hilo en un Runnable evita estos problemas. De hecho, si usa una
clase anónima (Java 1.1 en adelante) para implementar el Runnable el resultado es más sucinto y
más legible que los ejemplos anteriores.
Con una expresión lambda (Java 8 en adelante), el ejemplo anterior sería aún más elegante:
Pitfall - Demasiados hilos hace que una aplicación sea más lenta.
Una gran cantidad de personas que son nuevas en los subprocesos múltiples piensan que el uso
de subprocesos hace que una aplicación vaya más rápido. De hecho, es mucho más complicado
que eso. Pero una cosa que podemos decir con certeza es que para cualquier computadora hay
un límite en el número de subprocesos que se pueden ejecutar al mismo tiempo:
Esto nos dice que simplemente crear más y más hilos de Java no puede hacer que la aplicación
vaya más rápido y más rápido. Pero hay otras consideraciones también:
• Cada subproceso requiere una región de memoria fuera del montón para su pila de
subprocesos. El tamaño de pila de hilos típico (predeterminado) es 512Kbytes o 1Mbytes. Si
tiene un número significativo de subprocesos, el uso de la memoria puede ser significativo.
• Cada subproceso activo hará referencia a una serie de objetos en el montón. Eso aumenta
el conjunto de trabajo de objetos alcanzables , lo que afecta la recolección de basura y el
https://riptutorial.com/es/home 799
uso de la memoria física.
Dependiendo de los detalles de su aplicación, estos factores generalmente significan que hay un
"punto dulce" para el número de hilos. Más allá de eso, agregar más hilos proporciona una mejora
mínima del rendimiento y puede empeorar el rendimiento.
Si su aplicación se crea para cada nueva tarea, un aumento inesperado en la carga de trabajo
(por ejemplo, una alta tasa de solicitud) puede llevar a un comportamiento catastrófico.
Una mejor manera de lidiar con esto es usar un grupo de subprocesos limitados cuyo tamaño
puede controlar (estática o dinámicamente). Cuando hay mucho trabajo por hacer, la aplicación
necesita poner en cola las solicitudes. Si usa un ExecutorService , se encargará de la
administración del grupo de subprocesos y la cola de tareas.
El primer punto de referencia simplemente crea, inicia y une hilos. El Runnable del hilo no funciona.
$ java ThreadTest
34627.91355
33596.66021
33661.19084
33699.44895
33603.097
33759.3928
33671.5719
33619.46809
33679.92508
https://riptutorial.com/es/home 800
33500.32862
33409.70188
33475.70541
33925.87848
33672.89529
^C
En una PC moderna típica que ejecuta Linux con 64bit Java 8 u101, este punto de referencia
muestra un tiempo promedio que se tarda en crear, iniciar y unir hilos de entre 33.6 y 33.9
microsegundos.
import java.util.concurrent.*;
$ java ExecutorTest
6714.66053
5418.24901
5571.65213
5307.83651
5294.44132
5370.69978
5291.83493
5386.23932
5384.06842
5293.14126
5445.17405
5389.70685
^C
Como puedes ver, los promedios están entre 5.3 y 5.6 microsegundos.
Si bien los tiempos reales dependerán de una variedad de factores, la diferencia entre estos dos
resultados es significativa. Claramente, es más rápido utilizar un grupo de subprocesos para
reciclar subprocesos que crear nuevos subprocesos.
https://riptutorial.com/es/home 801
Considera este ejemplo:
La intención de este programa es iniciar un subproceso, dejar que se ejecute durante 1000
milisegundos y luego hacer que se detenga al establecer el indicador de stop .
La especificación del lenguaje Java garantiza que las lecturas y escrituras de memoria hechas en
un hilo sean visibles para ese hilo, según el orden de las declaraciones en el código fuente. Sin
embargo, en general, esto NO está garantizado cuando un hilo escribe y otro hilo
(posteriormente) lee. Para obtener una visibilidad garantizada, es necesario que haya una cadena
de relaciones de suceso antes de una escritura y una lectura posterior. En el ejemplo anterior, no
hay tal cadena para la actualización del indicador de stop , y por lo tanto, no se garantiza que el
subproceso secundario verá el cambio de stop en true .
(Nota para los autores: Debe haber un tema separado en el Modelo de memoria de Java para
profundizar en los detalles técnicos).
https://riptutorial.com/es/home 802
En este caso, hay dos formas sencillas de garantizar que la actualización de stop esté visible:
Para una variable volatile , el JLS especifica que hay una relación de suceso antes entre
una escritura por un hilo y una lectura posterior por un segundo hilo.
Además de garantizar que haya una exclusión mutua, el JLS especifica que hay una relación de
suceso antes entre la liberación de un mutex en un hilo y obtener el mismo mutex en un segundo
hilo.
Sin embargo, ese hecho no significa que los efectos de la actualización serán visibles
simultáneamente a todos los subprocesos. Sólo una cadena adecuada de relaciones de suceso-
antes lo garantizará.
https://riptutorial.com/es/home 803
Los programadores que realizan programación de subprocesos múltiples en Java por primera vez
encuentran que el modelo de memoria es un desafío. Los programas se comportan de una
manera no intuitiva porque la expectativa natural es que las escrituras son visibles de manera
uniforme. Entonces, ¿por qué los diseñadores de Java diseñan el modelo de memoria de esta
manera?
Pero eso nos da un nuevo problema cuando varios núcleos están leyendo y escribiendo variables
compartidas. La última versión de una variable puede estar en el caché de un núcleo. A menos
que ese núcleo descargue la línea de caché en la memoria principal, Y otros núcleos invaliden su
copia en caché de versiones anteriores, algunos de ellos pueden ver versiones obsoletas de la
variable. Pero si los cachés se vaciaran en la memoria cada vez que hay una escritura de caché
("por si acaso" hubo una lectura por parte de otro núcleo) que consumiría innecesariamente el
ancho de banda de la memoria principal.
Volviendo a Java. El modelo de memoria está diseñado para que los compiladores de Java no
tengan que emitir la invalidación de la memoria caché y las instrucciones de escritura directa
donde no sean realmente necesarias. El supuesto es que el programador utilizará un mecanismo
de sincronización apropiado (por ejemplo, mutexes primitivos, clases de concurrencia volatile ,
de alto nivel, etc.) para indicar que necesita visibilidad de memoria. En ausencia de una relación
de suceso antes , los compiladores de Java son libres de asumir que no se requieren operaciones
de caché (o similares).
Esto tiene importantes ventajas de rendimiento para aplicaciones de subprocesos múltiples, pero
la desventaja es que escribir aplicaciones de subprocesos múltiples correctas no es una cuestión
simple. El programador tiene que entender lo que él o ella está haciendo.
https://riptutorial.com/es/home 804
¿Por qué no puedo reproducir esto?
Hay varias razones por las que problemas como este son difíciles de reproducir:
3. Es posible que esté observando los efectos de la sincronización fortuita . Por ejemplo, si
agrega traceprints, normalmente se produce una sincronización entre bambalinas en las
secuencias de E / S que causan vacíos de caché. Por lo tanto, agregar traceprints a
menudo hace que la aplicación se comporte de manera diferente.
Estas cosas hacen que los errores debidos a una sincronización inadecuada sean particularmente
difíciles de resolver.
https://riptutorial.com/es/home 805
Capítulo 117: Lectores y escritores
Introducción
Los lectores y escritores y sus respectivas subclases proporcionan I / O simple para datos
basados en texto / caracteres.
Examples
BufferedReader
Introducción
La clase BufferedReader es una envoltura para otras clases de Reader que cumple dos propósitos
principales:
https://riptutorial.com/es/home 806
Puedes aplicar este patrón a cualquier Reader
Notas:
2. El código dentro del bloque try es virtualmente idéntico al que FileReader si leemos
directamente desde el FileReader . De hecho, un BufferedReader funciona exactamente igual
que el Reader que envuelve. La diferencia es que esta versión es mucho más eficiente.
El método BufferedReader.readLine ()
Java 8 proporciona una forma más concisa de hacerlo utilizando el método lines() :
Ejemplo de StringWriter
La clase StringWriter de Java es un flujo de caracteres que recopila los resultados del búfer de
cadena, que se puede usar para construir una cadena.
https://riptutorial.com/es/home 807
La clase StringWriter extiende la clase Writer.
En la clase StringWriter, los recursos del sistema como los sockets de red y los archivos no se
utilizan, por lo que no es necesario cerrar el StringWriter.
import java.io.*;
public class StringWriterDemo {
public static void main(String[] args) throws IOException {
char[] ary = new char[1024];
StringWriter writer = new StringWriter();
FileInputStream input = null;
BufferedReader buffer = null;
input = new FileInputStream("c://stringwriter.txt");
buffer = new BufferedReader(new InputStreamReader(input, "UTF-8"));
int x;
while ((x = buffer.read(ary)) != -1) {
writer.write(ary, 0, x);
}
System.out.println(writer.toString());
writer.close();
buffer.close();
}
}
El ejemplo anterior nos ayuda a conocer un ejemplo simple de StringWriter que utiliza
BufferedReader para leer datos de archivos de la secuencia.
https://riptutorial.com/es/home 808
Capítulo 118: LinkedHashMap
Introducción
La clase LinkedHashMap es la implementación de la tabla Hash y la lista vinculada de la interfaz
Map, con un orden de iteración predecible. Hereda la clase HashMap e implementa la interfaz
Map.
Los puntos importantes sobre la clase LinkedHashMap de Java son: Un LinkedHashMap contiene
valores basados en la clave. Sólo contiene elementos únicos. Puede tener una clave nula y varios
valores nulos. Es igual que HashMap en cambio mantiene el orden de inserción.
Examples
Clase LinkedHashMap de Java
Puntos clave:-
Métodos: -
Ejemplo: -
https://riptutorial.com/es/home 809
Set set = lhm.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry me = (Map.Entry) i.next();
System.out.println(me.getKey() + " : " + me.getValue());
}
https://riptutorial.com/es/home 810
Capítulo 119: Lista vs SET
Introducción
¿Cuáles son las diferencias entre la colección List y Set en el nivel superior y cómo elegir cuándo
usar List en java y cuándo usar Set en Java?
Examples
Lista vs conjunto
import java.util.ArrayList;
clase pública SetAndListExample {public static void main (String [] args) {System.out.println ("List
list ....."); List list = new ArrayList (); list.add ("1"); list.add ("2"); list.add ("3"); list.add ("4"); list.add
("1");
https://riptutorial.com/es/home 811
Capítulo 120: Literales
Introducción
Un literal de Java es un elemento sintáctico (es decir, algo que se encuentra en el código fuente
de un programa Java) que representa un valor. Los ejemplos son 1 , 0.333F , false , 'X' y "Hello
world\n" .
Examples
Literales hexadecimales, octales y binarios.
Un número hexadecimal es un valor en base-16. Hay 16 dígitos, 0-9 y las letras AF (el caso no
importa). AF representan 10-16 .
El literal octal puede ser fácilmente una trampa para los errores semánticos. Si define un '0'
inicial en sus literales decimales, obtendrá el valor incorrecto:
Desde Java 7 ha sido posible usar uno o más guiones bajos (_) para separar grupos de dígitos en
un número literal primitivo para mejorar su legibilidad.
Java SE 7
int i1 = 123456;
int i2 = 123_456;
System.out.println(i1 == i2); // true
Esto se puede aplicar a todos los literales de números primitivos como se muestra a continuación:
https://riptutorial.com/es/home 812
Java SE 7
Esto también funciona usando prefijos para bases binarias, octales y hexadecimales:
Java SE 7
Hay algunas reglas sobre los guiones bajos que prohíben su colocación en los siguientes
lugares:
https://riptutorial.com/es/home 813
Secuencia de escape Sentido
El <octal> de lo anterior consta de uno, dos o tres dígitos octales ('0' a '7') que representan un
número entre 0 y 255 (decimal).
Tenga en cuenta que una barra invertida seguida de cualquier otro carácter es una secuencia de
escape no válida. Las secuencias de escape no válidas se tratan como errores de compilación
por el JLS.
Referencia:
Unicode se escapa
Además de las secuencias de escape de caracteres y cadenas descritas anteriormente, Java
tiene un mecanismo de escape Unicode más general, como se define en JLS 3.3. Unicode
Escapes . Un escape Unicode tiene la siguiente sintaxis:
donde <hex-digit> es uno de '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' ,
'e' , 'f' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' .
Los literales enteros proporcionan valores que se pueden usar donde se necesita una instancia
de byte , short , int , long o char . (Este ejemplo se centra en las formas decimales simples. Otros
ejemplos explican cómo los literales en octal, hexadecimal y binario, y el uso de guiones bajos
para mejorar la legibilidad).
https://riptutorial.com/es/home 814
1 // The decimal number one (type 'int')
42 // The decimal number forty two (type 'int')
Tienes que tener cuidado con los ceros iniciales. Un cero inicial hace que un literal entero se
interprete como octal no decimal.
Los literales enteros están sin firmar. Si ve algo como -10 o +10 , estas son en realidad
expresiones que usan los operadores unarios - y unarios + .
El rango de literales enteros de esta forma tiene un tipo intrínseco de int , y debe estar en el
rango de cero a 2 31 o 2,147,483,648.
Tenga en cuenta que 2 31 es 1 mayor que Integer.MAX_VALUE . Los literales desde 0 hasta
2147483647 se pueden utilizar en cualquier lugar, pero es un error de compilación de usar
2147483648 sin precedentes unario - operador. (En otras palabras, está reservado para expresar el
valor de Integer.MIN_VALUE ).
Tenga en cuenta que la distinción entre literales int y long es significativa en otros lugares. Por
ejemplo
int i = 2147483647;
long l = i + 1; // Produces a negative value because the operation is
// performed using 32 bit arithmetic, and the
// addition overflows
long l2 = i + 1L; // Produces the (intuitively) correct value.
Literales booleanos
Los literales booleanos son los más simples de los literales en el lenguaje de programación Java.
https://riptutorial.com/es/home 815
Los dos valores boolean posibles están representados por los literales true y false . Estos son
sensibles a las mayúsculas y minúsculas. Por ejemplo:
Literales de cuerda
Los literales de cadena proporcionan la forma más conveniente de representar valores de cadena
en el código fuente de Java. Un literal de cadena consiste en:
Por ejemplo:
Tenga en cuenta que un único literal de cadena no puede abarcar varias líneas de código fuente.
Es un error de compilación para que se produzca un salto de línea (o el final del archivo de
origen) antes de la comilla doble de cierre de un literal. Por ejemplo:
Cuerdas largas
Si necesita una cadena que sea demasiado larga para que quepa en una línea, la forma
convencional de expresarla es dividirla en varios literales y usar el operador de concatenación ( +
) para unir las piezas. Por ejemplo
Una expresión como la anterior que consta de cadenas literales y + satisface los requisitos para
ser una expresión constante . Eso significa que la expresión será evaluada por el compilador y
representada en tiempo de ejecución por un solo objeto String .
https://riptutorial.com/es/home 816
Cuando la JVM carga el archivo de clase que contiene literales de cadena, el sistema de tiempo
de ejecución introduce internamente los objetos de String correspondientes. Esto significa que un
literal de cadena utilizado en varias clases no ocupa más espacio que si se usara en una clase.
Para obtener más información sobre interning y el conjunto de cadenas, consulte el ejemplo de
String pool y heap storage en el tema Strings.
El literal nulo
El literal nulo (escrito como null ) representa el único valor del tipo nulo. Aquí hay unos ejemplos
myMethod(null);
if (objects != null) {
// Do something
}
El tipo nulo es bastante inusual. No tiene nombre, por lo que no puede expresarlo en el código
fuente de Java. (Y tampoco tiene representación en tiempo de ejecución.)
El único propósito del tipo nulo es ser el tipo de null . Es compatible con la asignación de todos
los tipos de referencia, y se puede convertir a cualquier tipo de referencia. (En este último caso, la
conversión no implica una verificación de tipo de tiempo de ejecución).
Finalmente, null tiene la propiedad de que null instanceof <SomeReferenceType> evaluará como
false , sin importar cuál sea el tipo.
Los literales de punto flotante proporcionan valores que se pueden usar cuando se necesita una
instancia float o double . Hay tres tipos de literal de punto flotante.
(Las reglas de sintaxis de JLS combinan las dos formas decimales en una sola forma. Las
tratamos por separado para facilitar la explicación).
Hay tipos literales distintos para literales float y double , expresados con sufijos. Las diversas
formas usan letras para expresar diferentes cosas. Estas letras son mayúsculas y minúsculas.
https://riptutorial.com/es/home 817
el literal es un valor float ( f o F ) o double ( d o D ). El valor predeterminado (cuando no se
especifica ningún sufijo) es double .
Por ejemplo
De hecho, los dígitos decimales seguidos de un sufijo también son un literal de coma flotante.
El significado de un literal decimal es el número de punto flotante de IEEE más cercano al número
real matemático de precisión infinita indicado por la forma de punto flotante decimal. Este valor
conceptual se convierte a la representación de punto flotante binario IEEE utilizando la ronda al
más cercano . (La semántica precisa de la conversión decimal se especifica en los javadocs para
Double.valueOf(String) y Float.valueOf(String) , teniendo en cuenta que existen diferencias en las
sintaxis numéricas).
Formas hexadecimales
A partir de Java 6, es posible expresar literales de punto flotante en hexadecimal. La forma
hexadecimal tiene una sintaxis análoga a las formas decimales simples y escaladas con las
siguientes diferencias:
https://riptutorial.com/es/home 818
3. El exponente es obligatorio y se introduce mediante la letra p (o P ) en lugar de una e o una E
El exponente representa un factor de escala que es una potencia de 2 en lugar de una
potencia de 10.
Consejo: dado que las formas hexadecimales de punto flotante no son familiares para la mayoría
de los programadores de Java, es aconsejable usarlas con moderación.
Guiones bajos
Comenzando con Java 7, se permiten guiones bajos dentro de las cadenas de dígitos en las tres
formas de literal de coma flotante. Esto se aplica también a las partes del "exponente". Consulte
Uso de guiones bajos para mejorar la legibilidad .
Casos especiales
Es un error de compilación si un literal de punto flotante denota un número que es demasiado
grande o demasiado pequeño para representarlo en la representación seleccionada; es decir, si el
número se desbordaría a + INF o -INF, o subbordaría a 0.0. Sin embargo, es legal que un literal
represente un número desnormalizado distinto de cero.
La sintaxis literal de punto flotante no proporciona representaciones literales para los valores
especiales IEEE 754, como los valores INF y NaN. Si necesita expresarlos en código fuente, la
forma recomendada es usar las constantes definidas por java.lang.Float y java.lang.Double ; por
ejemplo, Float.NaN , Float.NEGATIVE_INFINITY y Float.POSITIVE_INFINITY .
Literales de personajes
Por ejemplo:
char a = 'a';
char doubleQuote = '"';
char singleQuote = '\'';
https://riptutorial.com/es/home 819
Un salto de línea en un literal de carácter es un error de compilación:
https://riptutorial.com/es/home 820
Capítulo 121: Liza
Introducción
Una lista es una colección ordenada de valores. En Java, las listas son parte de Java Collections
Framework . Las listas implementan la interfaz java.util.List , que extiende java.util.Collection
.
Sintaxis
• ls.add (elemento E); // Agrega un elemento
• ls.remove (elemento E); // Elimina un elemento
• para (elemento E: ls) {} // itera sobre cada elemento
• ls.toArray (nueva cadena [ls.length]); // Convierte una lista de cadenas a una matriz de
cadenas
• ls.get (índice int); // Devuelve el elemento en el índice especificado.
• ls.set (índice int, elemento E); // Reemplaza el elemento en una posición especificada.
• ls.isEmpty (); // Devuelve verdadero si la matriz no contiene elementos, de lo contrario,
devuelve falso.
• ls.indexOf (Objeto o); // Devuelve el índice de la primera ubicación del elemento
especificado o, o, si no está presente, devuelve -1.
• ls.lastIndexOf (Objeto o); // Devuelve el índice de la última ubicación del elemento
especificado o, o, si no está presente, devuelve -1.
• ls.size (); // Devuelve el número de elementos en la Lista.
Observaciones
Una lista es un objeto que almacena una colección ordenada de valores. "Ordenado" significa que
los valores se almacenan en un orden particular: un elemento aparece primero, otro ocupa el
segundo lugar, etc. Los valores individuales son comúnmente llamados "elementos". Las listas de
Java suelen proporcionar estas características:
https://riptutorial.com/es/home 821
Agregar un valor a una lista en algún punto que no sea el final moverá todos los siguientes
elementos "hacia abajo" o "hacia la derecha". En otras palabras, agregar un elemento en el índice
n mueve el elemento que solía estar en el índice n al índice n + 1 , y así sucesivamente. Por
ejemplo:
Examples
Ordenar una lista genérica
La clase Collections ofrece dos métodos estáticos estándar para ordenar una lista:
Aplicar lo anterior requiere modificar la clase de elementos de lista que se están ordenando, lo
que no siempre es posible. También puede ser indeseable ya que, si bien proporciona la
clasificación predeterminada, es posible que se requieran otras órdenes de clasificación en
diferentes circunstancias, o la clasificación es una tarea única.
Considere que tenemos la tarea de ordenar los objetos que son instancias de la siguiente clase:
@Override
public String toString() {
return String.format("%s:%d", username, id);
}
}
https://riptutorial.com/es/home 822
this.id = id;
this.username = username;
}
@Override
public String toString() {
return String.format("%s:%d", username, id);
}
@Override
/** The natural ordering for 'User' objects is by the 'id' field. */
public int compareTo(User o) {
return id.compareTo(o.id);
}
}
(Aparte: muchas clases Java estándar como String , Long , Integer implementan la interfaz
Comparable . Esto hace que las listas de esos elementos se puedan ordenar de forma
predeterminada y simplifica la implementación de compare o compareTo en otras clases).
Con la modificación anterior, podemos ordenar fácilmente una lista de objetos de User según el
orden natural de las clases. (En este caso, hemos definido que se ordenen según los valores de
id ). Por ejemplo:
System.out.print(users);
// [B:25, C:28, A:33]
Sin embargo, supongamos que queremos ordenar los objetos de User por name lugar de por id .
Alternativamente, supongamos que no pudimos cambiar la clase para que sea implementable
como Comparable .
Java SE 8
En Java 8 puedes usar un lambda en lugar de una clase anónima. Este último se reduce a una
sola línea:
https://riptutorial.com/es/home 823
Collections.sort(users, (l, r) -> l.username.compareTo(r.username));
Para crear una lista necesita un tipo (cualquier clase, por ejemplo, String ). Este es el tipo de su
List . La List solo almacenará objetos del tipo especificado. Por ejemplo:
List<String> strings;
Puede almacenar "string1" , "hello world!" , "goodbye" , etc., pero no puede almacenar 9.2 , sin
embargo:
List<Double> doubles;
Inicializando tu lista
Si intentas agregar algo a las listas anteriores, obtendrás una NullPointerException, ¡porque las
strings y los doubles nulos iguales!
Listes una interfaz, lo que significa que no tiene un constructor, sino métodos que una clase
debe reemplazar. ArrayList es el más comúnmente utilizado List , aunque LinkedList también es
común. Así que inicializamos nuestra lista de esta manera:
Java SE 7
https://riptutorial.com/es/home 824
o
La clase Collections proporciona dos métodos útiles para crear listas sin una variable de List :
Y un método que utiliza una List existente para completar los datos:
• addAll(L, T...) : agrega todos los elementos especificados a la lista pasada como primer
parámetro.
Ejemplos:
import java.util.List;
import java.util.Collections;
List<Integer> l = Collections.emptyList();
List<Integer> l1 = Collections.singletonList(42);
Collections.addAll(l1, 1, 2, 3);
La API de lista tiene ocho métodos para las operaciones de acceso posicional:
• add(T type)
• add(int index, T type)
• remove(Object o)
• remove(int index)
• get(int index)
• set(int index, E element)
• int indexOf(Object o)
• int lastIndexOf(Object o)
Y queríamos añadir las cuerdas "¡Hola mundo!" y "adiós mundo!" Para ello, lo haríamos como tal:
strings.add("Hello world!");
strings.add("Goodbye world!");
Y nuestra lista contendría los dos elementos. Ahora digamos que queríamos agregar "¡Programa
empezando!" al frente de la lista. Haríamos esto así:
https://riptutorial.com/es/home 825
NOTA: El primer elemento es 0.
strings.remove("Goodbye world!");
Y si quisiéramos eliminar la primera línea (que en este caso sería "¡Programa empezando!",
Podríamos hacerlo así:
strings.remove(0);
Nota:
1. Agregar y eliminar elementos de la lista modifica la lista, y esto puede llevar a una
ConcurrentModificationException si la lista se está iterando simultáneamente.
2. La adición y eliminación de elementos puede ser O(1) u O(N) según la clase de lista, el
método utilizado y si está agregando / eliminando un elemento al inicio, al final o en medio
de la lista.
Para recuperar un elemento de la lista en una posición específica, puede utilizar el E get(int
index); Método de la lista API. Por ejemplo:
strings.get(0);
Puede reemplazar cualquier elemento en una posición específica usando el set(int index, E
element); . Por ejemplo:
strings.set(0,"This is a replacement");
El int indexOf(Object o); devuelve la posición de la primera aparición del objeto pasado como
argumento. Si no hay apariciones del objeto en la lista, se devuelve el valor -1. Continuando con
el ejemplo anterior si llama:
strings.indexOf("This is a replacement")
https://riptutorial.com/es/home 826
strings.add("This is a replacement");
strings.lastIndexOf("This is a replacement");
Para el ejemplo, digamos que tenemos una Lista de tipo String que contiene cuatro elementos:
"hola", "cómo", "son", "usted?"
La mejor manera de iterar sobre cada elemento es usando un bucle para cada uno:
Que imprimiría:
hello,
how
are
you?
Se imprimirá:
Supongamos que tiene 2 listas A y B, y desea eliminar de B todos los elementos que tiene en A,
el método en este caso es
List.removeAll(Collection c);
https://riptutorial.com/es/home 827
#Ejemplo:
numbersB.removeAll(numbersA);
System.out.println("B cleared: " + numbersB);
}
esto imprimirá
A: [1, 3, 4, 7, 5, 2]
Supongamos que tiene dos listas: A y B, y necesita encontrar los elementos que existen en
ambas listas.
Ejemplo:
https://riptutorial.com/es/home 828
.collect(Collectors.toList());
Es decir:
ArrayList es una de las estructuras de datos incorporadas en Java. Es una matriz dinámica
(donde el tamaño de la estructura de datos no necesita declararse primero) para almacenar
elementos (Objetos).
El tipo de ArrayList puede ser cualquier Objeto. El tipo no puede ser un tipo primitivo (en su lugar,
use sus clases de envoltorio ).
myArrayList.add(element);
myArrayList.remove(element);
https://riptutorial.com/es/home 829
Este ejemplo se trata de reemplazar un elemento de la List mientras se asegura que el elemento
de reemplazo esté en la misma posición que el elemento que se reemplaza.
Considere una ArrayList contenga los elementos "¡Programa empezando!", "¡Hola mundo!" y
"adiós mundo!"
Si conocemos el índice del elemento que queremos reemplazar, simplemente podemos usar set
siguiente manera:
Notas:
La clase Colecciones proporciona una manera de hacer que una lista no sea modificable:
La clase Colecciones le permite mover objetos en la lista usando varios métodos (ls es la Lista):
https://riptutorial.com/es/home 830
Invertir una lista:
Collections.reverse(ls);
El método de rotación requiere un argumento entero. Este es el número de puntos para moverlo a
lo largo de la línea. Un ejemplo de esto es a continuación:
Usando la misma lista anterior, podemos barajar los elementos en una lista:
Collections.shuffle(ls);
También podemos darle un objeto java.util.Random que utiliza para colocar objetos
aleatoriamente en puntos:
La interfaz de List está implementada por diferentes clases. Cada uno de ellos tiene su propio
camino para implementarlo con diferentes estrategias y proporcionar diferentes pros y contras.
1. Clases abstractas:
• Lista abstracta
• AbstractSequentialList
2. Clases de concreto:
• Lista de arreglo
• Lista de atributos
https://riptutorial.com/es/home 831
• CopyOnWriteArrayList
• Lista enlazada
• Lista de roles
• RoleUnresolvedList
• Apilar
• Vector
Lista de arreglo
- PROS:
Las operaciones size, isEmpty, get , set , iterator y listIterator se ejecutan en tiempo constante.
Por lo tanto, obtener y configurar cada elemento de la Lista tiene el mismo costo de tiempo :
int e1 = myList.get(0); // \
int e2 = myList.get(10); // | => All the same constant cost => O(1)
myList.set(2,10); // /
- CONTRAS:
La implementación con una matriz (estructura estática) que agrega elementos sobre el tamaño de
la matriz tiene un gran costo debido al hecho de que es necesario realizar una nueva asignación
para toda la matriz. Sin embargo, a partir de la documentación :
https://riptutorial.com/es/home 832
Lista de atributos
En venir
CopyOnWriteArrayList
En venir
Lista enlazada
LinkedList se implementa mediante una lista doblemente enlazada, una estructura de datos
vinculados que consiste en un conjunto de registros vinculados secuencialmente llamados nodos.
- PROS:
myList.add(10); // \
myList.add(0,2); // | => constant time => O(1)
myList.remove(); // /
- CONTRA: De la documentación :
Las operaciones que indizan en la lista recorrerán la lista desde el principio o el final,
lo que esté más cerca del índice especificado.
Operaciones como:
myList.get(10); // \
myList.add(11,25); // | => worst case done in O(n/2)
myList.set(15,35); // /
Lista de roles
En venir
https://riptutorial.com/es/home 833
RoleUnresolvedList
En venir
Apilar
En venir
Vector
En venir
https://riptutorial.com/es/home 834
Capítulo 122: Localización e
internacionalización.
Observaciones
Java viene con un mecanismo poderoso y flexible para localizar sus aplicaciones, pero también
es fácil de usar mal y terminar con un programa que ignora o maneja la configuración regional del
usuario, y por lo tanto cómo esperan que se comporte su programa.
Sus usuarios esperarán ver datos localizados en los formatos a los que están acostumbrados, y
tratar de admitir esto manualmente es una tarea estúpida. Este es solo un pequeño ejemplo de
las diferentes formas en que los usuarios esperan ver el contenido que usted podría asumir que
se muestra "siempre" de cierta manera:
Brasil
China
Egipto
Recursos Generales
• Wikipedia: Internacionalización y localización.
Recursos de Java
• Tutorial de Java: Internacionalización
• Oracle: Internacionalización: Entendiendo la configuración regional en la plataforma Java
• JavaDoc: Locale
Examples
Fechas formateadas automáticamente usando "locale"
SimpleDateFormatter es genial en caso de apuro, pero como su nombre indica, no se escala bien.
https://riptutorial.com/es/home 835
Si codificas "MM/dd/yyyy" toda tu aplicación, tus usuarios internacionales no estarán contentos.
Donde style es una de las constantes de formato ( FULL , LONG , MEDIUM , SHORT , etc.) especificadas
en DateFormat .
Para una aplicación del lado del servidor donde el usuario especifica su configuración regional
como parte de la solicitud, debe pasarla explícitamente a getDateInstance() lugar:
String localizedDate =
DateFormat.getDateInstance(style, request.getLocale()).format(date);
Comparación de cuerdas
"School".equalsIgnoreCase("school"); // true
No usar
text1.toLowerCase().equals(text2.toLowerCase());
Los idiomas tienen diferentes reglas para convertir mayúsculas y minúsculas. Un 'I' se convertiría
a 'i' en inglés. Pero en turco un 'yo' se convierte en un 'ı'. Si tiene que usar toLowerCase() use la
sobrecarga que espera una Locale : String.toLowerCase(Locale) .
Ordene las cadenas respetando el orden del lenguaje natural, ignorando mayúsculas y
minúsculas (use la clave de intercalación para:
https://riptutorial.com/es/home 836
Lugar
La clase java.util.Locale se utiliza para representar una región "geográfica, política o cultural"
para localizar un texto, número, fecha u operación dado. Por lo tanto, un objeto Locale puede
contener un país, región, idioma y también una variante de un idioma, por ejemplo, un dialecto
hablado en una determinada región de un país, o hablado en un país diferente al país desde el
cual se origina el idioma.
La instancia de Locale se entrega a los componentes que necesitan localizar sus acciones, ya
sea para convertir la entrada, la salida o solo para las operaciones internas. La clase Locale no
puede hacer ninguna internacionalización o localización por sí misma.
Idioma
El idioma debe ser un código de idioma ISO 639 de 2 o 3 caracteres, o una subetiqueta de idioma
registrado de hasta 8 caracteres. En caso de que un idioma tenga un código de idioma de 2 y 3
caracteres, use el código de 2 caracteres. Puede encontrar una lista completa de códigos de
idiomas en el Registro de subetiquetas de idiomas de la IANA.
Los códigos de idioma no distinguen entre mayúsculas y minúsculas, pero la clase Locale
siempre usa versiones en minúsculas de los códigos de idioma
Locale constants
Locale constructors
Locale.Builder class
Locale.forLanguageTag factory method
Java ResourceBundle
Usted crea una instancia de ResourceBundle como esta:
message=This is locale
Salida:
https://riptutorial.com/es/home 837
This is locale
Configuración regional
Si desea reproducir el estado utilizando otros idiomas, puede usar el método setDefault() . Su
uso:
https://riptutorial.com/es/home 838
Capítulo 123: log4j / log4j2
Introducción
Apache Log4j es una utilidad de registro basada en Java, es uno de varios marcos de trabajo de
registro de Java. Este tema muestra cómo configurar y configurar Log4j en Java con ejemplos
detallados de todos sus posibles aspectos de uso.
Sintaxis
• Logger.debug ("texto para registrar"); // Registro de información de depuración
• Logger.info ("texto para registrar"); // Registro de información común
• Logger.error ("texto para registrar"); // Información de error de registro
• Logger.warn ("texto para registrar"); // Advertencias de registro
• Logger.trace ("texto para registrar"); // Registro de información de rastreo
• Logger.fatal ("texto para registrar"); // Registro de errores fatales
• Uso de Log4j2 con registro de parámetros:
• Logger.debug ("Debug params {} {} {}", param1, param2, param3); // Registro de depuración
con parámetros
• Logger.info ("Información params {} {} {}", param1, param2, param3); // Registro de
información con parámetros.
• Logger.error ("Parámetros de error {} {} {}", param1, param2, param3); // Error de registro
con parámetros
• Logger.warn ("Advertir params {} {} {}", param1, param2, param3); // Registro de
advertencias con parámetros.
• Logger.trace ("Trace params {} {} {}", param1, param2, param3); // Registro de seguimiento
con parámetros
• Logger.fatal ("Fatal params {} {} {}", param1, param2, param3); // Registro fatal con
parámetros
• Logger.error ("Excepción capturada:", ex); // Excepción de registro con message y
stacktrace (se agregará automáticamente)
Observaciones
De: http://logging.apache.org/log4j/1.2/
https://riptutorial.com/es/home 839
Examples
Como obtener Log4j
Utilizando Maven:
Agregue la siguiente dependencia a su archivo POM.xml :
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
Usando Ivy:
<dependencies>
<dependency org="org.apache.logging.log4j" name="log4j-api" rev="2.6.2" />
<dependency org="org.apache.logging.log4j" name="log4j-core" rev="2.6.2" />
</dependencies>
Utilizando Gradle:
dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.6.2'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.6.2'
}
Nota: Log4j 1.x ha alcanzado el final de la vida útil (EOL) (ver Comentarios).
Utilizando Maven:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
https://riptutorial.com/es/home 840
</dependency>
Usando Ivy:
Usle Gradle:
Utilizando Buildr:
'log4j:log4j:jar:1.2.17'
//logs an exception
logger.error("Information about some error: ", exception);
https://riptutorial.com/es/home 841
# Redirect log messages to console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
/ProjectFolder/src/java/resources
Esta es una configuración básica de log4j2.xml que tiene una aplicación de consola y un
registrador de raíz. El diseño del patrón especifica qué patrón se debe utilizar para registrar las
declaraciones.
Para depurar la carga de log4j2.xml puede agregar el atributo status = <WARN | DEBUG | ERROR |
FATAL | TRACE | INFO> en la etiqueta de configuración de su log4j2.xml.
También puede agregar un intervalo de supervisión para que vuelva a cargar la configuración
después del período de intervalo especificado. El intervalo del monitor se puede agregar a la
etiqueta de configuración de la siguiente manera: monitorInterval = 30 . Esto significa que la
configuración se cargará cada 30 segundos.
Si desea migrar de log4j 1.x existente en su proyecto a log4j 2.x, elimine todas las dependencias
de log4j 1.x existentes y agregue la siguiente dependencia:
Maven Build
https://riptutorial.com/es/home 842
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
Construir hiedra
<dependencies>
<dependency org="org.apache.logging.log4j" name="log4j-1.2-api" rev="2.6.2" />
</dependencies>
Construcción de Gradle
dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-1.2-api', version: '2.6.2'
}
Maven Build
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
Construir hiedra
<dependencies>
<dependency org="org.apache.logging.log4j" name="log4j-jcl" rev="2.6.2" />
</dependencies>
Construcción de Gradle
dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-jcl', version: '2.6.2'
}
Referencia: https://logging.apache.org/log4j/2.x/maven-artifacts.html
Para que este ejemplo funcione, necesitará un controlador JDBC compatible con el sistema en el
https://riptutorial.com/es/home 843
que se ejecuta la base de datos. Puede encontrar una fuente abierta que le permite conectarse a
bases de datos DB2 en un IBM System i aquí: JT400
Aunque este ejemplo es específico de DB2, funciona para casi todos los demás sistemas si
intercambia el controlador y adapta la URL de JDBC.
Puede usar un filtro para registrar solo los mensajes "más bajos" que, por ejemplo, el nivel de
ERROR . Pero el filtro no es compatible con PropertyConfigurator. Así que debes cambiar a la
configuración XML para usarlo . Ver log4j-Wiki sobre filtros .
O "rango de nivel"
https://riptutorial.com/es/home 844
<param name="ConversionPattern" value="%m%n"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMax" value="info"/>
<param name="LevelMin" value="info"/>
<param name="AcceptOnMatch" value="true"/>
</filter>
</appender>
https://riptutorial.com/es/home 845
Capítulo 124: Los operadores
Introducción
Los operadores en el lenguaje de programación Java son símbolos especiales que realizan
operaciones específicas en uno, dos o tres operandos y luego devuelven un resultado.
Observaciones
Un operador es un símbolo (o símbolos) que le dice a un programa Java que realice una
operación en uno, dos o tres operandos . Un operador y sus operandos forman una expresión
(consulte el tema Expresiones). Los operandos de un operador son en sí mismos expresiones.
Este tema describe los 40 o más operadores distintos definidos por Java. El tema de las
expresiones separadas explica:
Examples
El operador de concatenación de cuerdas (+)
En el caso simple, el operador de concatenación une dos cadenas para dar una tercera cadena.
Por ejemplo:
Cuando uno de los dos operandos no es una cadena, se convierte en una String siguiente
manera:
https://riptutorial.com/es/home 846
lugar se usa el literal de cadena "null" .
Por ejemplo:
int one = 1;
String s3 = "One is " + one; // s3 contains "One is 1"
String s4 = null + " is null"; // s4 contains "null is null"
String s5 = "{1} is " + new int[]{1}; // s5 contains something like
// "{} is [I@xxxxxxxx"
Optimización y eficiencia.
Como se señaló anteriormente, con la excepción de las expresiones constantes, cada expresión
de concatenación de cadena crea un nuevo objeto de String . Considere este código:
En el método anterior, cada iteración del bucle creará una nueva String que es un carácter más
largo que la iteración anterior. Cada concatenación copia todos los caracteres en las cadenas de
operandos para formar la nueva String . Así, las stars(N) :
Esto es muy caro para N grande. De hecho, cualquier código que concatene cadenas en un bucle
puede tener este problema. Una mejor manera de escribir esto sería como sigue:
https://riptutorial.com/es/home 847
StringBuilder sb = new StringBuilder(count);
for (int i = 0; i < count; i++) {
sb.append("*");
}
return sb.toString();
}
Algunas personas aplican este patrón a todas las concatenaciones de cuerdas. Sin embargo, esto
no es necesario porque JLS permite que un compilador de Java optimice las concatenaciones de
cadenas dentro de una sola expresión. Por ejemplo:
String s1 = ...;
String s2 = ...;
String test = "Hello " + s1 + ". Welcome to " + s2 + "\n";
(El compilador JIT puede optimizar eso aún más si puede deducir que s1 o s2 no puede ser null ).
Pero tenga en cuenta que esta optimización solo está permitida dentro de una sola expresión.
El lenguaje Java proporciona 7 operadores que realizan aritmética en valores enteros y de punto
flotante.
https://riptutorial.com/es/home 848
El operador de sustracción binaria resta un número de otro.
○
https://riptutorial.com/es/home 849
más cercano" IEE 768.
El significado de división
El operador / divide el operando izquierdo n (el dividendo ) y el operando derecho d (el divisor ) y
produce el resultado q (el cociente ).
La división entera de Java se redondea hacia cero. La Sección 15.17.2 de JLS especifica el
comportamiento de la división entera de Java de la siguiente manera:
Java división de punto flotante tiene más casos de borde a considerar. Sin embargo, la idea
básica es que el resultado q es el valor más cercano a la satisfacción de d . q = n .
La división de punto flotante nunca dará lugar a una excepción. En cambio, las operaciones que
se dividen por cero dan como resultado valores de INF y NaN; vea abajo.
De la definición anterior se desprende que a % b puede ser negativo solo si a es negativo, y solo
positivo si a es positivo. Además, la magnitud de a % b es siempre menor que la magnitud de b .
La operación de resto de punto flotante es una generalización del caso entero. El resultado de a %
b es el resto r se define por la relación matemática r = a - (b ⋅ q) donde:
• q es un número entero,
• es negativo solo si a / b es negativo y positivo solo si a / b es positivo, y
• su magnitud es tan grande como sea posible sin exceder la magnitud del verdadero
cociente matemático de a y b .
https://riptutorial.com/es/home 850
El resto de punto flotante puede producir valores de INF y NaN en casos de borde, como cuando b
es cero; vea abajo. No lanzará una excepción.
Nota IMPORTANTE:
Desbordamiento de enteros
Los valores enteros de Java de 32 y 64 bits están firmados y utilizan una representación binaria
de dos complementos. Por ejemplo, el rango de números representables como (32 bit) int -2 31 a
+2 31 - 1.
• Los valores "infinitos" o INF denotan números que son demasiado grandes. El valor +INF
denota números que son demasiado grandes y positivos. El valor -INF denota números que
son demasiado grandes y negativos.
• El "indefinido" / "no un número" o NaN denota valores resultantes de operaciones sin
sentido.
Los valores INF son producidos por operaciones flotantes que causan desbordamiento, o por
división por cero.
Los valores de NaN se producen dividiendo cero por cero, o calculando cero resto cero.
https://riptutorial.com/es/home 851
• Añadiendo + INF y -INF da NaN.
• La división por INF da +0.0 o -0.0.
• Todas las operaciones con uno o más operandos de NaN dan NaN.
Para obtener más detalles, consulte las subsecciones relevantes de JLS 15 . Tenga en cuenta
que esto es en gran parte "académico". Para cálculos típicos, un INF o NaN significa que algo ha
salido mal; por ejemplo, tiene datos de entrada incompletos o incorrectos, o el cálculo se ha
programado incorrectamente.
Los operadores == y != Son operadores binarios que se evalúan como true o false dependiendo
de si los operandos son iguales. El operador == da true si los operandos son iguales y false
contrario. El operador != Da false si los operandos son iguales y true contrario.
Estos operadores pueden usarse operandos con tipos primitivos y de referencia, pero el
comportamiento es significativamente diferente. Según el JLS, en realidad hay tres conjuntos
distintos de estos operadores:
Sin embargo, en todos los casos, el tipo de resultado de los operadores == y != Es boolean .
Nota: debe tener cuidado al usar == y != Para comparar valores de punto flotante.
https://riptutorial.com/es/home 852
Los operadores booleanos == y !=
Si ambos operandos son boolean , o uno es boolean y el otro es Boolean , estos operadores son los
operadores booleano == y != . El comportamiento es el siguiente:
UNA segundo A == B A! = B
Hay dos "trampas" que hacen que sea aconsejable usar == y != moderación con los valores de
verdad:
• Si usa == o != Para comparar dos objetos Boolean , entonces se usan los operadores de
referencia. Esto puede dar un resultado inesperado; ver Escaparate: usar == para comparar
objetos de envoltorios primitivos, como Integer
• El operador == puede ser mal escrito como = . Para la mayoría de los tipos de operandos,
este error conduce a un error de compilación. Sin embargo, para Boolean operandos boolean
y Boolean el error conduce a un comportamiento de tiempo de ejecución incorrecto; ver Pitfall
- Usar '==' para probar un booleano
s1.equals(s2); // true
https://riptutorial.com/es/home 853
http://www.riptutorial.com/java/example/8996/pitfall--using----to-compare-primitive-wrappers-
objects-such-as-integer .
Sin embargo, esto no es una "rareza" de Java, este comportamiento se especifica en los
estándares de punto flotante IEEE 754 y encontrará que está implementado por la mayoría de los
lenguajes de programación modernos. (Para obtener más información, consulte
http://stackoverflow.com/a/1573715/139985 ... ¡note que esto está escrito por alguien que estaba
"en la sala cuando se tomaron las decisiones"!)
int a = 10;
a++; // a now equals 11
a--; // a now equals 10 again
Cuando los operadores ++ y -- preceden a las variables, las operaciones se llaman pre-
incremento y pre-decremento respectivamente.
int x = 10;
--x; // x now equals 9
++x; // x now equals 10
int x=10;
System.out.println("x=" + x + " x=" + x++ + " x=" + x); // outputs x=10 x=10 x=11
System.out.println("x=" + x + " x=" + ++x + " x=" + x); // outputs x=11 x=12 x=12
System.out.println("x=" + x + " x=" + x-- + " x=" + x); // outputs x=12 x=12 x=11
https://riptutorial.com/es/home 854
System.out.println("x=" + x + " x=" + --x + " x=" + x); // outputs x=11 x=10 x=10
int x = 0;
x = x++ + 1 + x++; // x = 0 + 1 + 1
// do not do this - the last increment has no effect (bug!)
System.out.println(x); // prints 2 (not 3!)
Correcto:
int x = 0;
x = x++ + 1 + x; // evaluates to x = 0 + 1 + 1
x++; // adds 1
System.out.println(x); // prints 3
El Operador Condicional (? :)
Sintaxis
{condición para evaluar} ? {instrucción-ejecutada-en-verdadero} : {declaración-ejecutada-en-falso}
Es equivalente a
if (testCondition) {
result = value1;
} else {
result = value2;
}
Por ejemplo:
https://riptutorial.com/es/home 855
int absValue = a < 0 ? -a : a;
System.out.println("abs = " + absValue); // prints "abs = 10"
Es equivalente a
Uso común
Puede usar el operador condicional para asignaciones condicionales (como la comprobación de
nulos).
String x = "";
if (y != null) {
x = y.toString();
}
Dado que el Operador Condicional tiene la segunda prioridad más baja, por encima de los
Operadores de Asignación , rara vez es necesario usar paréntesis alrededor de la condición ,
pero se requiere paréntesis alrededor de la construcción completa del Operador Condicional
cuando se combina con otros operadores:
// parenthesis required
7 * (a > 0 ? 2 : 5)
a ? "a is true" :
b ? "a is false, b is true" :
c ? "a and b are false, c is true" :
"a, b, and c are false"
https://riptutorial.com/es/home 856
a ? x : (b ? y : (c ? z : w))
Nota:
1 - Tanto la especificación del lenguaje Java como el tutorial de Java llaman al operador ( ? : :) El operador
condicional . El Tutorial dice que es "también conocido como el Operador Ternario" ya que es (actualmente) el único
operador ternario definido por Java. La terminología de "Operador condicional" es consistente con C y C ++ y otros
idiomas con un operador equivalente.
El lenguaje Java proporciona 4 operadores que realizan operaciones en modo bit o lógicas en
operandos enteros o booleanos.
Las operaciones lógicas realizadas por estos operadores cuando los operandos son booleanos se
pueden resumir de la siguiente manera:
0 0 1 0 0 0
0 1 1 0 1 1
1 0 0 0 1 1
1 1 0 1 1 0
Tenga en cuenta que para los operandos enteros, la tabla anterior describe lo que sucede para
los bits individuales. Los operadores realmente operan en todos los 32 o 64 bits del operando u
operandos en paralelo.
El operador ~ se usa para invertir un valor booleano, o cambiar todos los bits en un operando
https://riptutorial.com/es/home 857
entero.
El operador & se usa para "enmascarar" algunos de los bits en un operando de enteros. Por
ejemplo:
El | operador se utiliza para combinar los valores de verdad de dos operandos. Por ejemplo:
Para obtener más ejemplos del uso de los operadores bitwise, vea Manipulación de bits.
Este operador verifica si el objeto es de una clase particular / tipo de interfaz. El operador
instanceof se escribe como:
Ejemplo:
true
Este operador aún devolverá verdadero si el objeto que se compara es la asignación compatible
con el tipo de la derecha.
Ejemplo:
https://riptutorial.com/es/home 858
class Vehicle {}
true
El operando de la izquierda para estos operadores debe ser una variable no final o un elemento
de una matriz. El operando de la derecha debe ser compatible con la asignación del operando de
la izquierda. Esto significa que o los tipos deben ser iguales, o el tipo de operando derecho debe
ser convertible al tipo de operandos izquierdo mediante una combinación de boxeo,
desempaquetado o ampliación. (Para detalles completos refiérase a JLS 5.2 ).
Tenga en cuenta que hay una conversión de tipos implícita antes de la asignación final.
1. =
2. +=
El operador "agregar y asignar": agrega el valor del operando de la mano derecha al valor del
operando de la mano izquierda y asigna el resultado al operando de la mano izquierda. Si el
operando de la izquierda tiene el tipo String , entonces este es un operador de "concatenar y
asignar".
3. -=
El operador "restar y asignar": resta el valor del operando derecho del valor del operando de la
izquierda y asigna el resultado al operando de la izquierda.
https://riptutorial.com/es/home 859
Ejemplo: c -= a es aproximadamente lo mismo que c = c - a
4. *=
El operador "multiplicar y asignar": multiplica el valor del operando de la mano derecha por el
valor del operando de la mano izquierda y asigna el resultado al operando de la mano izquierda. .
5. /=
El operador "dividir y asignar": divide el valor del operando de la mano derecha por el valor del
operando de la mano izquierda y asigna el resultado al operando de la mano izquierda.
6. %=
El operador "módulo y asignación": calcula el módulo del valor del operando de la derecha por el
valor del operando de la izquierda y asigna el resultado al operando de la izquierda.
7. <<=
8. >>=
9. >>>=
10. &=
11. |=
https://riptutorial.com/es/home 860
12. ^=
Java proporciona un operador condicional y un operador condicional, que toman uno o dos
operandos de tipo boolean y producen un resultado boolean . Estos son:
{
boolean L = evaluate(<left-expr>);
if (L) {
return evaluate(<right-expr>);
} else {
// short-circuit the evaluation of the 2nd operand expression
return false;
}
}
{
boolean L = evaluate(<left-expr>);
if (!L) {
return evaluate(<right-expr>);
} else {
// short-circuit the evaluation of the 2nd operand expression
return true;
}
}
https://riptutorial.com/es/home 861
}
La primera versión funciona en la mayoría de los casos, pero si el argumento de value es null , se
lanzará una NullPointerException .
En la segunda versión hemos añadido una prueba de "guarda". El value != null && value == 0
expresión se evalúa realizando primero el value != null Prueba value != null . Si la prueba null
tiene éxito (es decir, se evalúa como true ), se evalúa el value == 0 expresión. Si la prueba null
falla, entonces la evaluación del value == 0 se omite (en cortocircuito) y no obtenemos una
NullPointerException .
El lenguaje Java proporciona tres operadores para realizar cambios a nivel de bits en valores
enteros de 32 y 64 bits. Todos estos son operadores binarios con el primer operando que es el
valor que se va a cambiar, y el segundo operando que dice qué tan lejos desplazarse.
• El operador ">>" o de cambio aritmético desplaza el valor dado por el primer operando hacia
la derecha por el número de posiciones de bit dado por el segundo operando. Las
posiciones vacías en el extremo izquierdo se llenan copiando el bit más a la izquierda. Este
proceso se conoce como extensión de signo .
Notas:
1. Estos operadores requieren un valor int o long como el primer operando, y producen un
https://riptutorial.com/es/home 862
valor con el mismo tipo que el primer operando. (Necesitará usar un tipo explícito de
conversión al asignar el resultado de un cambio a una variable de byte , short o char ).
2. Si utiliza un operador de cambio con un primer operando que es un byte , char o short , se
promueve a un int y la operación produce un int .)
4. Los bits que se desvían del extremo izquierdo o derecho por la operación se descartan.
(Java no proporciona un operador de "rotación" primitivo).
La siguiente tabla le ayudará a ver los efectos de los tres operadores de turno. (Los números se
han expresado en notación binaria para ayudar a la visualización).
Desde Java 8 en adelante, el operador Lambda ( -> ) es el operador utilizado para introducir una
expresión Lambda. Hay dos sintaxis comunes, como se ilustra en estos ejemplos:
https://riptutorial.com/es/home 863
Java SE 8
Una expresión lambda define una función anónima o, más correctamente, una instancia de una
clase anónima que implementa una interfaz funcional .
(Este ejemplo se incluye aquí para estar completo. Consulte el tema de Expresiones de Lambda
para el tratamiento completo).
Los operadores < , <= , > y >= son operadores binarios para comparar tipos numéricos. El
significado de los operadores es como usted esperaría. Por ejemplo, si a y b se declaran como
cualquiera de los tipos de byte , short , char , int , long , float , double o los cuadros
correspondientes:
- `a < b` tests if the value of `a` is less than the value of `b`.
- `a <= b` tests if the value of `a` is less than or equal to the value of `b`.
- `a > b` tests if the value of `a` is greater than the value of `b`.
- `a >= b` tests if the value of `a` is greater than or equal to the value of `b`.
Los operadores relacionales se pueden utilizar para comparar números con diferentes tipos. Por
ejemplo:
int i = 1;
long l = 2;
if (i < l) {
System.out.println("i is smaller");
}
Los operadores relacionales pueden usarse cuando uno o ambos números son instancias de
tipos numéricos en caja. Por ejemplo:
https://riptutorial.com/es/home 864
Debe tener cuidado con las comparaciones relacionales que involucran números de punto
flotante:
• Las expresiones que computan números de punto flotante a menudo incurren en errores de
redondeo debido al hecho de que las representaciones de punto flotante de la computadora
tienen una precisión limitada.
• Al comparar un tipo de entero y un tipo de punto flotante, la conversión del entero a punto
flotante también puede llevar a errores de redondeo.
Finalmente, Java sí admite el uso de operadores relacionales con cualquier tipo distinto a los
enumerados anteriormente. Por ejemplo, no puede usar estos operadores para comparar
cadenas, matrices de números, etc.
https://riptutorial.com/es/home 865
Capítulo 125: Manipulación de bits
Observaciones
• A diferencia de C / C ++, Java es completamente neutral con respecto al hardware
subyacente de la máquina. No obtienes un comportamiento endiano grande o pequeño por
defecto; Tienes que especificar explícitamente qué comportamiento quieres.
• El tipo de byte está firmado, con el rango de -128 a +127. Para convertir un valor de byte a
su equivalente sin signo, enmascararlo con 0xFF de esta manera: (b & 0xFF) .
Examples
Empaquetar / desempaquetar valores como fragmentos de bits
Es común que el rendimiento de la memoria comprima múltiples valores en un solo valor primitivo.
Esto puede ser útil para pasar información diversa a una sola variable.
Por ejemplo, uno puede empaquetar 3 bytes, como el código de color en RGB , en un solo int.
https://riptutorial.com/es/home 866
(byte)(x >> 16)
};
Suponiendo que deseamos modificar el bit n de una primitiva entera, i (byte, short, char, int o
long):
Huellas dactilares
FIRST_BIT: true
SECOND_BIT: false
THIRD_BIT: true
FOURTh_BIT: false
FIFTH_BIT: true
BIT_55: true
que coincide con la máscara que nos pasa como checkBitMask parámetro: FIRST_BIT | THIRD_BIT |
FIFTH_BIT | BIT_55 .
Expresando el poder de 2
Para expresar la potencia de 2 (2 ^ n) de enteros, se puede usar una operación de cambio de bits
https://riptutorial.com/es/home 867
que permita especificar explícitamente la n .
La sintaxis es básicamente:
Ejemplos:
Esto es especialmente útil cuando se definen valores constantes que deberían hacer evidente
que se usa una potencia de 2, en lugar de usar valores hexadecimales o decimales.
Si un entero x es una potencia de 2, solo se establece un bit, mientras que x-1 tiene todos los bits
establecidos después de eso. Por ejemplo: 4 es 100 y 3 es 011 como número binario, que satisface
la condición mencionada anteriormente. El cero no es una potencia de 2 y debe comprobarse
explícitamente.
boolean isPowerOfTwo(int x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
Supongamos que tenemos tres tipos de permisos, LEER , ESCRIBIR y EJECUTAR . Cada
permiso puede variar de 0 a 7. (Supongamos un sistema de números de 4 bits)
¿Cómo podemos obtener los permisos (número de 12 bits) establecidos anteriormente (número
https://riptutorial.com/es/home 868
de 12 bits)?
Entonces, así es como podemos obtener los permisos de EJECUTAR del RECURSO . Ahora,
¿qué pasa si queremos obtener los permisos de LEER del RECURSO ?
¿Derecha? Probablemente estás asumiendo esto? Sin embargo, los permisos se obtienen en
1024. Queremos obtener solo los permisos de LEER para el recurso. No te preocupes, por eso
tuvimos los operadores de turno. Si vemos, los permisos de LECTURA están 8 bits detrás del
resultado real, por lo tanto, si se aplica algún operador de cambio, ¿cuál llevará los permisos de
LECTURA a la derecha del resultado? ¿Qué pasa si hacemos:
0100 0000 0000 >> 8 => 0000 0000 0100 (debido a que es un número positivo
reemplazado por 0, si no te importa la señal, solo usa el operador de turno derecho sin
signo)
Ahora, por ejemplo, tenemos permisos de LEER , ESCRIBIR , EJECUTAR para un RECURSO ,
¿qué podemos hacer para hacer los permisos para este RECURSO ?
Tomemos primero el ejemplo de los permisos binarios. (Todavía asumiendo sistema de número
de 4 bits)
LEER = 0001
ESCRIBIR = 0100
EJECUTAR = 0110
Pero los permisos se representan en realidad (en nuestro ejemplo) como 0001 0100 0110
Entonces, para hacer esto, sabemos que LEER se coloca 8 bits atrás, WRITE se coloca 4 bits
https://riptutorial.com/es/home 869
atrás y PERMISOS se coloca en el último. El sistema numérico que se usa para los permisos de
RECURSOS es en realidad 12 bits (en nuestro ejemplo). Puede (será) diferente en diferentes
sistemas.
Ahora, si agregamos los resultados del cambio anterior, será algo así como;
clase java.util.BitSet
Desde la versión 1.7 hay una clase java.util.BitSet que proporciona una interfaz de manipulación y
almacenamiento de bits simple y fácil de usar:
final BitSet bitSet = new BitSet(8); // by default all bits are unset
bitSet.set(3); // {0, 2, 3, 4, 6}
bitSet.flip(6); // {0, 2, 4}
BitSet implementa Clonable y Serializable , y bajo el capó, todos los valores de bit se almacenan
en el campo de long[] words , que se expande automáticamente.
bitSet.and(new BitSet(8));
bitSet.or(new BitSet(8));
bitSet.xor(new BitSet(8));
https://riptutorial.com/es/home 870
bitSet.andNot(new BitSet(8));
En Java, todos los primitivos numéricos están firmados. Por ejemplo, un int siempre representa
valores de [-2 ^ 31 - 1, 2 ^ 31], manteniendo el primer bit para firmar el valor: 1 para el valor
negativo, 0 para el positivo.
Los operadores de turno básicos >> y << son operadores firmados. Conservarán el signo del valor.
Pero es común que los programadores utilicen números para almacenar valores sin firmar . Para
un int, significa cambiar el rango a [0, 2 ^ 32 - 1], para tener el doble de valor que con un int
firmado.
Para aquellos usuarios avanzados, el bit para firmar no tiene significado. Es por eso que Java
agregó >>> , un operador de cambio a la izquierda, sin tener en cuenta ese bit de signo.
Esto viene de la definición pretendida de cambio a la derecha. Como llena los lugares vacíos de
la izquierda, no hay ninguna decisión que tomar con respecto al bit de señal. Como consecuencia,
no hay necesidad de 2 operadores diferentes.
https://riptutorial.com/es/home 871
Capítulo 126: Mapa débil
Introducción
Conceptos de Hashmap débil
Examples
Conceptos de HashHashmap
Puntos clave:-
Referencias débiles : los objetos a los que solo se hace referencia por referencias débiles se
recolectan con entusiasmo; El GC no esperará hasta que necesite memoria en ese caso.
Ejemplo: -
hashMap.put(keyHashMap, "Ankita");
weakHashMap.put(keyWeakHashMap, "Atul");
System.gc();
System.out.println("Before: hash map value:"+hashMap.get("keyHashMap")+" and weak hash
map value:"+weakHashMap.get("keyWeakHashMap"));
keyHashMap = null;
keyWeakHashMap = null;
System.gc();
https://riptutorial.com/es/home 872
El método de tamaño de llamada () en el objeto HashMap devolverá el mismo número de pares
clave-valor. el tamaño disminuirá solo si el método remove () se llama explícitamente en el objeto
HashMap.
https://riptutorial.com/es/home 873
Capítulo 127: Mapa Enum
Introducción
La clase Java EnumMap es la implementación especializada de mapas para claves de
enumeración. Hereda las clases Enum y AbstractMap.
Examples
Ejemplo de libro de mapas Enum
import java.util.*;
class Book {
int id;
String name,author,publisher;
int quantity;
public Book(int id, String name, String author, String publisher, int quantity) {
this.id = id;
this.name = name;
this.author = author;
this.publisher = publisher;
this.quantity = quantity;
}
}
public class EnumMapExample {
// Creating enum
public enum Key{
One, Two, Three
};
public static void main(String[] args) {
EnumMap<Key, Book> map = new EnumMap<Key, Book>(Key.class);
// Creating Books
Book b1=new Book(101,"Let us C","Yashwant Kanetkar","BPB",8);
Book b2=new Book(102,"Data Communications & Networking","Forouzan","Mc Graw Hill",4);
Book b3=new Book(103,"Operating System","Galvin","Wiley",6);
// Adding Books to Map
map.put(Key.One, b1);
map.put(Key.Two, b2);
map.put(Key.Three, b3);
// Traversing EnumMap
for(Map.Entry<Key, Book> entry:map.entrySet()){
Book b=entry.getValue();
System.out.println(b.id+" "+b.name+" "+b.author+" "+b.publisher+" "+b.quantity);
}
}
}
https://riptutorial.com/es/home 874
Capítulo 128: Mapas
Introducción
La interfaz java.util.Map representa una asignación entre las claves y sus valores. Un mapa no
puede contener claves duplicadas; y cada clave puede asignarse a un máximo de un valor.
Como Map es una interfaz, entonces necesita crear una instancia de una implementación concreta
de esa interfaz para poder usarla; hay varias implementaciones de Map , y en su mayoría se
utilizan java.util.HashMap y java.util.TreeMap
Observaciones
Un mapa es un objeto que almacena claves con un valor asociado para cada clave. Una clave y
su valor a veces se llaman un par clave / valor o una entrada . Los mapas suelen proporcionar
estas características:
La implementación de mapa más utilizada es HashMap . Funciona bien con teclas que son
cadenas o números.
Los mapas simples como HashMap no están ordenados. Iterar a través de pares clave / valor
puede devolver entradas individuales en cualquier orden. Si necesita recorrer de forma controlada
las entradas del mapa, debe mirar lo siguiente:
• Los mapas ordenados , como TreeMap , recorrerán las claves en su orden natural (o en un
orden que puede especificar, al proporcionar un Comparador ). Por ejemplo, se esperaría
que un mapa ordenado que usa números como claves itere a través de sus entradas en
orden numérico.
Examples
Agregar un elemento
1. Adición
https://riptutorial.com/es/home 875
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
System.out.println(map.get(1));
2. Anular
String currentVal;
Map<Integer, String> map = new TreeMap<>();
currentVal = map.put(1, "First element.");
System.out.println(currentVal);// Will print null
currentVal = map.put(2, "Second element.");
System.out.println(currentVal); // Will print null yet again
currentVal = map.put(2, "This will replace 'Second element'");
System.out.println(currentVal); // will print Second element.
System.out.println(map.size()); // Will print 2 as key having
// value 2 was replaced.
map.putAll(map2);
System.out.println(map.size());
Salida:
Para agregar muchos artículos puedes usar una clase interna como esta:
https://riptutorial.com/es/home 876
put(4, "low");
put(1, "too slow");
}};
Tenga en cuenta que crear una clase interna anónima no siempre es eficiente y puede provocar
pérdidas de memoria, por lo que, cuando sea posible, use un bloque de inicialización en su lugar:
static {
// Now no inner classes are created so we can avoid memory leaks
put(5, "high");
put(4, "low");
put(1, "too slow");
}
El ejemplo anterior hace que el mapa sea estático. También se puede utilizar en un contexto no
estático eliminando todas las apariciones de static .
Además de que la mayoría de las implementaciones son compatibles con putAll , que puede
agregar todas las entradas de un mapa a otro de esta manera:
another.putAll(one);
1. Utilizando getOrDefault
2. Usando forEach
https://riptutorial.com/es/home 877
3. Usando replaceAll
4. Usando putIfAbsent
5. Utilizando eliminar
6. Usando reemplazar
Si la clave está presente, el valor se reemplaza por un nuevo valor. Si la llave no está
presente, no hace nada.
7. Usando computeIfAbsent
Este método agrega una entrada en el mapa. la clave se especifica en la función y el valor es el
resultado de la aplicación de la función de mapeo
https://riptutorial.com/es/home 878
map.computeIfAbsent("peter", k->map.get("john")+10); //{john=20, paul=30, peter=40,
kelly=30} //peter already present
8. Usando computeIfPresent
Este método agrega una entrada o modifica una entrada existente en el Mapa. No hace nada si
una entrada con esa clave no está presente.
9. Utilizando compute
Este método reemplaza el valor de una clave por el valor recién calculado
Agrega el par clave-valor al mapa, si la clave no está presente o el valor de la clave es nulo
Reemplaza el valor con el valor recién calculado, si la clave está presente La clave se elimina del
mapa, si el nuevo valor calculado es nulo
//Adds the key-value pair to the map, if key is not present or value for the key is null
map.merge("kelly", 50 , (k,v)->map.get("john")+10); // {john=20, paul=30, peter=40,
kelly=50}
//Replaces the value with the newly computed value, if the key is present
map.merge("peter", 50 , (k,v)->map.get("john")+10); //{john=20, paul=30, peter=30,
kelly=50}
Borrar el mapa
https://riptutorial.com/es/home 879
map.put(1, "First element.");
map.put(2, "Second element.");
map.put(3, "Third element.");
map.clear();
System.out.println(map.size()); // => 0
Los mapas proporcionan métodos que le permiten acceder a las claves, valores o pares clave-
valor del mapa como colecciones. Puedes recorrer estas colecciones. Dado el siguiente mapa por
ejemplo:
Huellas dactilares:
Darin Dimitrov
Jon Skeet
Balus
keySet()proporciona las claves del mapa como un Set . Set se utiliza porque las claves no pueden
contener valores duplicados. Iterando a través del conjunto produce cada tecla a su vez. Los
HashMaps no se ordenan, por lo que en este ejemplo, las claves se pueden devolver en cualquier
orden.
Huellas dactilares:
715567
927654
708826
values()devuelve los valores del mapa como una Collection . Iterando a través de la colección
produce cada valor a su vez. Nuevamente, los valores pueden ser devueltos en cualquier orden.
https://riptutorial.com/es/home 880
Iterando a través de claves y valores juntos.
Huellas dactilares:
Use putAll para poner a cada miembro de un mapa en otro. Las claves ya presentes en el mapa
tendrán sus valores correspondientes sobrescritos.
numbers.putAll(other_numbers)
"One" -> 1
"Two" -> 2
"Three" -> 4 //old value 3 was overwritten by new value 4
Si desea combinar valores en lugar de sobrescribirlos, puede usar Map.merge , agregado en Java
8, que utiliza un BiFunction proporcionado por el BiFunction para combinar valores para claves
duplicadas. merge funciona con claves y valores individuales, por lo que deberá usar un bucle o
Map.forEach . Aquí concatenamos cadenas para claves duplicadas:
Si desea aplicar la restricción, no hay claves duplicadas, puede usar una función de combinación
que lanza un AssertionError :
mapA.forEach((k, v) ->
mapB.merge(k, v, (v1, v2) ->
https://riptutorial.com/es/home 881
{throw new AssertionError("duplicate values for key: "+k);}));
if (num.containsKey("one")) {
System.out.println(num.get("one")); // => first
}
https://riptutorial.com/es/home 882
Más formalmente, no hay garantía de que map.contains(key) <=> map.get(key)!=null
Esta sección proporciona código y puntos de referencia para diez implementaciones de ejemplo
únicas que repiten las entradas de un Map<Integer, Integer> y generan la suma de los valores de
Integer . Todos los ejemplos tienen una complejidad algorítmica de Θ(n) , sin embargo, los puntos
de referencia siguen siendo útiles para proporcionar información sobre qué implementaciones son
más eficientes en un entorno del "mundo real".
Iterator<Integer> it = map.keySet().iterator();
while (it.hasNext()) {
Integer key = it.next();
sum += key + map.get(key);
}
https://riptutorial.com/es/home 883
map.entrySet().stream().forEach(e -> sum += e.getKey() + e.getValue());
map.entrySet()
.stream()
.parallel()
.forEach(e -> sum += e.getKey() + e.getValue());
https://riptutorial.com/es/home 884
3. Rendimiento promedio de 10 ensayos (100000 elementos) Mejor: 1184.767 ± 332.968 μs /
op
4. Una comparación de las variaciones de rendimiento en relación con el tamaño del mapa
x: Size of Map
f(x): Benchmark Score (μs/op)
https://riptutorial.com/es/home 885
---------------------------------------------------
10 | 0.333 1.631 2.752 5.937 8.024
3 | 0.309 1.971 4.147 8.147 10.473
6 | 0.372 2.190 4.470 8.322 10.531
1 | 0.405 2.237 4.616 8.645 10.707
Tests 2 | 0.376 2.267 4.809 8.403 10.910
f(x) 7 | 0.473 2.448 5.668 9.790 12.125
9 | 0.565 2.830 5.952 13.22 16.965
4 | 0.808 5.012 8.813 13.939 17.407
5 | 0.81 5.104 8.533 14.064 17.422
8 | 5.173 12.499 17.351 24.671 30.403
Antes de usar su propio objeto como clave, debe anular los métodos hashCode () y equals () de
su objeto.
class MyKey {
private String name;
MyKey(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof MyKey) {
return this.name.equals(((MyKey)obj).name);
}
return false;
}
@Override
public int hashCode() {
return this.name.hashCode();
}
}
hashCodedecidirá a qué hash bucket pertenecerá la clave e equals determinará qué objeto dentro
de ese hash bucket.
Sin estos métodos, la referencia de su objeto se usará para la comparación anterior que no
funcionará a menos que use la misma referencia de objeto cada vez.
Uso de HashMap
HashMap es una implementación de la interfaz de mapa que proporciona una estructura de datos
para almacenar datos en pares clave-valor.
1. Declarar HashMap
https://riptutorial.com/es/home 886
KeyType y ValueType deben ser tipos válidos en Java, como - Cadena, Entero, Flotante o
cualquier clase personalizada como Empleado, Estudiante, etc.
Para poner un valor en HashMap, tenemos que llamar al método put en el objeto HashMap
pasando la clave y el valor como parámetros.
myMap.put("key1", 1);
myMap.put("key2", 2);
Si llama al método put con la clave que ya existe en el mapa, el método anulará su valor y
devolverá el valor anterior.
Para obtener el valor de un HashMap, debe llamar al método get , pasando la clave como
parámetro.
Si pasa una clave que no existe en el HashMap, este método devolverá null
myMap.containsKey(varKey);
myMap.containsValue(varValue);
Los métodos anteriores devolverán un valor boolean verdadero o falso si la clave, el valor existe
en el Mapa o no.
Introducción
Maps almacenan pares clave / valor, donde cada clave tiene un valor asociado. Dada una clave
particular, el mapa puede buscar el valor asociado muy rápidamente.
Maps , también conocidos como matriz asociada, son un objeto que almacena los datos en forma
de claves y valores. En Java, los mapas se representan mediante la interfaz de mapas, que no es
una extensión de la interfaz de colección.
https://riptutorial.com/es/home 887
• Camino 1: -
• Camino 2: -
• Camino 3: -
• Camino 4: -
• Camino 5: -
//Java 8
final Map<String, String> map =
Arrays.stream(new String[][] {
{ "name", "A" },
{ "address", "Malviya-Nagar" },
{ "city", "jaipur" },
}).collect(Collectors.toMap(m -> m[0], m -> m[1]));
System.out.println(map);
• Camino 6: -
https://riptutorial.com/es/home 888
map.put("c", "d");
}
https://riptutorial.com/es/home 889
Capítulo 129: Máquina virtual de Java (JVM)
Examples
Estos son los fundamentos.
JVM es una máquina de computación abstracta o máquina virtual que reside en su RAM.
Tiene un entorno de ejecución independiente de la plataforma que interpreta el código de bytes
de Java en un código de máquina nativo. (Javac es un compilador de Java que compila su código
Java en Bytecode)
El programa Java se ejecutará dentro de la JVM que luego se asignará a la máquina física
subyacente. Es una de las herramientas de programación en JDK.
(El Byte code es un código independiente de la plataforma que se ejecuta en todas las plataformas
y el Machine code es un código específico de la plataforma que se ejecuta solo en plataformas
específicas como Windows o Linux; depende de la ejecución).
(Editado)
https://riptutorial.com/es/home 890
Capítulo 130: Método dinámico de envío
Introducción
¿Qué es el método dinámico de envío?
Observaciones
• Enlace dinámico = Enlace tardío
• Las clases abstractas no pueden ser instanciadas, pero pueden ser subclasificadas (Base
para una clase infantil)
• Un método abstracto es un método que se declara sin una implementación
• La clase abstracta puede contener una mezcla de métodos declarados con o sin una
implementación
• Cuando una clase abstracta está subclasificada, la subclase generalmente proporciona
implementaciones para todos los métodos abstractos en su clase principal. Sin embargo, si
no lo hace, entonces la subclase también debe ser declarada abstracta
• El envío de métodos dinámicos es un mecanismo mediante el cual una llamada a un
método anulado se resuelve en tiempo de ejecución. Así es como Java implementa el
polimorfismo en tiempo de ejecución.
• Upcasting: Convertir un subtipo en un supertipo, hacia arriba en el árbol de herencia.
• Polimorfismo en tiempo de ejecución = polimorfismo dinámico
Examples
Método dinámico de envío - Código de ejemplo
Clase abstracta :
package base;
/*
Abstract classes cannot be instantiated, but they can be subclassed
*/
public abstract class ClsVirusScanner {
https://riptutorial.com/es/home 891
System.out.println("Perform Virus Scanner Version Check");
}
import base.ClsVirusScanner;
//Child Class 3
class ClsFreeVersion extends ClsVirusScanner{
@Override
public void fnStartScan() {
super.fnVirusMalwareScan();
}
}; //ClsTrialVersion IS-A ClsVirusScanner
//Calling Class
public class ClsRunTheApplication {
https://riptutorial.com/es/home 892
final String VIRUS_SCANNER_VERSION = "TRIAL_VERSION";
}
}
Resultado:
Upcasting:
https://riptutorial.com/es/home 893
Capítulo 131: Métodos de la fábrica de
recolección
Introducción
La llegada de Java 9 trae muchas características nuevas a la API de colecciones de Java, una de
las cuales son los métodos de la fábrica de colecciones. Estos métodos permiten una fácil
inicialización de colecciones inmutables , ya sean vacías o no vacías.
Tenga en cuenta que estos métodos de fábrica solo están disponibles para las siguientes
interfaces: List<E> , Set<E> y Map<K, V>
Sintaxis
• static <E> List<E> of()
• static <E> List<E> of(E e1)
• static <E> List<E> of(E e1, E e2)
• static <E> List<E> of(E e1, E e2, ..., E e9, E e10)
• static <E> List<E> of(E... elements)
• static <E> Set<E> of()
• static <E> Set<E> of(E e1)
• static <E> Set<E> of(E e1, E e2)
• static <E> Set<E> of(E e1, E e2, ..., E e9, E e10)
• static <E> Set<E> of(E... elements)
• static <K,V> Map<K,V> of()
• static <K,V> Map<K,V> of(K k1, V v1)
• static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2)
• static <K,V> Map<K,V> of(K k1, V v1, K k2, V v2, ..., K k9, V v9, K k10, V v10)
• static <K,V> Map<K,V> ofEntries(Map.Entry<? extends K,? extends V>... entries)
Parámetros
https://riptutorial.com/es/home 894
Examples
Lista Ejemplos de métodos de fábrica
• List<Integer> immutableEmptyList = List.of();
○ Inicializa una List<Integer> vacía e inmutable List<Integer> .
• List<Integer> immutableList = List.of(1, 2, 3, 4, 5);
○ Inicializa una List<Integer> inmutable List<Integer> con cinco elementos iniciales.
• List<Integer> mutableList = new ArrayList<>(immutableList);
○ Inicializa una List<Integer> mutable List<Integer> de una List<Integer> inmutable
List<Integer> .
https://riptutorial.com/es/home 895
Capítulo 132: Métodos predeterminados
Introducción
El método predeterminado introducido en Java 8 permite a los desarrolladores agregar nuevos
métodos a una interfaz sin romper las implementaciones existentes de esta interfaz. Proporciona
flexibilidad para permitir que la interfaz defina una implementación que se utilizará como
predeterminada cuando una clase que implementa esa interfaz no puede proporcionar una
implementación de ese método.
Sintaxis
• Nombre del método vacío público predeterminado () {/ * cuerpo del método * /}
Observaciones
Métodos predeterminados
• Puede usarse dentro de una interfaz, para introducir un comportamiento sin forzar las
subclases existentes para implementarlo.
• Puede ser reemplazado por subclases o por una sub-interfaz.
• No se les permite anular los métodos en la clase java.lang.Object.
• Si una clase que implementa más de una interfaz, hereda los métodos predeterminados con
firmas de métodos idénticas de cada una de las interfaces, debe invalidar y proporcionar su
propia interfaz como si no fueran métodos predeterminados (como parte de la resolución de
la herencia múltiple).
• A pesar de que están destinadas a introducir un comportamiento sin romper las
implementaciones existentes, las subclases existentes con un método estático con la misma
firma de método que el método por defecto recién introducido todavía se romperán. Sin
embargo, esto es cierto incluso en el caso de introducir un método de instancia en una
superclase.
Métodos estáticos
• Puede usarse dentro de una interfaz, principalmente destinada a ser utilizada como un
método de utilidad para los métodos predeterminados.
• No puede ser reemplazado por subclases o por una sub-interfaz (está oculto para ellos). Sin
embargo, como es el caso de los métodos estáticos, incluso ahora, cada clase o interfaz
puede tener la suya propia.
• No se les permite anular los métodos de instancia en la clase java.lang.Object (como en la
https://riptutorial.com/es/home 896
actualidad es el caso de las subclases también).
A continuación se muestra una tabla que resume la interacción entre subclase y superclase.
SUPER_CLASS-INSTANCE- SUPER_CLASS-STATIC-
-
METHOD METHOD
SUB_CLASS-INSTANCE-
anula genera-compiletime-error
METHOD
SUB_CLASS-STATIC-
genera-compiletime-error se esconde
METHOD
A continuación se muestra una tabla que resume la interacción entre la interfaz y la clase de
implementación.
INTERFACE-DEFAULT- INTERFACE-ESTÁTICO-
-
METHOD MÉTODO
IMPL_CLASS-INSTANCE-
anula se esconde
METHOD
IMPL_CLASS-STATIC-
genera-compiletime-error se esconde
METHOD
Referencias:
• http://www.journaldev.com/2752/java-8-interface-changes-static-method-default-method
• https://docs.oracle.com/javase/tutorial/java/IandI/override.html
Examples
Uso básico de los métodos por defecto.
/**
* Interface with default method
*/
public interface Printable {
default void printString() {
System.out.println( "default implementation" );
}
}
https://riptutorial.com/es/home 897
/**
* Class which falls back to default implementation of {@link #printString()}
*/
public class WithDefault
implements Printable
{
}
/**
* Custom implementation of {@link #printString()}
*/
public class OverrideDefault
implements Printable {
@Override
public void printString() {
System.out.println( "overridden implementation" );
}
}
new WithDefault().printString();
new OverrideDefault().printString();
default implementation
overridden implementation
int getB();
@Override
public int getB() {
return 2;
}
}
https://riptutorial.com/es/home 898
System.out.println(new Sum().calculateSum());
Los métodos predeterminados también podrían usarse junto con los métodos de interfaz
estáticos:
System.out.println(new Sum().calculateSum());
En las clases, super.foo() buscará solo en superclases. Si desea llamar a una implementación
predeterminada desde una superinterfaz, necesita calificar a super con el nombre de la interfaz:
Fooable.super.foo() .
La respuesta simple es que le permite evolucionar una interfaz existente sin romper las
implementaciones existentes.
https://riptutorial.com/es/home 899
void backStroke();
}
Hicimos un gran trabajo, nuestra interfaz es muy popular, hay muchas implementaciones en todo
el mundo y usted no tiene control sobre su código fuente.
Después de 20 años, ha decidido agregar una nueva funcionalidad a la interfaz, pero parece que
nuestra interfaz está congelada porque romperá las implementaciones existentes.
Ahora todas las implementaciones existentes de nuestra interfaz pueden seguir funcionando.
Pero lo más importante es que pueden implementar el método recién agregado en su propio
tiempo.
Una de las razones más importantes de este cambio, y uno de sus usos más importantes, está en
el marco de las Colecciones Java. Oracle no pudo agregar un método foreach a la interfaz
existente de Iterable sin romper todo el código existente que implementó Iterable. Al agregar
métodos predeterminados, la implementación existente de Iterable heredará la implementación
predeterminada.
Las implementaciones en clases, incluidas las declaraciones abstractas, tienen prioridad sobre
todos los valores predeterminados de la interfaz.
https://riptutorial.com/es/home 900
}
}
La siguiente declaración
new FooSwimmer().backStroke();
Producirá
AbstractSwimmer.backStroke
La siguiente declaración
new FooSwimmer().backStroke();
Producirá
FooSwimmer.backStroke
public interface A {
default void foo() { System.out.println("A.foo"); }
}
public interface B {
default void foo() { System.out.println("B.foo"); }
}
https://riptutorial.com/es/home 901
Aquí hay dos interfaces que declaran default método default foo con la misma firma.
Si intentas extend estas dos interfaces en la nueva interfaz, debes elegir entre dos, porque Java te
obliga a resolver esta colisión explícitamente.
Primero , puede declarar el método foo con la misma firma que el abstract , lo que anulará el
comportamiento A y B
Y cuando implement ABExtends en la class not tendrá que proporcionar la implementación foo :
https://riptutorial.com/es/home 902
Capítulo 133: Modelo de memoria de Java
Observaciones
El modelo de memoria de Java es la sección del JLS que especifica las condiciones bajo las
cuales se garantiza que un hilo vea los efectos de las escrituras en memoria realizadas por otro
hilo. La sección relevante en las ediciones recientes es "Modelo de memoria JLS 17.4" (en Java 8
, Java 7 , Java 6 )
Hubo una revisión importante del modelo de memoria de Java en Java 5 que (entre otras cosas)
cambió la forma en que funcionaba la volatile . Desde entonces, el modelo de memoria ha sido
esencialmente sin cambios.
Examples
Motivación para el modelo de memoria.
Si se usa esta clase es una aplicación de un solo hilo, entonces el comportamiento observable
será exactamente el que usted esperaría. Por ejemplo:
saldrá:
0, 0
1, 1
En lo que el hilo "principal" puede decir , las declaraciones en el método main() y el método doIt()
se ejecutarán en el orden en que están escritas en el código fuente. Este es un requisito claro de
la especificación del lenguaje Java (JLS).
https://riptutorial.com/es/home 903
Ahora considere la misma clase utilizada en una aplicación de subprocesos múltiples.
Reordenación de asignaciones
Una posible explicación de los resultados inesperados es que el compilador JIT ha cambiado el
orden de las asignaciones en el método doIt() . El JLS requiere que las instrucciones parezcan
ejecutarse en orden desde la perspectiva del hilo actual . En este caso, nada en el código del
método doIt() puede observar el efecto de un reordenamiento (hipotético) de esas dos
afirmaciones. Esto significa que al compilador JIT se le permitiría hacer eso.
https://riptutorial.com/es/home 904
Efectos de cachés de memoria
Una segunda explicación posible es el efecto del almacenamiento en memoria caché. En una
arquitectura de computadora clásica, cada procesador tiene un pequeño conjunto de registros y
una mayor cantidad de memoria. El acceso a los registros es mucho más rápido que el acceso a
la memoria principal. En las arquitecturas modernas, hay cachés de memoria que son más lentos
que los registros, pero más rápidos que la memoria principal.
Sincronización adecuada
Hasta ahora, hemos visto que el JLS permite al compilador JIT generar código que hace que el
código de un solo subproceso sea más rápido al reordenar o evitar las operaciones de memoria.
Pero, ¿qué sucede cuando otros hilos pueden observar el estado de las variables (compartidas)
en la memoria principal?
La respuesta es que los otros subprocesos pueden observar estados variables que parecen
imposibles ... según el orden del código de las declaraciones de Java. La solución a esto es usar
la sincronización apropiada. Los tres enfoques principales son:
Pero incluso con esto, es importante entender dónde se necesita la sincronización y en qué
efectos puede confiar. Aquí es donde entra en juego el modelo de memoria Java.
El modelo de memoria
El modelo de memoria de Java es la sección del JLS que especifica las condiciones bajo las
cuales se garantiza que un hilo vea los efectos de las escrituras en memoria realizadas por otro
hilo. El modelo de memoria se especifica con un cierto grado de rigor formal y (como resultado)
requiere una lectura detallada y cuidadosa para comprender. Pero el principio básico es que
ciertas construcciones crean una relación "sucede antes de" entre la escritura de una variable por
un hilo y una lectura posterior de la misma variable por otro hilo. Si la relación "sucede antes"
existe, el compilador JIT está obligado a generar código que garantice que la operación de lectura
vea el valor escrito por la escritura.
https://riptutorial.com/es/home 905
Armado con esto, es posible razonar acerca de la coherencia de la memoria en un programa Java
y decidir si esto será predecible y consistente para todas las plataformas de ejecución.
Relaciones de antes-antes
(La siguiente es una versión simplificada de lo que dice la especificación del lenguaje Java. Para
una comprensión más profunda, debe leer la especificación en sí).
Las relaciones Happens-Before son la parte del modelo de memoria que nos permite entender y
razonar sobre la visibilidad de la memoria. Como dice el JLS ( JLS 17.4.5 ):
"Se pueden ordenar dos acciones por una relación de suceso-antes . Si ocurre una
acción -antes de otra, entonces la primera es visible y ordenada antes de la segunda".
Comportamiento
Las acciones a las que se refiere la cita anterior se especifican en JLS 17.4.2 . Hay 5 tipos de
acciones enumeradas definidas por la especificación:
• Acciones de sincronización:
• Acciones externas. Una acción que tiene un resultado que depende del entorno en el que se
encuentra el programa.
• Acciones de divergencia del hilo. Estos modelan el comportamiento de ciertos tipos de bucle
infinito.
https://riptutorial.com/es/home 906
El orden del programa describe el orden de ejecución de la declaración dentro de un solo hilo.
• Una acción de desbloqueo en el monitor se sincroniza con todas las acciones de bloqueo
subsiguientes en ese monitor.
• Una escritura en una variable volátil se sincroniza con todas las lecturas posteriores de la
misma variable por cualquier hilo.
• Una acción que inicia un hilo (es decir, la llamada a Thread.start() ) se sincroniza con la
primera acción en el hilo que comienza (es decir, la llamada al método run() del hilo).
• La acción final en un hilo se sincroniza con cualquier acción en otro hilo que detecta la
terminación; por ejemplo, la devolución de una llamada join() o isTerminated() llamada que
devuelve true .
• Si un hilo interrumpe otro hilo, la llamada de interrupción en el primer hilo se sincroniza con
el punto donde otro hilo detecta que el hilo se interrumpió.
Más específicamente, se garantiza que una lectura de una variable v observe una escritura en v si
y solo si sucede la write(v) - antes de la read(v) Y no hay escritura v a la v . Si hay escrituras
intermedias, entonces la read(v) puede ver los resultados de ellas en lugar de la anterior.
Las reglas que definen el suceso antes de ordenar son las siguientes:
• Regla Happens-Before # 2 : hay un borde antes del evento desde el final de un constructor
de un objeto hasta el inicio de un finalizador para ese objeto.
Además, varias clases en las bibliotecas estándar de Java se especifican para definir relaciones
de suceso antes . Puede interpretar que esto significa que sucede de alguna manera , sin
https://riptutorial.com/es/home 907
necesidad de saber exactamente cómo se va a cumplir la garantía.
Presentaremos algunos ejemplos para mostrar cómo aplicar el suceso antes del razonamiento
para verificar que las escrituras sean visibles en las lecturas posteriores.
4. write(a) sucede antes de write(b) y write(b) sucede antes de read(a) IMPLICA write(a)
sucede antes de read(a) .
5. write(b) sucede antes de read(a) y read(a) sucede antes de read(b) IMPLICA write(b)
sucede antes de read(b) .
Resumiendo:
6. La relación write(a) sucede antes de read(a) significa que se garantiza que la declaración a
a + b ve el valor correcto de a .
7. La relación write(b) sucede antes de read(b) significa que se garantiza que la declaración a
a + b ve el valor correcto de b .
https://riptutorial.com/es/home 908
private int b; // NOT volatile
En otras palabras, para esta secuencia en particular, tenemos la garantía de que el segundo
subproceso verá la actualización de la variable no volátil b realizada por el primer subproceso. Sin
embargo, también debe quedar claro que si las asignaciones en el método de update fueran al
revés, o el método de observe() leyera la variable b antes de a , entonces la cadena de suceso
antes se rompería. La cadena también se rompería si volatile-read(a) en el segundo hilo no fuera
posterior a la volatile-write(a) en el primer hilo.
Cuando se rompe la cadena, no hay garantía de que observe() verá el valor correcto de b .
https://riptutorial.com/es/home 909
Para analizar esto completamente, debemos considerar todas las posibles interrelaciones de las
declaraciones en el subproceso uno y el subproceso dos. En su lugar, consideraremos sólo dos
de ellos.
En este caso, es fácil ver que hay una cadena de write(b, 3) antes de write(b, 3) para read(b) .
Además, no hay que intervenir escribir a b . Por lo tanto, para este escenario, se garantiza que el
tercer subproceso verá que b tiene valor 3 .
Ahora, mientras hay una cadena de write(b, 3) antes de write(b, 3) para read(b) , hay una
acción de write(b, 1) interviene por el otro hilo. Esto significa que no podemos estar seguros de
qué valor read(b) .
(Aparte: Esto demuestra que no podemos confiar en la volatile para garantizar la visibilidad de
las variables no volátiles, excepto en situaciones muy limitadas).
El modelo de memoria es difícil de entender y difícil de aplicar. Es útil si necesita razonar acerca
de la corrección del código de subprocesos múltiples, pero no desea tener que hacer este
razonamiento para cada aplicación de subprocesos múltiples que escriba.
Si adopta los siguientes principios al escribir código concurrente en Java, puede evitar en gran
medida la necesidad de recurrir al suceso antes del razonamiento.
• Utilice estructuras de datos inmutables siempre que sea posible. Una clase inmutable
implementada correctamente será segura para subprocesos y no presentará problemas de
seguridad de subprocesos cuando la use con otras clases.
• Use mutexes primitivos u objetos Lock para sincronizar el acceso al estado en objetos
mutables que necesitan ser seguros para subprocesos 1 .
https://riptutorial.com/es/home 910
hilos de administración directamente.
1 - No todos los objetos deben estar a salvo de hilos. Por ejemplo, si un objeto u objetos están limitados a un hilo (es
decir, solo es accesible a un hilo), entonces su seguridad no es relevante.
https://riptutorial.com/es/home 911
Capítulo 134: Modificación Bytecode
Examples
¿Qué es Bytecode?
Bytecode es el conjunto de instrucciones utilizadas por la JVM. Para ilustrar esto tomemos este
programa Hello World.
ldc - Empuja una constante en la pila. En este caso, el String "Hello World".
Para la escritura:
https://riptutorial.com/es/home 912
• Jazmín
• Krakatau
Para la edición:
• Bibliotecas
○ ASM
○ Javassista
○ BCEL - No soporta Java 8+
• Herramientas
○ Bytecode-Viewer
○ JBytedit
○ reJ - No soporta Java 8+
○ JBE - No soporta Java 8+
En primer lugar las clases del tarro deben ser cargadas. Usaremos tres métodos para este
proceso:
• loadClasses (Archivo)
• readJar (JarFile, JarEntry, Mapa)
• getNode (byte [])
https://riptutorial.com/es/home 913
return classes;
}
try {
ClassNode cn = getNode(bytes);
classes.put(cn.name, cn);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
Con estos métodos, cargar y cambiar un archivo jar se convierte en una simple cuestión de
cambiar ClassNodes en un mapa. En este ejemplo, reemplazaremos todas las cadenas en el
contenedor por unas en mayúsculas usando la API del árbol.
Ahora que se han modificado todas las cadenas de ClassNode, debemos guardar los cambios.
Para guardar los cambios y tener una salida de trabajo, hay que hacer algunas cosas:
https://riptutorial.com/es/home 914
como bytes
• Guarda todos los bytes en un nuevo jar
Uso:
https://riptutorial.com/es/home 915
// Create jar output stream
JarOutputStream out = new JarOutputStream(new FileOutputStream(fileName));
// For each entry in the map, save the bytes
for (String entry : outBytes.keySet()) {
// Appent class names to class entries
String ext = entry.contains(".") ? "" : ".class";
out.putNextEntry(new ZipEntry(entry + ext));
out.write(outBytes.get(entry));
out.closeEntry();
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Load a class by from a ClassNode
*
* @param cn
* ClassNode to load
* @return
*/
public static Class<?> load(ClassNode cn) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
return new ClassDefiner(ClassLoader.getSystemClassLoader()).get(cn.name.replace("/", "."),
cw.toByteArray());
}
/**
* Classloader that loads a class from bytes.
*/
static class ClassDefiner extends ClassLoader {
public ClassDefiner(ClassLoader parent) {
super(parent);
}
https://riptutorial.com/es/home 916
out.putAll(process(nodes, mappings));
JarUtils.saveAsJar(out, "Input-new.jar");
}
SimpleRemapper es una clase existente en la biblioteca ASM. Sin embargo, solo permite que se
cambien los nombres de clase. Si desea cambiar el nombre de campos y métodos, debe crear su
propia implementación de la clase Remapper.
Javassist Basic
Permite escribir el primer transformador que realmente tome una clase hipotética
"com.my.to.be.instrumented.MyClass" y agregar a las instrucciones de cada método una llamada
de registro.
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
try {
// retrive default Javassist class pool
ClassPool cp = ClassPool.getDefault();
// get from the class pool our class with this qualified name
CtClass cc = cp.get("com.my.to.be.instrumented.MyClass");
https://riptutorial.com/es/home 917
// get all the methods of the retrieved class
CtMethod[] methods = cc.getDeclaredMethods()
for(CtMethod meth : methods) {
// The instrumentation code to be returned and injected
final StringBuffer buffer = new StringBuffer();
String name = meth.getName();
// just print into the buffer a log for example
buffer.append("System.out.println(\"Method " + name + " executed\" );");
meth.insertBefore(buffer.toString())
}
// create the byteclode of the class
byteCode = cc.toBytecode();
// remove the CtClass from the ClassPool
cc.detach();
} catch (Exception ex) {
ex.printStackTrace();
}
}
return byteCode;
}
}
Ahora, para usar este transformador (para que nuestra JVM invoque la transformación del método
en cada clase en el momento de la carga) necesitamos agregar este instrumento o esto con un
agente:
import java.lang.instrument.Instrumentation;
El último paso para iniciar nuestro primer experimento de instrumentación es registrar esta clase
de agente en la ejecución de la máquina JVM. La forma más fácil de hacerlo es registrarlo con
una opción en el comando de shell:
Como podemos ver, el proyecto de agente / transformador se agrega como un jar para la
ejecución de cualquier aplicación llamada MyJavaApplication que se supone que contiene una
clase llamada "com.my.to.be.instrumented.MyClass" para ejecutar nuestro código inyectado.
https://riptutorial.com/es/home 918
Capítulo 135: Modificadores sin acceso
Introducción
Los modificadores que no son de acceso no cambian la accesibilidad de las variables y los
métodos, pero sí les proporcionan propiedades especiales .
Examples
final
final en Java puede referirse a variables, métodos y clases. Hay tres reglas simples:
Usos
Algunos desarrolladores consideran una buena práctica marcar una variable final cuando puedas.
Si tiene una variable que no debe cambiarse, debe marcarla como final.
Un uso importante de final palabra clave final si para los parámetros del método. Si desea
enfatizar que un método no cambia sus parámetros de entrada, marque las propiedades como
finales.
Si su clase interna anónima quiere acceder a una variable, la variable debe marcarse como final
Java SE 8
https://riptutorial.com/es/home 919
Efectivamente las variables finales son una excepción. Estas son variables locales que se
escriben una sola vez y, por lo tanto, podrían ser definitivas. Efectivamente, también se puede
acceder a las variables finales desde clases anónimas.
Aunque el código a continuación es completamente legal cuando final variable final foo no es
static , en caso de static no compilará:
class TestFinal {
private final static List foo;
public Test() {
foo = new ArrayList();
}
}
La razón es, repitámoslo de nuevo, la variable final no puede ser reasignada . Como foo es
estático, se comparte entre todas las instancias de la clase TestFinal . Cuando se crea una nueva
instancia de una clase TestFinal , se invoca su constructor y, por lo tanto, foo se reasigna y el
compilador no lo permite. Una forma correcta de inicializar la variable foo en este caso es:
class TestFinal {
private static final List foo = new ArrayList();
//..
}
class TestFinal {
private static final List foo;
static {
foo = new ArrayList();
}
//..
}
final métodos final son útiles cuando la clase base implementa alguna funcionalidad importante
que la clase derivada no debe cambiar. También son más rápidos que los métodos no finales,
porque no hay un concepto de tabla virtual involucrado.
Todas las clases de envoltorio en Java son finales, como Integer , Long , etc. Los creadores de
estas clases no querían que nadie pudiera, por ejemplo, extender Integer a su propia clase y
cambiar el comportamiento básico de la clase Integer. Uno de los requisitos para hacer que una
clase sea inmutable es que las subclases no pueden anular los métodos. La forma más sencilla
de hacer esto es declarar la clase como final .
volátil
https://riptutorial.com/es/home 920
almacenado en caché local. Además, se garantiza que volatile lecturas y escrituras volatile son
atómicas (el acceso a un long o double no volatile no es atómico), lo que evita ciertos errores de
lectura / escritura entre varios subprocesos.
estático
La palabra clave static se usa en una clase, método o campo para hacer que funcionen
independientemente de cualquier instancia de la clase.
• Los campos estáticos son comunes a todas las instancias de una clase. No necesitan una
instancia para acceder a ellos.
• Los métodos estáticos se pueden ejecutar sin una instancia de la clase en la que se
encuentran. Sin embargo, solo pueden acceder a los campos estáticos de esa clase.
• Las clases estáticas pueden ser declaradas dentro de otras clases. No necesitan una
instancia de la clase en la que están para ser instanciados.
static {
// This block of code is run when the class first loads
staticVariable = 11;
}
int nonStaticVariable = 5;
void add() {
// We can access both static and non-static variables from non-static methods
nonStaticVariable += staticVariable;
}
https://riptutorial.com/es/home 921
public StaticInnerClass(int _number) {
number = _number;
}
void doSomething() {
// We can access number and staticVariable, but not nonStaticVariable
number += staticVariable;
}
int getNumber() {
return number;
}
}
}
System.out.println(object1.staticVariable); // 11
System.out.println(TestStatic.staticVariable); // 11
TestStatic.doSomething();
System.out.println(object1.staticVariable); // 10
System.out.println(object2.staticVariable); // 10
System.out.println(TestStatic.staticVariable); // 10
object1.add();
System.out.println(object1.nonStaticVariable); // 15
System.out.println(object2.nonStaticVariable); // 10
System.out.println(object3.getNumber()); // 100
System.out.println(object4.getNumber()); // 200
object3.doSomething();
System.out.println(object3.getNumber()); // 110
System.out.println(object4.getNumber()); // 200
resumen
https://riptutorial.com/es/home 922
class Honda extends Car
{
void tagLine()
{
System.out.println("Start Something Special");
}
}
sincronizado
class Shared
{
int i;
void SharedMethod2()
{
synchronized (this)
{
System.out.println("Thais access to currect object is synchronize "+this);
}
}
}
https://riptutorial.com/es/home 923
public void run()
{
s1.SharedMethod();
}
};
t1.start();
t2.start();
}
}
transitorio
Una variable que se declara como transitoria no se serializará durante la serialización de objetos.
strictfp
Java SE 1.2
El modificador strictfp se usa para cálculos de punto flotante. Este modificador hace que la
variable de punto flotante sea más consistente en múltiples plataformas y garantiza que todos los
cálculos de punto flotante se realicen de acuerdo con los estándares IEEE 754 para evitar errores
de cálculo (errores de redondeo), desbordamientos y subflujos en la arquitectura de 32 bits y 64
bits. Esto no se puede aplicar en métodos abstractos, variables o constructores.
class A{
strictfp void m(){}
}
https://riptutorial.com/es/home 924
Capítulo 136: Módulos
Sintaxis
• requiere java.xml;
• requiere java.xml público; # expone el módulo a dependientes para su uso
• exportaciones com.example.foo; # dependientes pueden usar tipos públicos en este
paquete
• exporta com.example.foo.impl a com.example.bar; # restringir el uso a un módulo
Observaciones
Se recomienda el uso de módulos, pero no es obligatorio, esto permite que el código existente
continúe trabajando en Java 9. También permite una transición gradual al código modular.
Cualquier código no modular se coloca en un módulo sin nombre cuando se compila. Este es un
módulo especial que puede usar tipos de todos los demás módulos pero solo de paquetes que
tienen una declaración de exports .
Las palabras clave, por ejemplo, el module etc., tienen un uso restringido dentro de la declaración
del módulo, pero se pueden seguir utilizando como identificadores en otros lugares.
Examples
Definiendo un módulo básico.
|-- module-info.java
|-- com
|-- example
|-- foo
|-- Foo.java
|-- bar
|-- Bar.java
module com.example {
requires java.httpclient;
exports com.example.foo;
}
El nombre del módulo debe ser único y se recomienda que use la misma notación de nombres de
https://riptutorial.com/es/home 925
DNS inverso que utilizan los paquetes para garantizar esto.
El módulo java.base , que contiene las clases básicas de Java, está visible de forma implícita en
cualquier módulo y no necesita ser incluido.
La declaración de requires nos permite utilizar otros módulos, en el ejemplo se importa el módulo
java.httpclient .
Un módulo también puede especificar qué paquetes exports y, por lo tanto, lo hace visible para
otros módulos.
El paquete com.example.foo declarado en la cláusula de exports será visible para otros módulos.
Cualquier com.example.foo de com.example.foo no se exportará, necesitan sus propias
declaraciones de export .
A la inversa, com.example.bar , que no figura en las cláusulas de exports , no será visible para otros
módulos.
https://riptutorial.com/es/home 926
Capítulo 137: Moneda y dinero
Examples
Añadir moneda personalizada
https://riptutorial.com/es/home 927
Capítulo 138: Motor de JavaScript Nashorn
Introducción
Nashorn es un motor de JavaScript desarrollado en Java por Oracle, y se ha lanzado con Java 8.
Nashorn permite integrar Javascript en aplicaciones Java a través de JSR-223 y permite
desarrollar aplicaciones de JavaScript independientes, y proporciona un mejor rendimiento en
tiempo de ejecución y un mejor cumplimiento con el ECMA Especificación de Javascript
normalizada.
Sintaxis
• ScriptEngineManager // Proporciona un mecanismo de descubrimiento e instalación para las
clases de ScriptEngine; utiliza un SPI (Interfaz de Proveedor de Servicios)
• ScriptEngineManager.ScriptEngineManager () // constructor recomendado
• ScriptEngine // Proporciona la interfaz para el lenguaje de scripting
• ScriptEngine ScriptEngineManager.getEngineByName (String shortName) // Método de
fábrica para la implementación dada
• Object ScriptEngine.eval (String script) // Ejecuta el script especificado
• Object ScriptEngine.eval (Reader Reader) // Carga y luego ejecuta un script desde la fuente
especificada
• ScriptContext ScriptEngine.getContext () // Devuelve el proveedor predeterminado de
enlaces, lectores y escritores
• void ScriptContext.setWriter (escritor escritor) // Establece el destino para enviar la salida del
script a
Observaciones
Nashorn es un motor de JavaScript escrito en Java e incluido en Java 8. Todo lo que necesita
está incluido en el paquete javax.script .
Tenga en cuenta que ScriptEngineManager proporciona una API genérica que le permite obtener
motores de secuencias de comandos para varios lenguajes de secuencias de comandos (es
decir, no solo Nashorn, no solo JavaScript).
Examples
Establecer variables globales
https://riptutorial.com/es/home 928
// Print the global variable
try {
engine.eval("print(textToPrint);");
} catch (ScriptException ex) {
ex.printStackTrace();
}
// Outcome:
// 'Data defined in Java.' printed on standard output
Hola Nashorn
// Outcome:
// 'Hello Nashorn!' printed on standard output
// Required imports
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.io.FileReader;
import java.io.FileNotFoundException;
// Outcome:
// 'Script from file!' printed on standard output
demo.js :
https://riptutorial.com/es/home 929
print('Script from file!');
// Outcome:
// Nothing printed on standard output, but
// stringWriter.toString() contains 'Redirected text!'
//String to be evaluated
String str = "3+2*4+5";
//Value after doing Arithmetic operation with operator precedence will be 16
//Outcome:
//Value of the string after arithmetic evaluation is printed on standard output.
//In this case '16.0' will be printed on standard output.
Es posible pasar objetos Java al motor Nashorn para ser procesados en código Java. Al mismo
tiempo, hay algunas construcciones específicas de JavaScript (y Nashorn), y no siempre está
claro cómo funcionan con los objetos java.
A continuación hay una tabla que describe el comportamiento de los objetos Java nativos dentro
de las construcciones de JavaScript.
https://riptutorial.com/es/home 930
Construcciones probadas:
1. Expresión en cláusula if. En la expresión JS, la cláusula if no tiene que ser booleana a
diferencia de Java. Se evalúa como falso para los llamados valores falsos (nulo, indefinido,
0, cadenas vacías, etc.)
2. Para cada declaración, Nashorn tiene un tipo especial de bucle, para cada una, que puede
iterar sobre diferentes objetos JS y Java.
3. Obtención del tamaño del objeto. En JS, los objetos tienen una longitud de propiedad, que
devuelve el tamaño de una matriz o una cadena.
Resultados:
Recomendaciones:
import java.io.FileReader;
import java.io.IOException;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
https://riptutorial.com/es/home 931
}
try {
//evaluate a script
/* pet.js */
/*
var Pet = Java.type("InterfaceImplementationExample.Pet");
new Pet() {
eat: function() { print("eat"); }
}
*/
pet.eat();
} catch (ScriptException ex) {
ex.printStackTrace();
}
// Outcome:
// 'eat' printed on standard output
}
}
try {
// Set value in the global name space of the engine
engine.put("name","Nashorn");
// Execute an hardcoded script
engine.eval("var value='Hello '+name+'!';");
// Get value
String value=(String)engine.get("value");
System.out.println(value);
} catch (ScriptException ex) {
// This is the generic Exception subclass for the Scripting API
ex.printStackTrace();
}
// Outcome:
// 'Hello Nashorn!' printed on standard output
https://riptutorial.com/es/home 932
Capítulo 139: NIO - Redes
Observaciones
SelectionKeydefine las diferentes operaciones e información seleccionables entre su Selector y
Canal . En particular, el archivo adjunto se puede utilizar para almacenar información relacionada
con la conexión.
El manejo de OP_READ es bastante sencillo. Sin embargo, se debe tener cuidado al tratar con
OP_WRITE : la mayoría de las veces, los datos se pueden escribir en sockets para que el evento se
siga disparando. Asegúrese de registrar OP_WRITE solo antes de que desee escribir datos (vea esa
respuesta ).
Además, OP_CONNECT debe cancelarse una vez que el Canal se haya conectado (porque, bueno,
está conectado. Vea esto y lo que responde en SO). Por lo tanto, la eliminación de OP_CONNECT
después de finishConnect() tuvo éxito.
Examples
Usando Selector para esperar eventos (ejemplo con OP_CONNECT)
NIO apareció en Java 1.4 e introdujo el concepto de "Canales", que se supone que son más
rápidos que la E / S normal. En cuanto a la red, el SelectableChannel es el más interesante, ya que
permite monitorear diferentes estados del Canal. Funciona de manera similar a la llamada al
sistema C select() : nos despertamos cuando ocurren ciertos tipos de eventos:
Permite la separación entre la detección de E / S de socket (algo se puede leer / escribir / ...) y
realizar la E / S (leer / escribir / ...). Especialmente, toda la detección de E / S se puede hacer en
un solo subproceso para múltiples sockets (clientes), mientras que la realización de E / S se
puede manejar en un conjunto de subprocesos o en cualquier otro lugar. Eso permite que una
aplicación se adapte fácilmente al número de clientes conectados.
1. Crear un Selector
2. Crear un SocketChannel
3. Registrar el SocketChannel al Selector
4. Bucle con el Selector para detectar eventos.
https://riptutorial.com/es/home 933
sc.configureBlocking(false); // ... non blocking
sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true); // ... set some options
// Register the Channel to the Selector for wake-up on CONNECT event and use some description
as an attachement
sc.register(sel, SelectionKey.OP_CONNECT, "Connection to google.com"); // Returns a
SelectionKey: the association between the SocketChannel and the Selector
System.out.println("Initiating connection");
if (sc.connect(new InetSocketAddress("www.google.com", 80)))
System.out.println("Connected"); // Connected right-away: nothing else to do
else {
boolean exit = false;
while (!exit) {
if (sel.select(100) == 0) // Did something happen on some registered Channels during
the last 100ms?
continue; // No, wait some more
// Something happened...
Set<SelectionKey> keys = sel.selectedKeys(); // List of SelectionKeys on which some
registered operation was triggered
for (SelectionKey k : keys) {
System.out.println("Checking "+k.attachment());
if (k.isConnectable()) { // CONNECT event
System.out.print("Connected through select() on "+k.channel()+" -> ");
if (sc.finishConnect()) { // Finish connection process
System.out.println("done!");
k.interestOps(k.interestOps() & ~SelectionKey.OP_CONNECT); // We are
already connected: remove interest in CONNECT event
exit = true;
} else
System.out.println("unfinished...");
}
// TODO: else if (k.isReadable()) { ...
}
keys.clear(); // Have to clear the selected keys set once processed!
}
}
System.out.print("Disconnecting ... ");
sc.shutdownOutput(); // Initiate graceful disconnection
// TODO: emtpy receive buffer
sc.close();
System.out.println("done");
Initiating connection
Checking Connection to google.com
Connected through 'select()' on java.nio.channels.SocketChannel[connection-pending
remote=www.google.com/216.58.208.228:80] -> done!
Disconnecting ... done
https://riptutorial.com/es/home 934
Capítulo 140: Nuevo archivo I / O
Sintaxis
• Paths.get (Cadena primero, Cadena ... más) // Crea una instancia de ruta por sus elementos
de cadena
• Paths.get (URI uri) // Crea una instancia de Path por un URI
Examples
Creando caminos
La clase de Path se usa para representar de manera programática una ruta en el sistema de
archivos (y, por lo tanto, puede apuntar a archivos y directorios, incluso a los que no existen)
Path p1 = Paths.get("/var/www");
Path p2 = Paths.get(URI.create("file:///home/testuser/File.txt"));
Path p3 = Paths.get("C:\\Users\\DentAr\\Documents\\HHGTDG.odt");
Path p4 = Paths.get("/home", "arthur", "files", "diary.tex");
La información sobre una ruta se puede obtener utilizando los métodos de un objeto Path :
• getFileName() devuelve el nombre del archivo (o, más específicamente, el último elemento
de la ruta)
https://riptutorial.com/es/home 935
• getParent() devuelve la ruta del directorio padre
Manipulando caminos
Path p5 = Paths.get("/home/");
Path p6 = Paths.get("arthur/files");
Path joined = p5.resolve(p6);
Path otherJoined = p5.resolve("ford/files");
joined.toString() == "/home/arthur/files"
otherJoined.toString() == "/home/ford/files"
Normalizando un camino
Los caminos pueden contener los elementos . (que apunta al directorio en el que se encuentra
actualmente) y .. (que apunta al directorio principal).
Cuando se usa en un camino, . puede eliminarse en cualquier momento sin cambiar el destino de
la ruta, y .. puede eliminarse junto con el elemento anterior.
Path p7 = Paths.get("/home/./arthur/../ford/files");
Path p8 = Paths.get("C:\\Users\\.\\..\\Program Files");
p7.normalize().toString() == "/home/ford/files"
p8.normalize().toString() == "C:\\Program Files"
Para interactuar con el sistema de archivos, utilice los métodos de la clase Files .
https://riptutorial.com/es/home 936
Comprobando la existencia
Para verificar la existencia del archivo o directorio al que apunta una ruta, utilice los siguientes
métodos:
Files.exists(Path path)
Files.notExists(Path path)
Path p1 = Paths.get("/var/www");
Path p2 = Paths.get("/home/testuser/File.txt");
Files.isDirectory(p1) == true
Files.isRegularFile(p1) == false
Files.isDirectory(p2) == false
Files.isRegularFile(p2) == true
Obteniendo propiedades
Esto se puede hacer usando los siguientes métodos:
Files.isReadable(Path path)
Files.isWritable(Path path)
Files.isExecutable(Path path)
https://riptutorial.com/es/home 937
Files.isHidden(Path path)
Files.isSymbolicLink(Path path)
Esto intenta obtener el tipo MIME de un archivo. Devuelve una cadena tipo MIME, como esta:
Archivos de lectura
Path p2 = Paths.get(URI.create("file:///home/testuser/File.txt"));
byte[] content = Files.readAllBytes(p2);
List<String> linesOfContent = Files.readAllLines(p2);
Escribiendo archivos
Los archivos se pueden escribir de forma mordida y lineal utilizando la clase Files
Path p2 = Paths.get("/home/testuser/File.txt");
List<String> lines = Arrays.asList(
new String[]{"First line", "Second line", "Third line"});
Files.write(p2, lines);
https://riptutorial.com/es/home 938
Capítulo 141: Objetos inmutables
Observaciones
Los objetos inmutables tienen un estado fijo (no establecedores), por lo que todo el estado debe
ser conocido en el momento de la creación del objeto.
Aunque no es técnicamente necesario, es una buena práctica hacer que todos los campos sean
final . Esto hará que la clase inmutable sea segura para subprocesos (véase Java Concurrency
in Practice, 3.4.1).
Los ejemplos muestran varios patrones que pueden ayudar a lograr esto.
Examples
Creación de una versión inmutable de un tipo mediante copia defensiva.
Algunos tipos y clases básicas en Java son fundamentalmente mutables. Por ejemplo, todos los
tipos de matriz son mutables, y también lo son las clases como java.util.Data . Esto puede ser
incómodo en situaciones donde se requiere un tipo inmutable.
Una forma de lidiar con esto es crear un envoltorio inmutable para el tipo mutable. Aquí hay una
envoltura simple para una matriz de enteros
Esta clase funciona utilizando una copia defensiva para aislar el estado mutable (el int[] ) de
cualquier código que pueda mutarlo:
• El constructor usa clone() para crear una copia distinta de la matriz de parámetros. Si la
persona que llama al constructor posteriormente cambió la matriz de parámetros, no
afectaría el estado de ImmutableIntArray .
• El método getValue() también usa clone() para crear la matriz que se devuelve. Si la
persona que llama cambiara la matriz de resultados, no afectaría el estado de
ImmutableIntArray .
https://riptutorial.com/es/home 939
lectura en la matriz envuelta; por ejemplo, obtener su longitud, obtener el valor en un índice
particular, y así sucesivamente.
Un objeto inmutable es un objeto cuyo estado no se puede cambiar. Una clase inmutable es una
clase cuyas instancias son inmutables por diseño e implementación. La clase de Java que se
presenta más comúnmente como un ejemplo de inmutabilidad es java.lang.String .
Una variante de esto es declarar el constructor como private y proporcionar un método de fábrica
public static .
• Todas las propiedades deben establecerse en el (los) constructor (es) o en los métodos de
fábrica.
• No debería haber setters.
• Si es necesario incluir configuradores por razones de compatibilidad de interfaz, no deberían
hacer nada o lanzar una excepción.
• Todas las propiedades deben ser declaradas como private y final .
• Para todas las propiedades que son referencias a tipos mutables:
○ la propiedad debe inicializarse con una copia en profundidad del valor pasado a través
del constructor, y
○ El captador de la propiedad debe devolver una copia profunda del valor de la
propiedad.
• La clase debe declararse como final para evitar que alguien cree una subclase mutable de
una clase inmutable.
https://riptutorial.com/es/home 940
Un par de otras cosas a tener en cuenta:
• La inmutabilidad no impide que el objeto sea anulable; Por ejemplo, null puede asignarse a
una variable de String .
• Si las propiedades de una clase inmutable se declaran como final , las instancias son
intrínsecamente seguras para subprocesos. Esto hace que las clases inmutables sean un
buen bloque de construcción para implementar aplicaciones de subprocesos múltiples.
Fallas típicas de diseño que evitan que una clase sea inmutable.
https://riptutorial.com/es/home 941
El siguiente fragmento de código muestra que la clase anterior no es inmutable:
Para solucionarlo, simplemente marque la propiedad del nombre como private y final .
import java.util.List;
import java.util.ArrayList;
public final class Names {
private final List<String> names;
public Names(List<String> names) {
this.names = new ArrayList<String>(names);
}
public List<String> getNames() {
return names;
}
public int size() {
return names.size();
}
}
Namesclase de Names parece inmutable a primera vista, pero no es como lo muestra el siguiente
código:
Esto sucedió porque un cambio en la Lista de referencia devuelto por getNames() puede modificar
la lista real de Names .
Para solucionar este problema, simplemente evite devolver referencias que hagan referencia a
objetos mutables de la clase, ya sea haciendo copias defensivas, de la siguiente manera:
o diseñando captadores de manera que solo se devuelvan otros objetos y primitivas inmutables ,
de la siguiente manera:
https://riptutorial.com/es/home 942
}
public int size() {
return names.size();
}
Inyectar el constructor con objeto (s) que pueden modificarse fuera de la clase inmutable
import java.util.List;
public final class NewNames {
private final List<String> names;
public Names(List<String> names) {
this.names = names;
}
public String getName(int index) {
return names.get(index);
}
public int size() {
return names.size();
}
}
Como los Names clase antes, también la clase NewNames parece inmutable a primera vista, pero no lo
es, de hecho, el siguiente fragmento de código demuestra lo contrario:
Para corregir esto, como en el defecto anterior, simplemente haga copias defensivas del objeto
sin asignarlo directamente a la clase inmutable, es decir, el constructor se puede cambiar de la
siguiente manera:
https://riptutorial.com/es/home 943
Personclase de Person parece inmutable a primera vista, pero supongamos que se define una
nueva subclase de Person :
ahora la mutabilidad de Person (im) puede ser explotada a través del polimorfismo usando la
nueva subclase:
Para solucionar este problema, o bien marcar la clase como final por lo que no se puede ampliar
o declarar la totalidad de su constructor (s) como private .
https://riptutorial.com/es/home 944
Capítulo 142: Objetos seguros
Sintaxis
• SealedObject sealedObject = new SealedObject (obj, cipher);
• SignedObject signedObject = new SignedObject (obj, signKey, signEngine);
Examples
SealedObject (javax.crypto.SealedObject)
Esta clase permite que un programador cree un objeto y proteja su confidencialidad con un
algoritmo criptográfico.
Dado cualquier objeto Serializable, se puede crear un SealedObject que encapsula el objeto
original, en formato serializado (es decir, una "copia profunda"), y sella (encripta) su contenido
serializado, utilizando un algoritmo criptográfico como AES, DES, para proteger Su
confidencialidad. El contenido cifrado se puede descifrar más tarde (con el algoritmo
correspondiente utilizando la clave de descifrado correcta) y deserializarse, lo que genera el
objeto original.
SignedObject (java.security.SignedObject)
https://riptutorial.com/es/home 945
SignedObject es una clase con el propósito de crear objetos de tiempo de ejecución auténticos
cuya integridad no puede ser comprometida sin ser detectada.
Más específicamente, un SignedObject contiene otro objeto Serializable, el objeto firmado (a ser)
y su firma.
//Create a key
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyGen.initialize(1024, random);
// create a private key
PrivateKey signingKey = keyGen.generateKeyPair().getPrivate();
// create a Signature
Signature signingEngine = Signature.getInstance("DSA");
signingEngine.initSign(signingKey);
// create a simple object
Serializable obj = new String("John");
// sign our object
SignedObject signedObject = new SignedObject(obj, signingKey, signingEngine);
System.out.println("signedObject-" + signedObject);
System.out.println("signedObject Data-" + signedObject.getObject());
https://riptutorial.com/es/home 946
Capítulo 143: Opcional
Introducción
Optionales un objeto contenedor que puede o no contener un valor no nulo. Si hay un valor
presente, isPresent() devolverá true y get() devolverá el valor.
Se proporcionan métodos adicionales que dependen de la presencia del valor contenido, como
orElse() , que devuelve un valor predeterminado si el valor no está presente, y ifPresent() que
ejecuta un bloque de código si el valor está presente.
Sintaxis
• Optional.empty () // Crea una instancia opcional vacía.
• Optional.of (value) // Devuelve un Optional con el valor no nulo especificado. Se emitirá una
NullPointerException si el valor pasado es nulo.
• Optional.ofNullable (valor) // Devuelve un opcional con el valor especificado que puede ser
nulo.
Examples
Devolver valor predeterminado si Opcional está vacío
return Optional.ofNullable(value).orElse("defaultValue");
// returns "something"
return Optional.ofNullable(value).orElse("defaultValue");
// returns "defaultValue"
La diferencia crucial entre orElse y orElseGet es que este último solo se evalúa cuando el opcional
está vacío, mientras que el argumento suministrado al anterior se evalúa incluso si el opcional no
está vacío. Por lo tanto, el orElse solo debe usarse para constantes y nunca para suministrar valor
en base a ningún tipo de cálculo.
https://riptutorial.com/es/home 947
Mapa
Use el método map() de Optional para trabajar con valores que podrían ser null sin hacer
verificaciones null explícitas:
(Tenga en cuenta que las operaciones map() y filter() se evalúan inmediatamente, a diferencia
de sus contrapartes de Stream que solo se evalúan en una operación de terminal ).
Sintaxis:
Ejemplos de código:
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "NONE"
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "SOMETHING"
Dado que Optional.map () devuelve un opcional vacío cuando su función de asignación devuelve
un valor nulo, puede encadenar varias operaciones map () como una forma de desreferenciación
segura de nulos. Esto también se conoce como encadenamiento Null-safe .
Aquí hay una forma alternativa de obtener el valor de toString() usando Optional :
Esto devolverá una cadena vacía si alguna de las funciones de mapeo devuelve un valor nulo.
A continuación se muestra otro ejemplo, pero ligeramente diferente. Imprimirá el valor solo si
ninguna de las funciones de asignación devolvió un valor nulo.
Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
https://riptutorial.com/es/home 948
.map(Baz::toString)
.ifPresent(System.out::println);
Use el método orElseThrow() de Optional para obtener el valor contenido o lanzar una excepción,
si no se ha establecido. Esto es similar a llamar a get() , excepto que permite tipos de excepción
arbitrarios. El método toma un proveedor que debe devolver la excepción para ser lanzado.
return optional.orElseThrow(IllegalArgumentException::new);
// returns "something" string
return optional.orElseThrow(IllegalArgumentException::new);
// throws IllegalArgumentException
También puede usar la sintaxis lambda si se necesita lanzar una excepción con el mensaje:
Filtrar
filter() se usa para indicar que le gustaría el valor solo si coincide con su predicado.
Ejemplos de código:
https://riptutorial.com/es/home 949
Usando contenedores opcionales para tipos de números primitivos
Debido a que los tipos numéricos tienen un valor, no hay un manejo especial para el valor nulo.
Los contenedores vacíos se pueden revisar con:
presentInt.isPresent(); // Is true.
absentInt.isPresent(); // Is false.
Del mismo modo, existen métodos abreviados para ayudar a la gestión del valor:
El método normal orElse toma un Object , por lo que podría preguntarse por qué hay una opción
para proporcionar un Supplier aquí (el método orElseGet ).
Considerar:
https://riptutorial.com/es/home 950
String value = "something";
return Optional.ofNullable(value)
.orElseGet(() -> getValueThatIsHardToCalculate()); // returns "something"
Mapa plano
En otras palabras, cuando encadena una llamada de método que devuelve un Optional , el uso de
Optional.flatMap evita la creación de Optionals anidados.
Optional<Optional<Bar>> nestedOptionalBar =
Optional.of(new Foo())
.map(Foo::getBar);
Optional<Bar> optionalBar =
Optional.of(new Foo())
.flatMap(Foo::getBar);
https://riptutorial.com/es/home 951
Capítulo 144: Operaciones de punto flotante
de Java
Introducción
Los números de punto flotante son números que tienen partes fraccionarias (generalmente
expresadas con un punto decimal). En Java, hay dos tipos primitivos para números de punto
flotante que son float (usa 4 bytes) y double (usa 8 bytes). Esta página de documentación es para
detallar con operaciones de ejemplos que se pueden hacer en puntos flotantes en Java.
Examples
Comparando valores de punto flotante
Debe tener cuidado al comparar valores de punto float ( float o double ) utilizando operadores
relacionales: == != , < Y así sucesivamente. Estos operadores dan resultados de acuerdo con las
representaciones binarias de los valores de punto flotante. Por ejemplo:
Este problema de representaciones inexactas es más grave cuando intentamos mezclar el double
y el float en los cálculos. Por ejemplo:
System.out.println(floatVal); // 0.1
System.out.println(doubleVal); // 0.1
System.out.println(doubleValCopy); // 0.10000000149011612
Las representaciones de punto flotante utilizadas en Java para los tipos float y double tienen un
https://riptutorial.com/es/home 952
número limitado de dígitos de precisión. Para el tipo float , la precisión es de 23 dígitos binarios o
aproximadamente 8 dígitos decimales. Para el tipo double , es de 52 bits o alrededor de 15 dígitos
decimales. Además de eso, algunas operaciones aritméticas introducirán errores de redondeo.
Por lo tanto, cuando un programa compara valores de punto flotante, es una práctica estándar
definir un delta aceptable para la comparación. Si la diferencia entre los dos números es menor
que el delta, se considera que son iguales. Por ejemplo
System.out.println();
}
}
}
Resultado:
delta: 0.01
1.0 == 1.0001 ? true
1.0001 == 1.0000001 ? true
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true
delta: 1.0E-5
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true
https://riptutorial.com/es/home 953
delta: 1.0E-7
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? true
1.000000001 == 1.0000000000001 ? true
delta: 1.0E-10
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? false
1.000000001 == 1.0000000000001 ? false
delta: 0.0
1.0 == 1.0001 ? false
1.0001 == 1.0000001 ? false
1.0000001 == 1.000000001 ? false
1.000000001 == 1.0000000000001 ? false
También para la comparación de tipos primitivos double y float se puede usar el método de
compare estática del tipo de boxeo correspondiente. Por ejemplo:
double a = 1.0;
double b = 1.0001;
System.out.println(Double.compare(a, b));//-1
System.out.println(Double.compare(b, a));//1
Finalmente, determinar qué deltas son más apropiadas para una comparación puede ser
complicado. Un enfoque comúnmente utilizado es seleccionar valores delta que, según nuestra
intuición, son correctos. Sin embargo, si conoce la escala y la precisión (verdadera) de los valores
de entrada y los cálculos realizados, puede ser posible establecer límites matemáticamente
sólidos sobre la precisión de los resultados y, por lo tanto, para los deltas. (Hay una rama formal
de Matemáticas conocida como Análisis Numérico que solía enseñarse a científicos
computacionales que cubrían este tipo de análisis).
OverFlow y UnderFlow
El tipo de datos flotante es un punto flotante IEEE 754 de 32 bits de precisión simple.
Desbordamiento de Float
El valor máximo posible es 3.4028235e+38 , cuando supera este valor produce Infinity
float f = 3.4e38f;
float result = f*2;
System.out.println(result); //Infinity
El valor mínimo es 1.4e-45f, cuando está por debajo de este valor, produce 0.0
https://riptutorial.com/es/home 954
float f = 1e-45f;
float result = f/1000;
System.out.println(result);
El tipo de datos doble es un punto flotante IEEE 754 de doble precisión de 64-bit .
Double OverFlow
El valor máximo posible es 1.7976931348623157e+308 , cuando supera este valor produce Infinity
double d = 1e308;
double result=d*2;
System.out.println(result); //Infinity
El valor mínimo es 4.9e-324, cuando está por debajo de este valor, produce 0.0
double d = 4.8e-323;
double result = d/1000;
System.out.println(result); //0.0
Los números de punto flotante se pueden formatear como un número decimal utilizando
String.format con el String.format 'f'
Los números de punto flotante se pueden formatear como un número decimal usando
DecimalFormat
https://riptutorial.com/es/home 955
String format = new DecimalFormat("0.##").format(1.2323000);
System.out.println(format); //1.23
strictfp desactiva este comportamiento. Se aplica a una clase, interfaz o método, y se aplica a
todo lo que contiene, como clases, interfaces, métodos, constructores, inicializadores de
variables, etc. Con strictfp , los valores intermedios de una expresión de punto flotante deben
estar dentro de el conjunto de valores flotantes o el conjunto de valores dobles. Esto hace que los
resultados de tales expresiones sean exactamente aquellos que predice la especificación IEEE
754.
Todas las expresiones constantes son implícitamente estrictas, incluso si no están dentro de un
alcance strictfp .
Por lo tanto, strictfp tiene el efecto neto de que algunas veces los cálculos de casos de esquina
sean menos precisos, y también puede hacer que las operaciones de punto flotante sean más
lentas (ya que la CPU está haciendo más trabajo para garantizar que cualquier precisión adicional
nativa no afecte el resultado). Sin embargo, también hace que los resultados sean exactamente
iguales en todas las plataformas. Por lo tanto, es útil en cosas como programas científicos, donde
la reproducibilidad es más importante que la velocidad.
public static final strictfp class Ops { // strictfp affects all enclosed entities
private StrictOps() {}
https://riptutorial.com/es/home 956
Lea Operaciones de punto flotante de Java en línea:
https://riptutorial.com/es/java/topic/6167/operaciones-de-punto-flotante-de-java
https://riptutorial.com/es/home 957
Capítulo 145: Paquetes
Introducción
El paquete en java se usa para agrupar clases e interfaces. Esto ayuda al desarrollador a evitar
conflictos cuando hay un gran número de clases. Si usamos las clases de este paquete, podemos
crear una clase / interfaz con el mismo nombre en diferentes paquetes. Mediante el uso de
paquetes podemos importar la pieza de nuevo en otra clase. Hay muchos paquetes incorporados
en java como> 1.java.util> 2.java.lang> 3.java.io Podemos definir nuestros propios paquetes
definidos por el usuario .
Observaciones
Los paquetes proporcionan protección de acceso.
La declaración del paquete debe ser la primera línea del código fuente. Solo puede
haber un paquete en un archivo fuente.
Examples
Usando paquetes para crear clases con el mismo nombre
Primera prueba.clase:
package foo.bar
package foo.bar.baz
Lo anterior está bien porque las dos clases existen en paquetes diferentes.
https://riptutorial.com/es/home 958
variables de otras clases dentro del mismo paquete como si esas variables estuvieran disponibles
públicamente.
package foo.bar
public ExampleClass() {
exampleNumber = 3;
exampleString = "Test String";
}
//No getters or setters
}
package foo.bar
package baz.foo
https://riptutorial.com/es/home 959
Capítulo 146: Polimorfismo
Introducción
El polimorfismo es uno de los principales conceptos de programación orientada a objetos (POO).
La palabra polimorfismo se derivó de las palabras griegas "poli" y "morfos". Poli significa
"muchos" y morfos significa "formas" (muchas formas).
Observaciones
Interfaces son otra forma de lograr el polimorfismo en Java, aparte de la herencia basada en
clases. Las interfaces definen una lista de métodos que forman la API del programa. Las clases
deben implement una interface anulando todos sus métodos.
Examples
Método de sobrecarga
Si estos tres son iguales para cualquiera de los dos métodos en una clase, el compilador arroja
un error de método duplicado .
class Polymorph {
https://riptutorial.com/es/home 960
}
System.out.println(poly.add(a, b));
System.out.println(poly.add(a, b, c));
System.out.println(poly.add(d, e));
}
2
6
4.000000
Los métodos sobrecargados pueden ser estáticos o no estáticos. Esto tampoco afecta la
sobrecarga de métodos.
https://riptutorial.com/es/home 961
void methodOverloaded(){
//No argument and No return type
}
int methodOverloaded(){
//No argument and int return type
return 0;
}
Método Anulando
En Java, esto se traduce en subclases que anulan los métodos definidos en la súper clase. En
Java, todas las variables no primitivas son en realidad references , que son similares a los
punteros a la ubicación del objeto real en la memoria. Las references solo tienen un tipo, que es el
tipo con el que se declararon. Sin embargo, pueden apuntar a un objeto de su tipo declarado o
cualquiera de sus subtipos.
class SuperType {
public void sayHello(){
System.out.println("Hello from SuperType");
}
class Test {
public static void main(String... args){
SuperType superType = new SuperType();
superType.sayHello(); // -> Hello from SuperType
https://riptutorial.com/es/home 962
Para anular un método en la subclase, el método de anulación (es decir, el que está en la
subclase) DEBE TENER :
• mismo nombre
• mismo tipo de retorno en el caso de primitivas (se permite una subclase para las clases,
esto también se conoce como tipos de retorno covariantes).
• mismo tipo y orden de parametros
• puede lanzar solo aquellas excepciones que están declaradas en la cláusula de
lanzamientos del método de la superclase o excepciones que son subclases de las
excepciones declaradas. También puede optar por NO lanzar ninguna excepción. Los
nombres de los tipos de parámetros no importan. Por ejemplo, void methodX (int i) es igual
que void methodX (int k)
• No podemos anular los métodos finales o estáticos. Lo único que podemos hacer es
cambiar solo el cuerpo del método.
import java.util.ArrayList;
import java.util.List;
new MakeThingsFly().letTheMachinesFly(machines);
}
}
class MakeThingsFly {
public void letTheMachinesFly(List<FlyingMachine> flyingMachines) {
for (FlyingMachine flyingMachine : flyingMachines) {
flyingMachine.fly();
}
}
}
class FlyingMachine {
public void fly() {
out.println("No implementation");
}
}
https://riptutorial.com/es/home 963
out.println("Fire missile");
}
}
Explicación
b) El método letTheMachinesFly también funciona sin ningún cambio (!) cuando agrega una nueva
clase, por ejemplo, PropellerPlane :
Ese es el poder del polimorfismo. Puedes implementar el principio abierto-cerrado con él.
Funciones virtuales
Los métodos virtuales son métodos en Java que son no estáticos y sin la palabra clave Final en
primer plano. Todos los métodos por defecto son virtuales en Java. Los métodos virtuales
desempeñan funciones importantes en el polimorfismo porque las clases secundarias en Java
pueden anular los métodos de sus clases primarias si la función que se reemplaza no es estática
y tiene la misma firma de método.
Hay, sin embargo, algunos métodos que no son virtuales. Por ejemplo, si el método se declara
privado o con la palabra clave final, entonces el método no es Virtual.
Considere el siguiente ejemplo modificado de herencia con métodos virtuales de esta publicación
de StackOverflow ¿Cómo funcionan las funciones virtuales en C # y Java? :
public class A{
public void hello(){
System.out.println("Hello");
}
}
}
https://riptutorial.com/es/home 964
System.out.println("No");
}
}
}
Si invocamos la clase B y llamamos hola () y boo (), obtendríamos "No" y "Diga jaja" como la
salida resultante porque B anula los mismos métodos de A. Aunque el ejemplo anterior es casi
exactamente el mismo que Al reemplazar los métodos, es importante entender que los métodos
en la clase A son todos, por defecto, virtuales.
Además, podemos implementar métodos virtuales utilizando la palabra clave abstracta. Los
métodos declarados con la palabra clave "resumen" no tienen una definición de método, lo que
significa que el cuerpo del método aún no está implementado. Considere el ejemplo de arriba
nuevamente, excepto que el método boo () se declara abstracto:
public class A{
public void hello(){
System.out.println("Hello");
}
}
}
Si invocamos boo () desde B, la salida seguirá siendo "Say haha", ya que B hereda el método
abstracto boo () y hace que boo () muestre "Say haha".
Echa un vistazo a esta gran respuesta que proporciona información mucho más completa sobre
las funciones virtuales:
De java tutorial
https://riptutorial.com/es/home 965
La definición del diccionario de polimorfismo se refiere a un principio en biología en el
que un organismo o especie puede tener muchas formas o etapas diferentes. Este
principio también puede aplicarse a la programación orientada a objetos y lenguajes
como el lenguaje Java. Las subclases de una clase pueden definir sus propios
comportamientos únicos y, sin embargo, compartir algunas de las mismas
funciones de la clase principal.
Eche un vistazo a este ejemplo para comprender los diferentes tipos de anulación.
fragmento de código:
import java.util.HashMap;
public Game(){
player1 = new Player("Player 1");
player2 = new Player("Player 2");
currentPlayer = player1;
initializeGame();
}
/* Type 1: Let subclass define own implementation. Base class defines abstract method to
force
sub-classes to define implementation
*/
/* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable
*/
protected void logTimeBetweenMoves(Player player){
System.out.println("Base class: Move Duration: player.PlayerActTime -
player.MoveShownTime");
}
/* Type 3: Base class provides implementation. Sub-class can enhance base class
implementation by calling
super.methodName() in first line of the child class method and specific implementation
later */
protected void logGameStatistics(){
System.out.println("Base class: logGameStatistics:");
https://riptutorial.com/es/home 966
}
/* Type 4: Template method: Structure of base class can't be changed but sub-class can
some part of behaviour */
protected void runGame() throws Exception{
System.out.println("Base class: Defining the flow for Game:");
while (runGame) {
/*
1. Set current player
2. Get Player Move
*/
validatePlayerMove(currentPlayer);
logTimeBetweenMoves(currentPlayer);
Thread.sleep(500);
setNextPlayer();
}
logGameStatistics();
}
/* sub-part of the template method, which define child class behaviour */
protected abstract void validatePlayerMove(Player p);
class Player{
String name;
Player(String name){
this.name = name;
}
public String getName(){
return name;
}
}
https://riptutorial.com/es/home 967
System.out.println("Child class: Validate Chess move:" + p.getName());
}
protected void logGameStatistics(){
super.logGameStatistics();
System.out.println("Child class: Add Chess specific logGameStatistics:");
}
}
class TicTacToe extends Game{
public TicTacToe(){
super();
}
public void initializeGame(){
System.out.println("Child class: Initialized TicTacToe game");
}
protected void validatePlayerMove(Player p){
System.out.println("Child class: Validate TicTacToe move:" + p.getName());
}
}
}catch(Exception err){
err.printStackTrace();
}
}
}
salida:
https://riptutorial.com/es/home 968
Lea Polimorfismo en línea: https://riptutorial.com/es/java/topic/980/polimorfismo
https://riptutorial.com/es/home 969
Capítulo 147: Preferencias
Examples
Añadiendo oyentes de eventos
Hay dos tipos de eventos emitidos por un Preferences del objeto: PreferenceChangeEvent y
NodeChangeEvent .
PreferenceChangeEvent
Un objeto PreferenceChangeEvent es emitido por un objeto Properties cada vez que cambia uno de
los pares clave-valor del nodo. PreferenceChangeEvent s se puede escuchar con un
PreferenceChangeListener :
Java SE 8
preferences.addPreferenceChangeListener(evt -> {
String newValue = evt.getNewValue();
String changedPreferenceKey = evt.getKey();
Preferences changedNode = evt.getNode();
});
Java SE 8
preferences.addPreferenceChangeListener(new PreferenceChangeListener() {
@Override
public void preferenceChange(PreferenceChangeEvent evt) {
String newValue = evt.getNewValue();
String changedPreferenceKey = evt.getKey();
Preferences changedNode = evt.getNode();
}
});
NodeChangeEvent
Este evento se activará cada vez que se agregue o elimine un nodo secundario de un nodo
Properties .
preferences.addNodeChangeListener(new NodeChangeListener() {
@Override
public void childAdded(NodeChangeEvent evt) {
Preferences addedChild = evt.getChild();
Preferences parentOfAddedChild = evt.getParent();
}
@Override
public void childRemoved(NodeChangeEvent evt) {
https://riptutorial.com/es/home 970
Preferences removedChild = evt.getChild();
Preferences parentOfRemovedChild = evt.getParent();
}
});
/userRoot
├── com
│ └── mycompany
│ └── myapp
│ ├── darkApplicationMode=true
│ ├── showExitConfirmation=false
│ └── windowMaximized=true
└── org
└── myorganization
└── anotherapp
├── defaultFont=Helvetica
├── defaultSavePath=/home/matt/Documents
└── exporting
├── defaultFormat=pdf
└── openInBrowserAfterExport=false
package com.mycompany.myapp;
// ...
El uso de una ruta relativa (una ruta que no comienza con una / ) hará que la ruta se
resuelva en relación con el nodo principal en el que se resuelve. Por ejemplo, el siguiente
ejemplo devolverá el nodo de la ruta /one/two/three/com/mycompany/myapp :
El uso de una ruta absoluta en el nodo raíz no será diferente de usar una ruta relativa. La
diferencia es que, si se llama en un subnodo, la ruta se resolverá en relación con el nodo
https://riptutorial.com/es/home 971
raíz.
Todas las instancias de Preferences siempre son seguras para subprocesos en los subprocesos de
una única Máquina Virtual de Java (JVM). Debido a que las Preferences se pueden compartir en
múltiples JVM, existen métodos especiales que se ocupan de sincronizar los cambios en las
máquinas virtuales.
Si tiene una aplicación que se supone que se ejecuta solo en una instancia , no se requiere
sincronización externa .
Si tiene una aplicación que se ejecuta en varias instancias en un solo sistema y, por lo tanto,
el acceso a las Preferences debe coordinarse entre las JVM del sistema, entonces se puede usar
el método sync() de cualquier nodo de Preferences para garantizar que se realicen cambios en el
nodo de Preferences visible para otras JVM en el sistema:
Preferencias de exportación
Preferences nodos de Preferences se pueden exportar a un documento XML que representa ese nodo.
El árbol XML resultante se puede importar de nuevo. El documento XML resultante recordará si se
exportó desde el usuario o las Preferences sistema.
Java SE 7
Java SE 7
OutputStream os = null;
try {
os = ...;
preferences.exportSubtree(os);
} catch (IOException ioe) {
https://riptutorial.com/es/home 972
// Exception whilst writing data to the OutputStream
ioe.printStackTrace();
} catch (BackingStoreException bse) {
// Exception whilst reading from the backing preferences store
bse.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException ignored) {}
}
}
Java SE 7
Java SE 7
OutputStream os = null;
try {
os = ...;
preferences.exportSubtree(os);
} catch (IOException ioe) {
// Exception whilst writing data to the OutputStream
ioe.printStackTrace();
} catch (BackingStoreException bse) {
// Exception whilst reading from the backing preferences store
bse.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException ignored) {}
}
}
Importando preferencias
Preferences nodos de Preferences se pueden importar desde un documento XML. La importación debe
utilizarse junto con la funcionalidad de exportación de Preferences , ya que crea los documentos
XML correspondientes correctos.
Los documentos XML recordarán si se exportaron desde el usuario o las Preferences sistema. Por
lo tanto, se pueden importar de nuevo en sus respectivos árboles de Preferences , sin que tenga
que averiguar o saber de dónde vienen. La función estática descubrirá automáticamente si el
documento XML se exportó desde el usuario o las Preferences sistema y los importará
automáticamente en el árbol desde el que se exportaron.
Java SE 7
https://riptutorial.com/es/home 973
try (InputStream is = ...) {
// This is a static call on the Preferences class
Preferences.importPreferences(is);
} catch (IOException ioe) {
// Exception whilst reading data from the InputStream
ioe.printStackTrace();
} catch (InvalidPreferencesFormatException ipfe) {
// Exception whilst parsing the XML document tree
ipfe.printStackTrace();
}
Java SE 7
InputStream is = null;
try {
is = ...;
// This is a static call on the Preferences class
Preferences.importPreferences(is);
} catch (IOException ioe) {
// Exception whilst reading data from the InputStream
ioe.printStackTrace();
} catch (InvalidPreferencesFormatException ipfe) {
// Exception whilst parsing the XML document tree
ipfe.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ignored) {}
}
}
Los escuchas de eventos pueden eliminarse nuevamente de cualquier nodo de Properties , pero la
instancia del oyente debe mantenerse alrededor para eso.
Java SE 8
//
// later...
//
preferences.removePreferenceChangeListener(listener);
Java SE 8
https://riptutorial.com/es/home 974
}
};
preferences.addPreferenceChangeListener(listener);
//
// later...
//
preferences.removePreferenceChangeListener(listener);
Un valor de un nodo de Preferences puede ser del tipo String , boolean , byte[] , double , float
, int o long . Todas las invocaciones deben proporcionar un valor predeterminado, en caso de que
el valor especificado no esté presente en el nodo Preferences .
Para almacenar un valor en el nodo Preferences , se putXXX() uno de los métodos putXXX() . Un
valor de un nodo de Preferences puede ser del tipo String , boolean , byte[] , double , float ,
int o long .
Usando preferencias
Preferences se pueden usar para almacenar la configuración del usuario que refleja la
configuración personal de la aplicación del usuario, por ejemplo, la fuente de su editor, si
prefieren que la aplicación se inicie en modo de pantalla completa, si marcó la casilla de
verificación "No volver a mostrar esto" y demás. como eso.
if (!doShowDialog) {
https://riptutorial.com/es/home 975
return true;
}
//
// Show a dialog here...
//
boolean exitWasConfirmed = ...; // whether the user clicked OK or Cancel
boolean doNotShowAgain = ...; // get value from "Do not show again" checkbox
return exitWasConfirmed;
}
https://riptutorial.com/es/home 976
Capítulo 148: Procesamiento de argumentos de línea de comando
Sintaxis
Parámetros
Parámetro Detalles
Observaciones
Cuando se lanza una aplicación Java normal usando el comando java (o equivalente), se llamará a
un método main , pasando los argumentos desde la línea de comando en la matriz args .
Este tema intentará cubrir algunas de las bibliotecas de terceros más populares. Para obtener
una lista extensa de las alternativas, consulte esta respuesta a la pregunta de StackOverflow
"¿Cómo analizar los argumentos de la línea de comandos en Java?" .
Examples
Si desea analizar argumentos de línea de comando más complejos, por ejemplo, con parámetros
opcionales, lo mejor es utilizar el enfoque GWT de Google. Todas las clases son públicas
disponibles en:
https://gwt.googlesource.com/gwt/+/2.8.0-
beta1/dev/core/src/com/google/gwt/util/tools/ToolBase.java
Un ejemplo para manejar la línea de comandos myprogram -dir "~/Documents" -port 8888 es:
public MyProgramHandler() {
this.registerHandler(new ArgHandlerDir() {
@Override
public void setDir(File dir) {
this.dir = dir;
}
});
this.registerHandler(new ArgHandlerInt() {
@Override
https://riptutorial.com/es/home 977
public String[] getTagArgs() {
return new String[]{"port"};
}
@Override
public void setInt(int value) {
this.port = value;
}
});
}
public static void main(String[] args) {
MyProgramHandler myShell = new MyProgramHandler();
if (myShell.processArgs(args)) {
// main program operation
System.out.println(String.format("port: %d; dir: %s",
myShell.getPort(), myShell.getDir()));
}
System.exit(1);
}
}
ArgHandler también tiene un método isRequired() que se puede sobrescribir para decir que se
requiere el argumento de la línea de comandos (el retorno predeterminado es false por lo que el
argumento es opcional.
Cuando la sintaxis de la línea de comandos para una aplicación es simple, es razonable realizar
el procesamiento de los argumentos del comando completamente en código personalizado.
En este ejemplo, presentaremos una serie de estudios de casos simples. En cada caso, el código
generará mensajes de error si los argumentos son inaceptables, y luego llame a System.exit(1)
para decirle al shell que el comando ha fallado. (Supondremos en cada caso que el código Java se
invoca mediante un contenedor cuyo nombre es "myapp").
En este estudio de caso, el comando no requiere argumentos. El código ilustra que args.length
nos da el número de argumentos de línea de comando.
https://riptutorial.com/es/home 978
// Run the application
System.out.println("It worked: " + args[0] + ", " + args[1]);
}
}
package tommy;
public class Main {
public static void main(String[] args) {
boolean feelMe = false;
boolean seeMe = false;
int index;
loop: for (index = 0; index < args.length; index++) {
String opt = args[index];
switch (opt) {
case "-c":
seeMe = true;
break;
case "-f":
feelMe = true;
break;
default:
if (!opts.isEmpty() && opts.charAt(0) == '-') {
error("Unknown option: '" + opt + "');
}
break loop;
}
}
if (index >= args.length) {
error("Missing argument(s)");
}
Como puede ver, el procesamiento de los argumentos y las opciones se vuelve un tanto engorroso
si la sintaxis del comando es complicada. Es recomendable utilizar una biblioteca de "análisis
de línea de comando"; ver los otros ejemplos
https://riptutorial.com/es/home 979
Capítulo 149: Proceso
Observaciones
Tenga en cuenta que la API recomienda que, a partir de la versión 1.5, la forma preferida de
crear un proceso es utilizar ProcessBuilder.start() .
Otra observación importante es que el valor de salida producido por waitFor depende del programa
/ script que se ejecuta. Por ejemplo, los códigos de salida producidos por calc.exe son
diferentes de notepad.exe .
Examples
Este ejemplo llamará a la calculadora de windows. Es importante notar que el código de salida
variará de acuerdo con el programa / script que se está llamando.
package process.example;
import java.io.IOException;
System.out.println(exitCode);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Si tiene un programa llamado Add.exe que toma dos argumentos y los agrega, el código se vería
así:
//Set the working directory of the ProcessBuilder so it can find the .exe
https://riptutorial.com/es/home 980
//Alternatively you can just pass in the absolute file path of the .exe
File myWorkingDirectory = new File(yourFilePathNameGoesHere);
pb.workingDirectory(myWorkingDirectory);
try {
Process p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
Sin embargo, es posible que desee esperar a que finalice el programa llamado antes de continuar
con su propia ejecución (por ejemplo, el programa llamado escribirá los datos en un archivo y su
programa necesita ese acceso para acceder a esos datos).
Esto se puede hacer fácilmente llamando al método waitFor() desde la instancia de Process
devuelta.
Ejemplo de uso:
try {
Process p = pb.start();
p.waitFor();
} catch (IOException e) {
e.printStackTrack();
} catch (InterruptedException e) {
e.printStackTrace();
}
ch.vorburger.exec
Lanzar procesos externos desde Java utilizando la API java.lang.ProcessBuilder sin formato
directamente puede ser un poco engorroso. La biblioteca de Apache Commons Exec lo hace un poco
más fácil. La biblioteca ch.vorburger.exec se extiende más allá de Commons Exec para que sea
realmente conveniente:
https://riptutorial.com/es/home 981
.setConsoleBufferMaxLines(7000)
.build();
proc.start();
int status = proc.waitForExit();
int status = proc.waitForExitMaxMsOrDestroy(3000);
String output = proc.getConsole();
proc.startAndWaitForConsoleMessageMaxMs("started!", 7000);
// use service offered by external process...
proc.destroy();
En primer lugar, aquí hay un ejemplo de uso exec(String) se usa de manera segura:
Esto funcionará normalmente, pero fallará si dirPath es (por ejemplo) "/ home / user / My
Documents". El problema es que exec(String) divide la cadena en un comando y argumentos
simplemente buscando espacios en blanco. La cadena de comando:
se dividirá en:
y esto hará que el comando "mkdir" falle porque espera un argumento, no dos.
Ante esto, algunos programadores intentan agregar citas alrededor de la ruta de acceso. Esto
tampoco funciona:
se dividirá en:
Los caracteres de comillas dobles adicionales que se agregaron para intentar "citar" los
https://riptutorial.com/es/home 982
espacios se tratan como cualquier otro carácter que no sea un espacio en blanco. De hecho,
cualquier cosa que hagamos o escapemos de los espacios va a fallar.
Esto funcionará si dirpath incluye caracteres de espacio en blanco porque esta sobrecarga de
exec no intenta dividir los argumentos. Las cadenas se pasan a la llamada del sistema exec
sistema operativo tal como está.
(El primer ejemplo enumera los nombres de todos los archivos Java en el sistema de archivos, y
el segundo imprime las declaraciones del package 2 en los archivos Java en el árbol "fuente").
Estos no van a funcionar como se esperaba. En el primer caso, el comando "buscar" se ejecutará
con "2> / dev / null" como un argumento de comando. No se interpretará como una redirección. En
el segundo ejemplo, el carácter de canalización ("|") y las obras siguientes se asignarán al
comando "buscar".
El problema aquí es que los métodos exec y ProcessBuilder no comprenden ninguna sintaxis de
shell. Esto incluye redirecciones, conductos, expansión variable, globbing, etc.
En algunos casos (por ejemplo, redirección simple) puede lograr fácilmente el efecto deseado
utilizando ProcessBuilder . Sin embargo, esto no es cierto en general. Un enfoque alternativo es
ejecutar la línea de comandos en un shell; por ejemplo:
Pero tenga en cuenta que en el segundo ejemplo, necesitábamos escapar del carácter comodín ("*")
porque queremos que el comodín sea interpretado por "buscar" en lugar de por el shell.
https://riptutorial.com/es/home 983
Hay un par de razones por las que esto no funciona:
1. En "cd" y "exportar" los comandos son comandos incorporados en el shell. No existen como
ejecutables distintos.
2. Para que los shell construidos puedan hacer lo que se supone que deben hacer (por ejemplo,
cambiar el directorio de trabajo, actualizar el entorno), deben cambiar el lugar donde
reside ese estado. Para una aplicación normal (incluida una aplicación Java), el estado
está asociado con el proceso de la aplicación. Así, por ejemplo, el proceso hijo que
ejecutaría el comando "cd" no pudo cambiar el directorio de trabajo de su proceso "java"
principal. De manera similar, un proceso exec no puede cambiar el directorio de trabajo
para un proceso que lo sigue.
1 - También puede usar ProcessBuilder , pero eso no es relevante hasta el punto de este ejemplo.
2 - Esto es un poco áspero y listo ... pero una vez más, las fallas de este enfoque no son relevantes para el
ejemplo.
https://riptutorial.com/es/home 984
Capítulo 150: Programación Concurrente (Hilos)
Introducción
Observaciones
• Tipos atómicos
• Ejecutor, ExecutorService y grupos de subprocesos
• Extendiendo Thread versus implementando Runnable
Examples
Multihilo básico
Si tiene muchas tareas que ejecutar y todas estas tareas no dependen del resultado de las
anteriores, puede usar Multithreading para su computadora para realizar todas estas tareas al
mismo tiempo con más procesadores si su computadora puede. Esto puede hacer que la ejecución de
su programa sea más rápida si tiene algunas grandes tareas independientes.
CountAndPrint(String name) {
this.name = name;
}
https://riptutorial.com/es/home 985
El código del método de ejecución de las distintas instancias de CountAndPrint se ejecutará en
un orden no predecible. Un fragmento de una ejecución de muestra podría verse así:
Instance 4: 1
Instance 2: 1
Instance 4: 2
Instance 1: 1
Instance 1: 2
Main: 1
Instance 4: 3
Main: 2
Instance 3: 1
Instance 4: 4
...
Productor-consumidor
Un ejemplo simple de solución de problema productor-consumidor. Tenga en cuenta que las clases
JDK ( AtomicBoolean y BlockingQueue ) se utilizan para la sincronización, lo que reduce la
posibilidad de crear una solución no válida. Consulte Javadoc para varios tipos de BlockingQueue
; elegir una implementación diferente puede cambiar drásticamente el comportamiento de este
ejemplo (como DelayQueue o Priority Queue ).
https://riptutorial.com/es/home 986
//put throws an InterruptedException when the thread is interrupted
ProducedData data = queue.poll(10, TimeUnit.MILLISECONDS);
// process data
consumedCount++;
}
} catch (InterruptedException e) {
// the thread has been interrupted: cleanup and exit
consumedCount--;
//re-interrupt the thread in case the interrupt flag is needeed higher up
Thread.currentThread().interrupt();
}
System.out.println("Consumed " + consumedCount + " objects");
}
}
producer.start();
consumer.start();
Thread.sleep(1000);
producer.interrupt();
Thread.sleep(10);
consumer.interrupt();
}
}
Usando ThreadLocal
Una herramienta útil en Java Concurrency es ThreadLocal : esto le permite tener una variable que
será única para un hilo determinado. Por lo tanto, si el mismo código se ejecuta en subprocesos
diferentes, estas ejecuciones no compartirán el valor, sino que cada subproceso tiene su propia
variable que es local al subproceso .
Por ejemplo, esto se usa con frecuencia para establecer el contexto (como la información de
autorización) del manejo de una solicitud en un servlet. Podrías hacer algo como esto:
https://riptutorial.com/es/home 987
// business logic
} finally {
contexts.remove(); // 'ensure' removal of thread-local variable
}
}
Ahora, en lugar de pasar MyUserContext a cada método, puede usar MyServlet.getContext() donde lo
necesite. Ahora, por supuesto, esto introduce una variable que necesita ser documentada, pero es
segura para subprocesos, lo que elimina muchas de las desventajas de usar una variable de alto
alcance.
La ventaja clave aquí es que cada hilo tiene su propia variable local de hilo en ese contenedor
de contexts . Siempre que lo use desde un punto de entrada definido (como exigir que cada
servlet mantenga su contexto, o quizás agregando un filtro de servlet) puede confiar en que este
contexto estará allí cuando lo necesite.
CountDownLatch
CountDownLatch
Una ayuda de sincronización que permite que uno o más subprocesos esperen hasta que
se complete un conjunto de operaciones que se están realizando en otros subprocesos.
Métodos clave:
Provoca que el subproceso actual espere hasta que el pestillo haya descendido hasta
cero, a menos que se interrumpa el subproceso.
Reduce el conteo del pestillo, liberando todos los hilos en espera si el conteo llega
a cero.
Ejemplo:
import java.util.concurrent.*;
https://riptutorial.com/es/home 988
public class CountDownLatchDemo {
public static void main(String[] args) {
try {
int numberOfThreads = 5;
if (args.length < 1) {
System.out.println("Usage: java CountDownLatchDemo numberOfThreads");
return;
}
try {
numberOfThreads = Integer.parseInt(args[0]);
} catch(NumberFormatException ne) {
}
CountDownLatch latch = new CountDownLatch(numberOfThreads);
for (int n = 0; n < numberOfThreads; n++) {
Thread t = new Thread(new DoSomethingInAThread(latch));
t.start();
}
latch.await();
System.out.println("In Main thread after completion of " + numberOfThreads + "
threads");
} catch(Exception err) {
err.printStackTrace();
}
}
}
salida:
java CountDownLatchDemo 5
Do some thing
Do some thing
Do some thing
Do some thing
Do some thing
In Main thread after completion of 5 threads
Explicación:
Sincronización
En Java, hay un mecanismo integrado de bloqueo de nivel de idioma: el bloque synchronized , que
puede usar cualquier objeto Java como un bloqueo intrínseco (es decir, cada objeto Java puede
tener un monitor asociado).
Los bloqueos intrínsecos proporcionan atomicidad a grupos de afirmaciones. Para entender lo que
eso significa para nosotros, echemos un vistazo a un ejemplo donde la synchronized es útil:
https://riptutorial.com/es/home 989
count is for demonstration purposes.
for (int i = 0; i < 100; i++) {
executorService.execute(() -> {
synchronized (mutex) {
t++;
System.out.println(MessageFormat.format("t: {0}", t));
}
});
}
executorService.shutdown();
}
En este caso, si no fuera por el bloque synchronized , habría habido múltiples problemas de
concurrencia involucrados. El primero sería con el operador de incremento posterior (no es
atómico en sí mismo), y el segundo sería que observaríamos el valor de t después de que una
cantidad arbitraria de otros subprocesos haya tenido la oportunidad de modificarlo. Sin embargo,
desde que adquirimos un bloqueo intrínseco, no habrá condiciones de carrera aquí y la salida
contendrá números del 1 al 100 en su orden normal.
Los bloqueos intrínsecos en Java son exclusiones mutuas (es decir, bloqueos de ejecución mutua).
La ejecución mutua significa que si un subproceso ha adquirido el bloqueo, el segundo se verá
obligado a esperar a que el primero lo libere antes de que pueda adquirir el bloqueo por sí
mismo. Nota: Una operación que puede poner el hilo en el estado de espera (reposo) se denomina
operación de bloqueo . Por lo tanto, la adquisición de un bloqueo es una operación de bloqueo.
Los bloqueos intrínsecos en Java son reentrantes . Esto significa que si un hilo intenta
adquirir un bloqueo que ya posee, no lo bloqueará y lo logrará con éxito. Por ejemplo, el
siguiente código no se bloqueará cuando se le llame:
Los siguientes bloques de código son prácticamente equivalentes (aunque el código de bytes
parece ser diferente):
2. método synchronized :
https://riptutorial.com/es/home 990
class MyClass {
...
public static void bar() {
synchronized(MyClass.class) {
doSomeOtherStuff();
}
}
}
class MyClass {
...
public static synchronized void bar() {
doSomeOtherStuff();
}
}
Operaciones atómicas
Una operación atómica es una operación que se ejecuta "todo a la vez", sin ninguna posibilidad
de que otros hilos observen o modifiquen el estado durante la ejecución de la operación atómica.
En este caso, hay dos cuestiones. El primer problema es que el operador de incremento posterior
no es atómico. Se compone de varias operaciones: obtener el valor, agregar 1 al valor,
establecer el valor. Es por eso que si ejecutamos el ejemplo, es probable que no veamos t: 100
en la salida; dos subprocesos pueden obtener el valor al mismo tiempo, incrementarlo y
establecerlo: digamos que el valor de t es 10, y dos subprocesos están aumentando t. Ambos
subprocesos establecerán el valor de t en 11, ya que el segundo subproceso observa el valor de t
antes de que el primer subproceso haya terminado de incrementarlo.
El segundo tema es sobre cómo estamos observando t. Cuando estamos imprimiendo el valor de t, es
posible que el valor ya haya sido cambiado por un hilo diferente después de la operación de
incremento de este hilo.
https://riptutorial.com/es/home 991
for (int i = 0; i < 100; i++) {
executorService.execute(() -> {
int currentT = t.incrementAndGet();
System.out.println(MessageFormat.format("t: {0}", currentT));
});
}
executorService.shutdown();
}
Se produce un punto muerto cuando dos acciones en competencia esperan a que la otra termine, y
por lo tanto ninguna de las dos lo hace. En java hay un bloqueo asociado a cada objeto. Para
evitar la modificación simultánea realizada por varios subprocesos en un solo objeto, podemos
usar palabras clave synchronized , pero todo tiene un costo. El uso incorrecto de una palabra
clave synchronized puede llevar a sistemas atascados llamados sistemas bloqueados.
Considere que hay 2 subprocesos trabajando en 1 instancia, permite llamar a los subprocesos como
primero y segundo, y digamos que tenemos 2 recursos R1 y R2. First adquiere R1 y también
necesita R2 para completarse, mientras que Second adquiere R2 y necesita R1 para completarse.
digamos en el tiempo t = 0,
Primero tiene R1 y Segundo tiene R2. ahora First está esperando a R2 mientras que Second está
esperando a R1. esta espera es indefinida y esto lleva a un punto muerto.
@Override
public void run() {
// TODO Auto-generated method stub
dl.methodA();
}
});
@Override
public void run() {
// TODO Auto-generated method stub
try {
dl.method2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.setName("First");
t2.setName("Second");
https://riptutorial.com/es/home 992
t1.start();
t2.start();
}
}
class DeadLock {
Pausa de ejecucion
Thread.sleep hace que el subproceso actual suspenda la ejecución durante un período específico.
Este es un medio eficaz para hacer que el tiempo del procesador esté disponible para los otros
subprocesos de una aplicación u otras aplicaciones que puedan estar ejecutándose en un sistema
informático. Hay dos métodos de sleep sobrecargados en la clase Thread.
https://riptutorial.com/es/home 993
public static void sleep(long millis) throws InterruptedException
Thread.sleep(1000);
Es importante tener en cuenta que esto es una sugerencia para el programador del kernel del
sistema operativo. Esto puede no ser necesariamente preciso, y algunas implementaciones ni
siquiera consideran el parámetro de nanosegundo (posiblemente redondeando al milisegundo más
cercano).
Se recomienda incluir una llamada a Thread.sleep en try / catch and catch InterruptedException .
Como sabemos, debemos usar palabras clave synchronized para hacer que la ejecución de un método
o bloque sea exclusiva. Pero es posible que pocos de nosotros no estemos conscientes de un
aspecto más importante del uso de palabras clave synchronized y volatile : además de hacer una
unidad de código atómico, también proporciona una barrera de lectura / escritura . ¿Qué es esta
barrera de lectura / escritura? Vamos a discutir esto usando un ejemplo:
class Counter {
Supongamos que un subproceso A llama a incrementCount() primero y luego otro subproceso B llama
a getCount() . En este escenario, no hay garantía de que B vea el valor actualizado del count .
Todavía puede ver el count como 10 , incluso es posible que nunca vea el valor actualizado del
count nunca.
Para comprender este comportamiento, debemos comprender cómo se integra el modelo de memoria
Java con la arquitectura de hardware. En Java, cada hilo tiene su propia pila de hilos. Esta
pila contiene: pila de llamada a método y variable local creada en ese hilo. En un sistema de
varios núcleos, es muy posible que dos subprocesos se ejecuten simultáneamente en núcleos
separados. En tal escenario, es posible que parte de la pila de un hilo se encuentre dentro del
registro / caché de un núcleo. Si dentro de un hilo, se accede a un objeto usando una palabra
clave synchronized (o volatile ), después del bloque synchronized ese hilo sincroniza su copia
local de esa variable con la memoria principal. Esto crea una barrera de lectura / escritura y
se asegura de que el hilo vea el último valor de ese objeto.
Pero en nuestro caso, dado que el subproceso B no ha utilizado el acceso sincronizado para el
count , puede ser un valor referencial del count almacenado en el registro y puede que nunca vea
las actualizaciones del subproceso A. Para asegurarse de que B ve el valor más reciente del
recuento, necesitamos hacer getCount() sincronizado también.
https://riptutorial.com/es/home 994
return count;
}
El mismo efecto de visibilidad se volatile lecturas / escrituras volatile . Todas las variables
actualizadas antes de escribir en volatile se vaciarán en la memoria principal y todas las
lecturas después de la lectura de la variable volatile serán de la memoria principal.
Hay dos enfoques principales para crear un hilo en Java. En esencia, crear un hilo es tan fácil
como escribir el código que se ejecutará en él. Los dos enfoques difieren en donde se define ese
código.
Nota : usaré Thread para referirme a la clase java.lang.Thread y thread para referirse al
concepto lógico de threads.
https://riptutorial.com/es/home 995
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread running!");
}
}
}
Ahora que ya hemos definido el código que se ejecutará, el hilo se puede crear simplemente como:
La clase Thread también contiene un constructor que acepta una cadena, que se utilizará como el
nombre del hilo. Esto puede ser particularmente útil cuando se depura un programa multihilo.
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread running! ");
}
}
}
Esto puede ser muy poderoso cuando se combina con lambdas o referencias de métodos (solo Java
8):
Hablando de manera práctica, puede utilizar ambos enfoques sin preocupaciones. Sin embargo, la
sabiduría general dice usar este último.
Para cada uno de los cuatro constructores mencionados, también hay una alternativa que acepta
una instancia de java.lang.ThreadGroup como primer parámetro.
https://riptutorial.com/es/home 996
Para resumir, el subproceso se puede crear con uno de estos constructores públicos:
Thread()
Thread(String name)
Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
El último nos permite definir el tamaño de pila deseado para el nuevo hilo.
A menudo, la legibilidad del código sufre al crear y configurar muchos subprocesos con las
mismas propiedades o desde el mismo patrón. Ahí es cuando se puede usar
java.util.concurrent.ThreadFactory . Esta interfaz le permite encapsular el procedimiento de
crear el hilo a través del patrón de fábrica y su único método, newThread (Runnable) .
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Worker " + id++);
}
}
https://riptutorial.com/es/home 997
dejar algunas tareas sin manejar. El código que llama a los métodos de bloqueo se verá obligado
a lidiar con la excepción InterruptedException. Si es semánticamente posible, puede simplemente
propagar la InterruptedException y declarar que se debe lanzar. Como tal, se convierte en un
método de bloqueo en sí mismo en relación con sus llamadores. Si no puede propagar la excepción,
al menos debería establecer el indicador interrumpido, para que las personas que llaman más
arriba en la pila también sepan que el hilo fue interrumpido. En algunos casos, el método debe
continuar esperando, independientemente de la InterruptedException, en cuyo caso debe demorar la
configuración del indicador interrumpido hasta que, una vez que se termina de esperar, esto
puede implicar establecer una variable local, que debe verificarse antes de salir del método
para entonces interrumpe su hilo.
Ejemplos:
TaskHandler(BlockingQueue<Task> queue) {
this.queue = queue;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) { // check for interrupt flag, exit
loop when interrupted
try {
Task task = queue.take(); // blocking call, responsive to interruption
handle(task);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // cannot throw InterruptedException (due
to Runnable interface restriction) so indicating interruption by setting the flag
}
}
}
Ejemplo de código que retrasa la configuración de la bandera de interrupción hasta que esté
completamente terminado:
MustFinishHandler(BlockingQueue<Task> queue) {
this.queue = queue;
}
@Override
public void run() {
boolean shouldInterrupt = false;
while (true) {
try {
Task task = queue.take();
if (task.isEndOfTasks()) {
https://riptutorial.com/es/home 998
if (shouldInterrupt) {
Thread.currentThread().interrupt();
}
return;
}
handle(task);
} catch (InterruptedException e) {
shouldInterrupt = true; // must finish, remember to set interrupt flag when
we're done
}
}
}
Ejemplo de código que tiene una lista fija de tareas pero que puede cerrarse antes cuando se
interrumpe
@Override
public void run() {
for (Task task : tasks) {
if (Thread.currentThread().isInterrupted()) {
return;
}
handle(task);
}
}
A continuación el código muestra múltiples programas de Productor / Consumidor. Tanto las hebras
del productor como las del consumidor comparten la misma cola global.
import java.util.concurrent.*;
import java.util.Random;
https://riptutorial.com/es/home 999
pes.shutdown();
ces.shutdown();
}
}
salida:
Produced:69:by thread:2
Produced:553:by thread:1
Consumed: 69:by thread:1
Consumed: 553:by thread:2
Produced:41:by thread:2
https://riptutorial.com/es/home 1000
Produced:796:by thread:1
Consumed: 41:by thread:1
Consumed: 796:by thread:2
Produced:728:by thread:2
Consumed: 728:by thread:1
y así ................
Explicación:
Las implementaciones de BlockingQueue son seguras para subprocesos. Todos los métodos
de colas logran sus efectos de forma atómica utilizando bloqueos internos u otras
formas de control de concurrencia.
A veces se requiere que un proceso escriba y lea simultáneamente los mismos "datos".
1. Puede haber cualquier número de lectores concurrentes de los datos. Si hay al menos un
acceso de lector otorgado, entonces no es posible el acceso de un escritor.
2. Puede haber como máximo un único escritor para los datos. Si hay un acceso de escritor
otorgado, entonces ningún lector puede acceder a los datos.
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Sample {
// Our lock. The constructor allows a "fairness" setting, which guarantees the chronology of
lock attributions.
protected static final ReadWriteLock RW_LOCK = new ReentrantReadWriteLock();
https://riptutorial.com/es/home 1001
try {
return data;
} finally {
RW_LOCK.readLock().unlock();
}
}
NOTA 1 : Este caso de uso preciso tiene una solución más limpia que usa AtomicInteger , pero lo
que se describe aquí es un patrón de acceso, que funciona independientemente del hecho de que
los datos aquí son un número entero que es una variante atómica.
1. No se garantiza que las escrituras de valores primitivos sean atómicas en todas las JVM,
por lo que el lector podría ver, por ejemplo, que solo se escriben 32 bits de 64 bits si
los data fueran de 64 bits.
2. La visibilidad de la escritura desde un subproceso que no la realizó está garantizada por
la JVM solo si establecemos la relación Suceder antes de entre las escrituras y las
lecturas. Esta relación se establece cuando tanto los lectores como los escritores usan sus
respectivos bloqueos, pero no de otra manera
Java SE 8
En caso de que se requiera un mayor rendimiento, y bajo ciertos tipos de uso, hay un tipo de
bloqueo más rápido disponible, llamado StampedLock , que entre otras cosas implementa un modo de
bloqueo optimista. Este bloqueo funciona de manera muy diferente de ReadWriteLock , y esta
muestra no es transponible.
Objeto ejecutable
La interfaz Runnable define un solo método, run() , destinado a contener el código ejecutado en
el hilo.
Ejemplo
@Override
public void run() {
System.out.println("Hello from a thread");
}
Ejemplo en Java8:
https://riptutorial.com/es/home 1002
El empleo de un objeto Runnable es más general, porque el objeto Runnable puede subclasificar
una clase que no sea Thread .
Thread subclasificación de Thread es más fácil de usar en aplicaciones simples, pero está
limitada por el hecho de que su clase de tarea debe ser descendiente de Thread .
Semáforo
Un semáforo es un sincronizador de alto nivel que mantiene un conjunto de permisos que pueden
ser adquiridos y liberados por subprocesos. Un semáforo se puede imaginar como un contador de
permisos que se reducirá cuando un hilo adquiera, y se incrementará cuando un hilo se libere. Si
la cantidad de permisos es 0 cuando un subproceso intenta adquirir, el subproceso se bloqueará
hasta que un permiso esté disponible (o hasta que el subproceso se interrumpa).
Semaphore semaphore = new Semaphore(1); // The int value being the number of permits
El constructor Semaphore acepta un parámetro booleano adicional para ser justos. Cuando se
establece como falso, esta clase no ofrece garantías sobre el orden en que los subprocesos
adquieren permisos. Cuando la imparcialidad se establece como verdadera, el semáforo garantiza
que los subprocesos que invocan cualquiera de los métodos de adquisición se seleccionan para
obtener permisos en el orden en que se procesó su invocación de dichos métodos. Se declara de la
siguiente manera:
Ahora veamos un ejemplo de javadocs, donde Semaphore se usa para controlar el acceso a un
conjunto de elementos. En este ejemplo se usa un semáforo para proporcionar una funcionalidad de
bloqueo a fin de garantizar que siempre haya elementos que se obtendrán cuando se getItem() .
class Pool {
/*
* Note that this DOES NOT bound the amount that may be released!
* This is only a starting value for the Semaphore and has no other
* significant meaning UNLESS you enforce this inside of the
* getNextAvailableItem() and markAsUnused() methods
*/
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
/**
* Obtains the next available item and reduces the permit count by 1.
* If there are no items available, block.
*/
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
/**
* Puts the item into the pool and add 1 permit.
*/
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
https://riptutorial.com/es/home 1003
}
Un Threadpool tiene una cola de tareas, de las cuales cada una se ejecutará en uno de estos
Threads.
El siguiente ejemplo muestra cómo agregar dos matrices int utilizando un Threadpool.
Java SE 8
int[] firstArray = { 2, 4, 6, 8 };
int[] secondArray = { 1, 3, 5, 7 };
int[] result = { 0, 0, 0, 0 };
System.out.println(Arrays.toString(result));
Notas:
Obtenga el estado de todas las hebras iniciadas por su programa, excluyendo las hebras del
sistema
Fragmento de código:
import java.util.Set;
https://riptutorial.com/es/home 1004
public static void main(String args[]) throws Exception {
for (int i = 0; i < 5; i++){
Thread t = new Thread(new MyThread());
t.setName("MyThread:" + i);
t.start();
}
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
}
}
Salida:
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:3,5,main]:state:TIMED_WAITING
Thread :Thread[main,5,main]:state:RUNNABLE
Thread :Thread[MyThread:4,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread count started by Main thread:6
Explicación:
Reference Handler
Signal Dispatcher
Attach Listener
Finalizer
Callable y Futuro
Si bien Runnable proporciona un medio para envolver el código para que se ejecute en un
subproceso diferente, tiene una limitación en cuanto a que no puede devolver un resultado de la
ejecución. La única forma de obtener algún valor de retorno de la ejecución de un Runnable es
asignar el resultado a una variable accesible en un ámbito fuera del Runnable .
https://riptutorial.com/es/home 1005
Callable se introdujo en Java 5 como un par de Runnable . Callable es esencialmente el mismo,
excepto que tiene un método de call lugar de run . El método de call tiene la capacidad
adicional de devolver un resultado y también se le permite lanzar excepciones marcadas.
El resultado de un envío de tarea callable está disponible para ser pulsado a través de un
futuro
Interfaz invocable
Futuro
interface Future<V> {
V get();
V get(long timeout, TimeUnit unit);
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
}
@Override
public String call() throws Exception {
// just sleep for 10 secs to simulate a lengthy computation
Thread.sleep(10000);
System.out.println("Result after a lengthy 10sec calculation");
return "Complex Result"; // the result
}
}
Salida
https://riptutorial.com/es/home 1006
Time At the Point of Printing the Result : Thu Aug 04 15:05:25 EDT 2016
Si bien get() es el método para extraer el resultado real, Future tiene provisión
• get(long timeout, TimeUnit unit) define el período de tiempo máximo durante la get(long
timeout, TimeUnit unit) actual esperará un resultado;
• Para cancelar la tarea, cancele la llamada cancel(mayInterruptIfRunning) . La bandera
mayInterrupt indica que la tarea debe interrumpirse si se inició y se está ejecutando en
este momento;
• Para verificar si la tarea se completó / terminó llamando a isDone() ;
• Para verificar si la tarea prolongada se canceló, se cancela isCancelled() .
Antes de la introducción del paquete concurrente de Java 5, el subproceso era más bajo. La
introducción de este paquete proporcionaba varias ayudas / construcciones de programación
concurrente de nivel superior.
Los bloqueos son mecanismos de sincronización de subprocesos que sirven esencialmente para el
mismo propósito que los bloques sincronizados o palabras clave.
Bloqueo intrínseco
Los bloqueos también tienen una funcionalidad disponible que el bloqueo intrínseco no ofrece,
como el bloqueo pero que responde a la interrupción, o intenta bloquear, y no bloquear cuando no
puede hacerlo.
class Locky {
int count = 0; // shared among multiple threads
https://riptutorial.com/es/home 1007
try {
lockObj.lockInterruptibly();
++count; // a non-atomic operation
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // stopping
}
} finally {
if (!Thread.currentThread().isInterrupted()) {
lockObj.unlock(); // sure to release the lock without fail
}
}
}
}
Hay varias variantes de bloqueo disponibles. Para más detalles, consulte los documentos api aquí
https://riptutorial.com/es/home 1008
Capítulo 151: Programación paralela con el framework Fork / Join.
Examples
El framework fork / join en Java es ideal para un problema que se puede dividir en partes más
pequeñas y resolver en paralelo. Los pasos fundamentales de un problema fork / join son:
Una ForkJoinTask es la interfaz que define este problema. En general, se espera que usted
subclasifique una de sus implementaciones abstractas (generalmente la Tarea Recursiva ) en lugar
de implementar la interfaz directamente.
En este ejemplo, vamos a sumar una colección de enteros, dividiendo hasta obtener un tamaño de
lote de no más de diez.
import java.util.List;
import java.util.concurrent.RecursiveTask;
@Override
public Integer compute() {
if (maxExclusive - minInclusive > MAX_BATCH_SIZE) {
// This is too big for a single batch, so we shall divide into two tasks
int mid = (minInclusive + maxExclusive) / 2;
SummingTask leftTask = new SummingTask(numbers, minInclusive, mid);
SummingTask rightTask = new SummingTask(numbers, mid, maxExclusive);
// Submit the left hand task as a new task to the same ForkJoinPool
leftTask.fork();
// Run the right hand task on the same thread and get the result
int rightResult = rightTask.compute();
// Wait for the left hand task to complete and get its result
int leftResult = leftTask.join();
https://riptutorial.com/es/home 1009
// This is fine for a single batch, so we will run it here and now
int sum = 0;
for (int i = minInclusive; i < maxExclusive; i++) {
sum += numbers.get(i);
}
return sum;
}
}
}
Una instancia de esta tarea ahora se puede pasar a una instancia de ForkJoinPool .
// Submit the task to the pool, and get what is effectively the Future
ForkJoinTask<Integer> task = pool.submit(new SummingTask(numbers));
https://riptutorial.com/es/home 1010
Capítulo 152: Publicación por entregas
Introducción
Después de que un objeto serializado se haya escrito en un archivo, se puede leer del archivo y
deserializar, es decir, la información de tipo y los bytes que representan el objeto y sus datos
se pueden usar para recrear el objeto en la memoria.
Examples
¿Qué es la serialización?
java.io.Serializable es una interfaz de marcador (no tiene cuerpo). Solo se utiliza para
"marcar" clases de Java como serializables.
El tiempo de ejecución de serialización asocia con cada clase serializable un número de versión,
llamado serialVersionUID , que se usa durante la des- serialización para verificar que el
remitente y el receptor de un objeto serializado hayan cargado clases para ese objeto que sean
compatibles con respecto a la serialización. Si el receptor ha cargado una clase para el objeto
que tiene un serialVersionUID diferente al de la clase del remitente correspondiente, la
deserialización dará como resultado una InvalidClassException . Una clase serializable puede
declarar su propio serialVersionUID declarando explícitamente un campo llamado serialVersionUID
que debe ser static, final, y de tipo long :
import java.io.Serializable;
public SerialClass() {
currentTime = Calendar.getInstance().getTime();
}
https://riptutorial.com/es/home 1011
Cómo escribir un objeto en un archivo
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
El objeto almacenado puede leerse desde el sistema de archivos más tarde usando
java.io.ObjectInputStream como se muestra a continuación:
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.java.lang.ClassNotFoundException;
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
time = (SerialClass)in.readObject();
in.close();
} catch(IOException ex){
ex.printStackTrace();
} catch(ClassNotFoundException cnfe){
cnfe.printStackTrace();
}
// print out restored time
System.out.println("Restored time: " + time.getTime());
}
}
Serializar un objeto serializa el gráfico de objeto completo del cual es la raíz, y funciona
correctamente en presencia de gráficos cíclicos. Se proporciona un método reset() para forzar
que ObjectOutputStream olvide de los objetos que ya se han serializado.
https://riptutorial.com/es/home 1012
Campos transitorios - Serialización
//Skills
List<String> skills = new LinkedList<String>();
skills.add("leadership");
skills.add("Java Experience");
//Employe
Employe obj = new Employe();
obj.setFirstName("Christian");
obj.setLastName("Lusardi");
obj.setAge(25);
obj.setSalary(new BigDecimal("10000"));
obj.setSkills(skills);
//Serialization process
Gson gson = new Gson();
String json = gson.toJson(obj);
//{"firstName":"Christian","lastName":"Lusardi","age":25,"salary":10000,"skills":["leadership","Java
Experience"]}
Tenga en cuenta que no puede serializar objetos con referencias circulares, ya que esto
resultará en una recursión infinita.
(Deserialización)
La siguiente es una implementación que demuestra cómo un objeto puede ser serializado en su
cadena JSON correspondiente.
class Test {
https://riptutorial.com/es/home 1013
return idx;
}
String jsonString;
try {
jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(test);
System.out.println(jsonString);
} catch (JsonProcessingException ex) {
// Handle Exception
}
Salida:
{
"idx" : 1,
"name" : "abc"
}
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
Serialización personalizada
En este ejemplo, queremos crear una clase que genere y genere en la consola, un número aleatorio
entre un rango de dos enteros que se pasan como argumentos durante la inicialización.
https://riptutorial.com/es/home 1014
public SimpleRangeRandom(int min, int max){
this.min = min;
this.max = max;
thread = new Thread(this);
thread.start();
}
@Override
private void WriteObject(ObjectOutputStreamout) throws IO Exception;
private void ReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
public void run() {
while(true) {
Random rand = new Random();
System.out.println("Thread: " + thread.getId() + " Random:" + rand.nextInt(max -
min));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Ahora si queremos que esta clase sea serializable habrá algunos problemas. El subproceso es una
de las ciertas clases de nivel de sistema que no son serializables. Así que tenemos que declarar
el hilo como transitorio . Al hacer esto podremos serializar los objetos de esta clase pero aún
tendremos un problema. Como puede ver en el constructor, establecemos los valores mínimo y
máximo de nuestro aleatorizador y, a continuación, iniciamos el hilo que es responsable de
generar e imprimir el valor aleatorio. Por lo tanto, al restaurar el objeto persistente llamando
a readObject (), el constructor no se ejecutará nuevamente ya que no hay creación de un nuevo
objeto. En ese caso, necesitamos desarrollar una serialización personalizada proporcionando dos
métodos dentro de la clase. Esos métodos son:
@Override
public void run() {
while(true) {
https://riptutorial.com/es/home 1015
Random rand = new Random();
System.out.println("Thread: " + thread.getId() + " Random:" + rand.nextInt(max -
min));
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
https://riptutorial.com/es/home 1016
}
}
}
Si ejecuta main, verá que hay dos subprocesos en ejecución para cada instancia de RangeRandom y
eso se debe a que el método Thread.start () ahora está en el constructor y en el readObject () .
Versiones y serialVersionUID
Cuando implementa la interfaz java.io.Serializable para hacer que una clase sea serializable, el
compilador busca un campo static final llamado serialVersionUID de tipo long . Si la clase no
tiene este campo declarado explícitamente, el compilador creará uno de estos campos y le
asignará un valor que sale de un cálculo dependiente de la implementación de serialVersionUID .
Este cálculo depende de varios aspectos de la clase y sigue las Especificaciones de
serialización de objetos proporcionadas por Sun. Pero, no se garantiza que el valor sea el mismo
en todas las implementaciones del compilador.
Este valor se usa para verificar la compatibilidad de las clases con respecto a la serialización
y esto se hace al deserializar un objeto guardado. El Tiempo de ejecución de serialización
verifica que serialVersionUID lea de los datos sin serializar y que serialVersionUID declarado
en la clase sea exactamente el mismo. Si ese no es el caso, lanza una InvalidClassException .
Mientras que serialVersionUID sea el mismo, la serialización de Java puede manejar diferentes
versiones de una clase. Cambios compatibles e incompatibles son;
Cambios compatibles
• Adición de campos: cuando la clase que se reconstituye tiene un campo que no aparece en el
flujo, ese campo en el objeto se inicializará con el valor predeterminado para su tipo. Si
se necesita una inicialización específica de la clase, la clase puede proporcionar un
método readObject que puede inicializar el campo a valores no predeterminados.
• Agregar clases: la secuencia contendrá la jerarquía de tipos de cada objeto en la
secuencia. La comparación de esta jerarquía en la secuencia con la clase actual puede
detectar clases adicionales. Como no hay información en la ruta desde la cual inicializar
el objeto, los campos de la clase se inicializarán a los valores predeterminados.
• Eliminación de clases: la comparación de la jerarquía de clases en la ruta con la de la
clase actual puede detectar que una clase se ha eliminado. En este caso, los campos y
objetos correspondientes a esa clase se leen de la secuencia. Los campos primitivos se
descartan, pero los objetos a los que hace referencia la clase eliminada se crean, ya que
se pueden consultar más adelante en la secuencia. Se recolectarán cuando el flujo se
recolecta o se restablece.
• Agregar métodos writeObject / readObject: si la versión que lee la secuencia tiene estos
métodos, se espera que readObject, como de costumbre, lea los datos necesarios escritos en
la secuencia por la serialización predeterminada. Debe llamar a defaultReadObject primero
antes de leer cualquier dato opcional. Se espera que el método writeObject llame a
defaultWriteObject para escribir los datos requeridos y luego puede escribir datos
opcionales.
https://riptutorial.com/es/home 1017
• Agregar java.io.Serializable: Esto es equivalente a agregar tipos. No habrá valores en el
flujo para esta clase, por lo que sus campos se inicializarán a los valores
predeterminados. El soporte para la subclasificación de clases no serializables requiere
que el supertipo de la clase tenga un constructor sin argumentos y la clase en sí misma se
inicializará con los valores predeterminados. Si el constructor no-arg no está disponible,
se lanza la excepción InvalidClassException.
• Cambio del acceso a un campo: los modificadores de acceso público, paquete, protegido y
privado no afectan la capacidad de serialización para asignar valores a los campos.
• Cambiar un campo de estático a no estático o transitorio a no transitorio: cuando se confía
en la serialización predeterminada para calcular los campos serializables, este cambio es
equivalente a agregar un campo a la clase. El nuevo campo se escribirá en la secuencia,
pero las clases anteriores ignorarán el valor, ya que la serialización no asignará valores
a campos estáticos o transitorios.
Cambios incompatibles
• Eliminar campos: si se elimina un campo en una clase, la secuencia escrita no contendrá su
valor. Cuando una clase anterior lee el flujo, el valor del campo se establecerá en el
valor predeterminado porque no hay ningún valor disponible en el flujo. Sin embargo, este
valor predeterminado puede perjudicar la capacidad de la versión anterior para cumplir su
contrato.
• Mover clases hacia arriba o hacia abajo en la jerarquía: esto no se puede permitir ya que
los datos en la secuencia aparecen en la secuencia incorrecta.
• Cambiar un campo no estático a estático o un campo no transitorio a transitorio: cuando se
confía en la serialización predeterminada, este cambio es equivalente a eliminar un campo
de la clase. Esta versión de la clase no escribirá esos datos en el flujo, por lo que no
estará disponible para ser leída por versiones anteriores de la clase. Al igual que al
eliminar un campo, el campo de la versión anterior se inicializará con el valor
predeterminado, lo que puede hacer que la clase falle de manera inesperada.
• Cambio del tipo declarado de un campo primitivo: Cada versión de la clase escribe los datos
con su tipo declarado. Las versiones anteriores de la clase que intenten leer el campo
fallarán porque el tipo de datos en la secuencia no coincide con el tipo del campo.
• Cambiar el método writeObject o readObject para que ya no escriba o lea los datos de campo
predeterminados o cambiarlo para que intente escribirlo o leerlo cuando la versión anterior
no lo hizo. Los datos de campo predeterminados deben aparecer constantemente o no aparecer
en la transmisión.
• Cambiar una clase de Serializable a Externalizable o viceversa es un cambio incompatible,
ya que la transmisión contendrá datos que son incompatibles con la implementación de la
clase disponible.
• Cambiar una clase de un tipo sin enumeración a un tipo de enumeración o viceversa, ya que
la secuencia contendrá datos que son incompatibles con la implementación de la clase
disponible.
• La eliminación de Serializable o Externalizable es un cambio incompatible, ya que cuando se
escribe ya no proporcionará los campos necesarios para las versiones anteriores de la
clase.
• Agregar el método writeReplace o readResolve a una clase es incompatible si el
comportamiento produce un objeto que es incompatible con cualquier versión anterior de la
clase.
https://riptutorial.com/es/home 1018
private String name;
private String email;
{
"id": 1,
"name": "Program @# 1",
"createdBy": {
"id": 1,
"name": "Bazlur Rahman",
"email": "[email protected]"
},
"contents": "Some contents"
}
Ahora puede hacer lo contrario muy fácilmente. Si tenemos este JSON, podemos unmarshal a un
objeto de programa usando ObjectMapper de la siguiente manera:
Ahora, digamos, este no es el caso real, vamos a tener un JSON diferente de una API que no
coincide con nuestra clase de Program .
{
"id": 1,
"name": "Program @# 1",
"ownerId": 1
"contents": "Some contents"
}
https://riptutorial.com/es/home 1019
Mire la cadena JSON, como puede ver, tiene un campo diferente que es owenerId.
Ahora, si desea serializar este JSON como hicimos anteriormente, tendrá excepciones.
@JsonIgnoreProperties(ignoreUnknown = true)
public class Program {}
Pero hay casos en los que realmente necesita este campo owerId . Digamos que desea relacionarlo
como un ID de la clase User .
Como puede ver, primero debe acceder a JsonNode desde JonsParser . Y luego puede extraer
fácilmente información de un JsonNode usando el método get() . y tienes que asegurarte del
nombre del campo. Debe ser el nombre exacto, error de ortografía causará excepciones.
mapper.registerModule(module);
@JsonDeserialize(using = ProgramDeserializer.class)
public class Program {
}
https://riptutorial.com/es/home 1020
Capítulo 153: Puntos de referencia
Introducción
Examples
Una de las herramientas para escribir pruebas de referencia adecuadas es JMH . Digamos que
queremos comparar el rendimiento de la búsqueda de un elemento en HashSet vs TreeSet .
La manera más fácil de conseguir JHM en su proyecto - es el uso de Maven y sombra plugin.
También puedes ver pom.xml de los ejemplos de JHM .
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>/benchmarks</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
https://riptutorial.com/es/home 1021
<version>1.18</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.18</version>
</dependency>
</dependencies>
package benchmark;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
public class CollectionFinderBenchmarkTest {
private static final int SET_SIZE = 10000;
@Setup
public void setupCollections() {
hashSet = new HashSet<>(SET_SIZE);
treeSet = new TreeSet<>();
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void testHashSet(Blackhole blackhole) {
blackhole.consume(hashSet.contains(stringToFind));
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void testTreeSet(Blackhole blackhole) {
blackhole.consume(treeSet.contains(stringToFind));
}
}
Por favor, tenga en cuenta este blackhole.consume() , volveremos más adelante. También
https://riptutorial.com/es/home 1022
necesitamos la clase principal para ejecutar benchmark:
package benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
new Runner(options).run();
}
}
Y estamos todos listos. Solo necesitamos ejecutar el mvn package (creará benchmarks.jar en su
carpeta /target ) y ejecutamos nuestra prueba de referencia:
Puede encontrar más información sobre cómo escribir puntos de referencia adecuados en el blog de
Aleksey Shipilëv , en el blog de Jacob Jenkov y en el blog de java-performance: 1 , 2 .
https://riptutorial.com/es/home 1023
Capítulo 154: Recursion
Introducción
La recursión ocurre cuando un método se llama a sí mismo. Tal método se llama recursivo . Un
método recursivo puede ser más conciso que un enfoque equivalente no recursivo. Sin embargo,
para una recursión profunda, a veces una solución iterativa puede consumir menos espacio de pila
finito de un hilo.
Observaciones
• Caso base. Esto definirá cuándo se detendrá su recursión y dará salida al resultado. El
caso base en el ejemplo factorial es:
if (n <= 1) {
return 1;
}
else {
return n * factorial(n - 1);
}
Salida
En este ejemplo, calculamos el n-ésimo número factorial. Los primeros factoriales son:
0! = 1
1! = 1
2! = 1 x 2 = 2
3! = 1 x 2 x 3 = 6
4! = 1 x 2 x 3 x 4 = 24
...
Examples
¿Qué es la recursión?
https://riptutorial.com/es/home 1024
En general, la recursión es cuando una función se invoca a sí misma, ya sea directa o
indirectamente. Por ejemplo:
Hay dos condiciones previas para usar funciones recursivas para resolver un problema específico:
1. Debe haber una condición base para el problema, que será el punto final de la recursión.
Cuando una función recursiva alcanza la condición base, no hace más llamadas recursivas
(más profundas).
2. Cada nivel de recursión debería estar intentando un problema más pequeño. La función
recursiva divide el problema en partes cada vez más pequeñas. Suponiendo que el problema es
finito, esto asegurará que la recursión termine.
En Java hay una tercera condición previa: no debería ser necesario repetir demasiado para
resolver el problema; Ver recursión profunda es problemática en Java
Ejemplo
La siguiente función calcula los factoriales utilizando la recursividad. Observe cómo el método
factorial llama a sí mismo dentro de la función. Cada vez que se llama a sí mismo, reduce el
parámetro n en 1. Cuando n alcanza 1 (la condición base), la función no retrocederá más.
Esta no es una forma práctica de calcular factoriales en Java, ya que no tiene en cuenta el desbordamiento de
enteros o el desbordamiento de la pila de llamadas (es decir, las excepciones de StackOverflowError ) para
valores grandes de n .
El método implementa un caso base (n <= 2) y un caso recursivo (n> 2). Esto ilustra el uso de la
recursión para calcular una relación recursiva.
Sin embargo, aunque este ejemplo es ilustrativo, también es ineficiente: cada instancia
individual del método llamará a la función en sí misma dos veces, lo que llevará a un
crecimiento exponencial en el número de veces que se llama a la función a medida que N aumenta.
La función anterior es O (2 N ), pero una solución iterativa equivalente tiene complejidad O (N).
Además, hay una expresión de "forma cerrada" que se puede evaluar en multiplicaciones de punto
flotante O (N).
https://riptutorial.com/es/home 1025
Cálculo de la suma de enteros de 1 a N
Este método es O (N) y se puede reducir a un simple bucle usando la optimización de la llamada
de cola. De hecho, hay una expresión de forma cerrada que calcula la suma en operaciones O(1) .
El siguiente método calcula el valor de num elevado a la potencia de exp mediante recursión:
Esto ilustra los principios mencionados anteriormente: el método recursivo implementa un caso
base (dos casos, n = 0 y n = 1) que termina la recursión, y un caso recursivo que llama al
método nuevamente. Este método es O (N) y se puede reducir a un simple bucle usando la
optimización de la llamada de cola.
/**
* Just a snippet to explain the idea of recursion
*
**/
https://riptutorial.com/es/home 1026
Atravesando una estructura de datos de árbol con recursión
Considere la clase de nodo con 3 datos de miembros, puntero izquierdo izquierdo y puntero
secundario derecho, como se muestra a continuación.
Podemos atravesar el árbol construido conectando el objeto de varias clases de Nodos como a
continuación, el recorrido se denomina recorrido transversal del árbol.
Tipos de recursion
En la recursión de la cabeza , la llamada recursiva, cuando ocurre, se produce antes que otro
procesamiento en la función (piense que sucede en la parte superior, o cabeza, de la función).
Una función con una ruta con una sola llamada recursiva al comienzo de la ruta usa lo que se
llama recursión de cabeza. La función factorial de una exposición anterior utiliza la recursión
de la cabeza. Lo primero que hace una vez que determina que se necesita recursión es llamarse a
sí mismo con el parámetro decrementado. Una función con una sola llamada recursiva al final de
una ruta está utilizando la recursión de cola.
tail(n-1); System.out.println(n);
} }
https://riptutorial.com/es/home 1027
into the next recursive call .
Ejemplo
Si se llama a este método con parámetros grandes (p. Ej., La recursion(50000) probablemente
provocará un desbordamiento de pila. El valor exacto depende del tamaño de la pila de hilos, que
a su vez depende de la construcción del hilo, los parámetros de la línea de comandos como -Xss ,
o el tamaño por defecto para la JVM.
Solución
Una recursión se puede convertir en un bucle almacenando los datos para cada llamada recursiva
en una estructura de datos. Esta estructura de datos se puede almacenar en el montón en lugar de
en la pila de hilos.
En general, los datos necesarios para restaurar el estado de invocación de un método se pueden
almacenar en una pila y un bucle while se puede usar para "simular" las llamadas recursivas. Los
datos que pueden requerirse incluyen:
Ejemplo
La siguiente clase permite la impresión recursiva de una estructura de árbol hasta una
profundidad específica.
https://riptutorial.com/es/home 1028
}
p.ej
Node n = new Node(10, new Node(20, new Node(50), new Node(1)), new Node(30, new Node(42),
null));
n.print(2);
System.out.println();
Huellas dactilares
(((...)20(...))10((...)30))
while (!stack.isEmpty()) {
// get topmost stack element
int index = stack.size() - 1;
Frame frame = stack.get(index); // get topmost frame
if (frame.maxDepth <= 0) {
// termial case (too deep)
https://riptutorial.com/es/home 1029
System.out.print("(...)");
stack.remove(index); // drop frame
} else {
switch (frame.state) {
case 0:
frame.state++;
Nota: Este es solo un ejemplo del enfoque general. A menudo, puede encontrar una forma mucho
mejor de representar un marco y / o almacenar los datos del marco.
Considere el siguiente método ingenuo para sumar dos números positivos usando la recursión:
Esto es algorítmicamente correcto, pero tiene un problema importante. Si llama a add con una
gran a , se bloqueará con un StackOverflowError , en cualquier versión de Java hasta (al menos)
Java 9.
https://riptutorial.com/es/home 1030
llegar a la respuesta 1001 .
El problema es que el tamaño de la pila de hilos de Java se fija cuando se crea el hilo. (Esto
incluye el hilo "principal" en un programa de un solo hilo.) Si se asignan demasiados marcos de
pila, la pila se desbordará. La JVM detectará esto y lanzará un StackOverflowError .
Un enfoque para lidiar con esto es simplemente usar una pila más grande. Hay opciones de JVM que
controlan el tamaño predeterminado de una pila, y también puede especificar el tamaño de la pila
como un parámetro del constructor Thread . Desafortunadamente, esto solo "quita" el
desbordamiento de pila. Si necesita realizar un cálculo que requiera una pila aún mayor,
entonces StackOverflowError regresa.
La solución real es identificar algoritmos recursivos donde es probable una recursión profunda y
realizar manualmente la optimización de la llamada de cola en el nivel del código fuente. Por
ejemplo, nuestro método de add se puede reescribir de la siguiente manera:
(Obviamente, hay mejores maneras de agregar dos enteros. Lo anterior es simplemente para
ilustrar el efecto de la eliminación manual de la llamada de la cola).
• Algunos códigos podrían depender de StackOverflowError para (por ejemplo) colocar un límite
en el tamaño de un problema computacional.
• Los administradores de seguridad de Sandbox a menudo se basan en analizar la pila de
llamadas al decidir si permiten que un código sin privilegios realice una acción
privilegiada.
"Los efectos de eliminar el marco de la pila de la persona que llama son visibles
para algunas API, en particular las verificaciones de control de acceso y el
seguimiento de la pila. Es como si la persona que llamó hubiera llamado directamente
a la persona llamada. Cualquier privilegio que posea la persona que llama se descarta
después de que el control se transfiere al Sin embargo, la vinculación y la
accesibilidad del método se calculan antes de la transferencia de control, y tienen
en cuenta al llamante que llama ".
En otras palabras, la eliminación de la llamada de cola podría hacer que un método de control de
acceso piense erróneamente que un código de confianza estaba llamando a una API sensible a la
seguridad.
https://riptutorial.com/es/home 1031
Capítulo 155: Recursos (en classpath)
Introducción
Java permite la recuperación de recursos basados en archivos almacenados dentro de un JAR junto
con las clases compiladas. Este tema se enfoca en cargar esos recursos y ponerlos a disposición
de su código.
Observaciones
Un recurso son datos de tipo archivo con un nombre de ruta, que reside en la ruta de clase. El
uso más común de los recursos es el agrupamiento de imágenes de aplicaciones, sonidos y datos de
solo lectura (como la configuración predeterminada).
Los métodos de ClassLoader aceptan un nombre de recurso similar a una ruta como un argumento y
buscan en cada ubicación en la ruta de clases del ClassLoader una entrada que coincida con ese
nombre.
• Si una ubicación de classpath es un archivo .jar, una entrada jar con el nombre
especificado se considera una coincidencia.
• Si una ubicación de classpath es un directorio, un archivo relativo debajo de ese
directorio con el nombre especificado se considera una coincidencia.
El nombre del recurso es similar a la porción de ruta de una URL relativa. En todas las
plataformas, utiliza barras diagonales ( / ) como separadores de directorios. No debe comenzar
con una barra.
• El nombre del recurso puede comenzar con una barra inclinada, en cuyo caso esa barra
inicial se elimina y el resto del nombre se pasa al método correspondiente de ClassLoader.
• Si el nombre del recurso no comienza con una barra diagonal, se trata en relación con la
clase a la que se llama el método getResource o getResourceAsStream. El nombre del recurso
real se convierte en paquete / nombre , donde paquete es el nombre del paquete al que
pertenece la clase, con cada período reemplazado por una barra y nombre es el argumento
original dado al método.
Por ejemplo:
package com.example;
https://riptutorial.com/es/home 1032
}
Los recursos deben colocarse en paquetes con nombre, en lugar de en la raíz de un archivo .jar,
por la misma razón que las clases se colocan en paquetes: para evitar colisiones entre varios
proveedores. Por ejemplo, si hay varios archivos .jar en la ruta de clase, y más de uno de ellos
contiene una entrada config.properties en su raíz, las llamadas a los métodos getResource o
getResourceAsStream devolverán las config.properties de cualquiera que sea .jar aparece primero
en el classpath Este no es un comportamiento predecible en entornos donde el orden de la ruta de
clase no está bajo el control directo de la aplicación, como Java EE.
Los recursos son de solo lectura. No hay forma de escribir en un recurso. Los desarrolladores
novatos a menudo cometen el error de suponer que, dado que el recurso es un archivo físico
independiente cuando se desarrolla en un IDE (como Eclipse), será seguro tratarlo como un
archivo físico separado en el caso general. Sin embargo, esto no es correcto; las aplicaciones
casi siempre se distribuyen como archivos .jar o archivos .war, y en tales casos, un recurso no
será un archivo separado y no se podrá escribir. (El método getFile de la clase de URL no es una
solución para esto; a pesar de su nombre, simplemente devuelve la parte de la ruta de una URL,
que de ninguna manera se garantiza que sea un nombre de archivo válido).
No hay una forma segura de enumerar los recursos en tiempo de ejecución. Nuevamente, dado que
los desarrolladores son responsables de agregar archivos de recursos a la aplicación en el
momento de la compilación, los desarrolladores ya deben conocer sus rutas. Si bien hay
soluciones alternativas, no son confiables y eventualmente fallarán.
Examples
package com.example;
package com.example;
defaults.load(defaultsStream);
}
https://riptutorial.com/es/home 1033
return defaults;
}
}
El recurso con la misma ruta y nombre puede existir en más de un archivo JAR en la ruta de
clase. Los casos comunes son recursos que siguen una convención o que son parte de una
especificación de empaquetado. Ejemplos de tales recursos son
• META-INF / MANIFEST.MF
• META-INF / beans.xml (CDI Spec)
• Propiedades de ServiceLoader que contienen proveedores de implementación
Para obtener acceso a todos estos recursos en diferentes tarros, uno tiene que usar un
ClassLoader, que tiene un método para esto. La Enumeration devuelta se puede convertir
convenientemente en una List mediante una función de colecciones.
Los últimos tres pasos se realizan normalmente al pasar la URL a un método de biblioteca o un
constructor para cargar el recurso. Normalmente utilizarás un método getResource en este caso.
También es posible leer los datos del recurso en el código de la aplicación. En este caso,
normalmente getResourceAsStream .
Los recursos que se pueden cargar desde la ruta de clase se indican mediante una ruta . La
sintaxis de la ruta es similar a la ruta de un archivo UNIX / Linux. Consiste en nombres simples
separados por caracteres de barra ( / ). Una ruta relativa comienza con un nombre y una ruta
absoluta comienza con un separador.
Como describen los ejemplos de Classpath, la classpath de una JVM define un espacio de nombres
superponiendo los espacios de nombres de los directorios y los archivos JAR o ZIP en la
classpath. Cuando se resuelve una ruta absoluta, los cargadores de clases interpretan la inicial
/ como la raíz del espacio de nombres. Por el contrario, una ruta relativa puede resolverse en
relación con cualquier "carpeta" en el espacio de nombres. La carpeta utilizada dependerá del
objeto que utilice para resolver la ruta.
https://riptutorial.com/es/home 1034
• Un literal de clase le dará el objeto de Class para cualquier clase que pueda nombrar en el
código fuente de Java; por ejemplo, String.class te da el objeto Class para el tipo String
.
• El Object.getClass() le dará el objeto Class para el tipo od cualquier objeto; por ejemplo,
"hello".getClass() es otra forma de obtener la Class del tipo String .
Una vez que tenga una instancia de Class o ClassLoader , puede encontrar un recurso, usando uno
de los siguientes métodos:
Métodos Descripción
Notas:
• La principal diferencia entre las versiones ClassLoader y Class de los métodos se encuentra
en la forma en que se interpretan las rutas relativas.
○ Los métodos de Class resuelven una ruta relativa en la "carpeta" que corresponde al
paquete de clases.
○ Los métodos de ClassLoader tratan las rutas relativas como si fueran absolutas; es
decir, resolverlos en la "carpeta raíz" del espacio de nombres de classpath.
• Las URL devueltas se podrán resolver mediante URL.toStream() . Pueden ser file: URL u otras
URL convencionales, pero si el recurso reside en un archivo JAR, serán jar: URL que
identifican el archivo JAR y un recurso específico dentro de él.
https://riptutorial.com/es/home 1035
Capítulo 156: Redes
Sintaxis
Examples
while (true) {
// Wait for a client connection.
// Once a client connected, we get a "Socket" object
// that can be used to send and receive messages to/from the newly
// connected client
Socket clientSocket = serverSocket.accept();
https://riptutorial.com/es/home 1036
OutputStream outStream = socket.getOutputStream();
PrintWriter writer = new PrintWriter(
new OutputStreamWriter(outStream, StandardCharsets.UTF_8));
writer.println("Hello world!");
writer.flush();
1. Al igual que los archivos y otros recursos externos, es importante que le informemos al
sistema operativo cuando hayamos terminado con ellos. Cuando hayamos terminado con un
socket, llame a socket.close() para cerrarlo correctamente.
2. Los sockets manejan las operaciones de E / S (entrada / salida) que dependen de una
variedad de factores externos. Por ejemplo, ¿qué pasa si el otro lado se desconecta de
repente? ¿Qué pasa si hay un error de red? Estas cosas están más allá de nuestro control.
Esta es la razón por la que muchas operaciones de socket pueden generar excepciones,
especialmente IOException .
Por lo tanto, un código más completo para el cliente sería algo como esto:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
https://riptutorial.com/es/home 1037
new InputStreamReader(in, StandardCharsets.UTF_8));
// Read from the socket and print line by line
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
catch (IOException e) {
e.printStackTrace();
} finally {
// This finally block ensures the socket is closed.
// A try-with-resources block cannot be used because
// the socket is passed into a thread, so it isn't
// created and closed in the same block
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Cliente:
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
https://riptutorial.com/es/home 1038
public class TrustLoader {
}
}
import java.io.*;
import java.net.Socket;
public static void main(String[] args) throws IOException {//We don't handle Exceptions in
this example
//Open a socket to stackoverflow.com, port 80
Socket socket = new Socket("stackoverflow.com",80);
https://riptutorial.com/es/home 1039
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
PrintWriter writer = new PrintWriter(new BufferedOutputStream(outStream));
Debería obtener una respuesta que comience con HTTP/1.1 200 OK , que indica una respuesta HTTP
normal, seguida del resto del encabezado HTTP, seguida de la página web sin procesar en formato
HTML.
Tenga en cuenta que el método readFully() es importante para evitar una excepción prematura de
EOF. A la última línea de la página web le puede faltar una devolución, para indicar el final de
la línea, luego readLine() se quejará, por lo que uno debe leerla a mano o usar métodos de
utilidad de Apache commons-io IOUtils
Este ejemplo pretende ser una simple demostración de conectarse a un recurso existente mediante
un socket, no es una forma práctica de acceder a páginas web. Si necesita acceder a una página
web utilizando Java, es mejor utilizar una biblioteca de cliente HTTP existente, como el Cliente
HTTP de Apache o el Cliente HTTP de Google.
Client.java
import java.io.*;
import java.net.*;
En este caso, pasamos la dirección del servidor, a través de un argumento ( args[0] ). El puerto
que estamos utilizando es 4160.
https://riptutorial.com/es/home 1040
Servidor.java
import java.io.*;
import java.net.*;
En el lado del servidor, declare un DatagramSocket en el mismo puerto al que enviamos nuestro
mensaje (4160) y espere una respuesta.
Multidifusión
https://riptutorial.com/es/home 1041
public void send() throws IOException{
// make datagram packet
byte[] message = ("Multicasting...").getBytes();
DatagramPacket packet = new DatagramPacket(message, message.length,
InetAddress.getByName(ip), port);
// send packet
serverSocket.send(packet);
}
// join by ip
socket.joinGroup(InetAddress.getByName(ip));
}
https://riptutorial.com/es/home 1042
public static void main(String[] args) {
try {
final String ip = args[0];
final int port = Integer.parseInt(args[1]);
Client client = new Client(ip, port);
client.printMessage();
client.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
Primero ejecute el Cliente: El Cliente debe suscribirse a la IP antes de que pueda comenzar a
recibir paquetes. Si inicia el servidor y llama al método send() , y luego printMessage() un
cliente (& call printMessage() ). Nada ocurrirá porque el cliente se conectó después de que se
envió el mensaje.
Para continuar con el desarrollo y las pruebas, puede desactivar la verificación SSL mediante
programación instalando un administrador de confianza "confiable":
try {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
https://riptutorial.com/es/home 1043
String fileName = "file.zip"; // name of the file
String urlToGetFrom = "http://www.mywebsite.com/"; // URL to get it from
String pathToSaveTo = "C:\\Users\\user\\"; // where to put it
Notas
• No dejes los bloques de captura vacíos!
• En caso de error, compruebe si el archivo remoto existe
• Esta es una operación de bloqueo, puede llevar mucho tiempo con archivos grandes
https://riptutorial.com/es/home 1044
Capítulo 157: Referencias de objetos
Observaciones
Esto debería ayudarlo a comprender una "excepción de puntero nulo": uno de ellos obtiene uno
porque una referencia de objeto es nula, pero el código del programa espera que el programa use
algo en esa referencia de objeto. Sin embargo, eso merece su propio tema ...
Examples
Este tema explica el concepto de una referencia de objeto ; Está dirigido a personas que son
nuevas en la programación en Java. Ya debe estar familiarizado con algunos términos y
significados: definición de clase, método principal, instancia de objeto y la llamada de métodos
"en" un objeto, y pasar parámetros a los métodos.
int i = 5;
setPersonName(person, i);
Para ser plenamente competente en la programación de Java, debería poder explicar este ejemplo a
alguien que no esté en lo alto de su cabeza. Sus conceptos son fundamentales para entender cómo
funciona Java.
Como puede ver, tenemos un main que crea una instancia de un objeto para la person variable y
llama a un método para establecer el campo de name en ese objeto en "Bob" . Luego llama a otro
método y pasa a la person como uno de dos parámetros; el otro parámetro es una variable entera,
establecida en 5.
El método llamado establece el valor del name en el objeto pasado a "Linda", y establece la
variable entera pasada a 99, luego regresa.
Linda 5
Entonces, ¿por qué el cambio realizado en person tiene efecto en main , pero el cambio realizado
en el entero no lo hace?
https://riptutorial.com/es/home 1045
Cuando se realiza la llamada, el método principal pasa una referencia de objeto por person al
método setPersonName ; cualquier cambio que setAnotherName haga a ese objeto es parte de ese
objeto, por lo que esos cambios aún son parte de ese objeto cuando el método regresa.
Otra forma de decir lo mismo: la person apunta a un objeto (almacenado en el montón, si está
interesado). Cualquier cambio que el método haga a ese objeto se realiza "en ese objeto", y no
se ve afectado por si el método que realiza el cambio todavía está activo o ha regresado. Cuando
el método vuelve, cualquier cambio realizado en el objeto todavía se almacena en ese objeto.
Contrasta esto con el entero que se pasa. Dado que este es un int primitivo (y no una instancia
de objeto Integer), se pasa "por valor", lo que significa que su valor se proporciona al método,
no un puntero al entero original pasado. El método puede cambiarlo por el método propósitos
propios, pero eso no afecta a la variable utilizada cuando se realiza la llamada al método.
En Java, todas las primitivas se pasan por valor. Los objetos se pasan por referencia, lo que
significa que un puntero al objeto se pasa como parámetro a cualquier método que los tome.
Esto significa algo menos obvio: no es posible que un método llamado cree un nuevo objeto y lo
devuelva como uno de los parámetros. La única forma en que un método puede devolver un objeto
que se crea, directa o indirectamente, mediante la llamada al método, es como un valor de
retorno del método. Primero veamos cómo eso no funcionaría, y luego cómo funcionaría.
getAnotherObjectNot(person);
System.out.println(person.getName());
Linda 5
Linda
¿Qué pasó con el objeto que tenía George? Bueno, el parámetro que se pasó fue un indicador a
Linda; cuando el método getAnotherObjectNot creó un nuevo objeto, reemplazó la referencia al
objeto de Linda con una referencia al objeto de George. El objeto de Linda todavía existe (en el
montón), el método main todavía puede acceder a él, pero el método getAnotherObjectNot no podría
hacer nada con él después de eso, porque no tiene ninguna referencia a él. Parece que el autor
del código destinado al método crea un nuevo objeto y lo devuelve, pero si es así, no funciona.
Si eso es lo que el escritor quería hacer, tendría que devolver el objeto recién creado desde el
método, algo como esto:
Person mary;
mary = getAnotherObject();
System.out.println(mary.getName());
https://riptutorial.com/es/home 1046
Y la salida del programa completo ahora sería:
Linda 5
Linda
Mary
int i = 5;
setPersonName(person, i);
System.out.println(person.getName() + " " + i);
getAnotherObjectNot(person);
System.out.println(person.getName());
Person person;
person = getAnotherObject();
System.out.println(person.getName());
}
https://riptutorial.com/es/home 1047
Capítulo 158: Registro (java.util.logging)
Examples
import java.util.logging.Level;
import java.util.logging.Logger;
// logging an exception
try {
// code might throw an exception
} catch (SomeException ex) {
// log a warning printing "Something went wrong"
// together with the exception message and stacktrace
LOG.log(Level.WARNING, "Something went wrong", ex);
}
// logging an object
LOG.log(Level.FINER, "String s: {0}", s);
Niveles de registro
Java Logging Api tiene 7 niveles . Los niveles en orden descendente son:
El nivel predeterminado es INFO (pero esto depende del sistema y utiliza una máquina virtual).
Nota : También hay niveles OFF (se pueden usar para desactivar el registro) y ALL (el opuesto de
OFF ).
https://riptutorial.com/es/home 1048
Código de ejemplo para esto:
import java.util.logging.Logger;
Por defecto, ejecutar esta clase solo generará mensajes con un nivel más alto que CONFIG :
El ejemplo anterior se ve perfectamente bien, pero muchos programadores olvidan que Java VM es
una máquina de pila. Esto significa que todos los parámetros del método se calculan antes de
ejecutar el método.
Este hecho es crucial para el registro en Java, especialmente para registrar algo en niveles
bajos, como FINE , FINER , FINEST que son desactivados por defecto. Veamos el takeOrder() Java
https://riptutorial.com/es/home 1049
para el método takeOrder() .
La línea 39 ejecuta el registro real. Todo el trabajo anterior (cargar variables, crear nuevos
objetos, concatenar cadenas en el método de format ) puede ser en vano si el nivel de registro
se establece más alto que FINE (y por defecto lo es). Dicho registro puede ser muy ineficiente y
consumir recursos innecesarios de memoria y procesador.
Por eso debe preguntar si el nivel que desea usar está habilitado.
Desde Java 8:
La clase Logger tiene métodos adicionales que toman un Supplier<String> como parámetro, que
simplemente puede proporcionar un lambda:
https://riptutorial.com/es/home 1050
El método de get() Proveedores get() en este caso, la lambda, solo se llama cuando el nivel
correspondiente está habilitado y por lo tanto la construcción if ya no es necesaria.
https://riptutorial.com/es/home 1051
Capítulo 159: Seguridad y criptografía
Examples
Para calcular los hashes de bloques de datos relativamente pequeños utilizando diferentes
algoritmos:
new SecureRandom().nextBytes(sample);
Sample: E4F14CEA2384F70B706B53A6DF8C5EFE
Tenga en cuenta que la llamada a nextBytes() puede bloquearse mientras se recopila la entropía
según el algoritmo que se esté utilizando.
randomness.nextBytes(sample);
https://riptutorial.com/es/home 1052
Provider: SUN version 1.8
Algorithm: SHA1PRNG
Sample: C80C44BAEB352FD29FBBE20489E4C0B9
dhGenerator.initialize(1024);
dsaGenerator.initialize(1024);
rsaGenerator.initialize(2048);
Para especificar una fuente de aleatoriedad para usar al generar las claves:
signer.initSign(privateKey);
signer.update(data);
Tenga en cuenta que el algoritmo de firma debe ser compatible con el algoritmo utilizado para
generar el par de claves.
verifier.initVerify(publicKey);
verifier.update(data);
https://riptutorial.com/es/home 1053
Signature: true
rsa.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
rsa.update(message.getBytes());
final byte[] result = rsa.doFinal();
Message: Hello
Encrypted: 5641FBB9558ECFA9ED...
Tenga en cuenta que al crear el objeto Cipher , debe especificar una transformación que sea
compatible con el tipo de clave que se está utilizando. (Consulte Nombres de algoritmos estándar
JCA para obtener una lista de las transformaciones admitidas). Para los datos de cifrado RSA, la
longitud de message.getBytes() debe ser menor que el tamaño de la clave. Vea esta respuesta SO
para detalles.
rsa.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
rsa.update(cipherText);
final String result = new String(rsa.doFinal());
Decrypted: Hello
https://riptutorial.com/es/home 1054
Capítulo 160: Seguridad y criptografía
Introducción
Las prácticas de seguridad en Java se pueden separar en dos categorías amplias, vagamente
definidas; Seguridad de la plataforma Java, y programación Java segura.
Las prácticas de programación de Java seguras se refieren a las mejores formas de escribir
programas de Java seguros. Incluye temas como el uso de números aleatorios y la criptografía, y
la prevención de vulnerabilidades.
Observaciones
Si bien los ejemplos deben hacerse claramente, algunos temas que deben cubrirse son:
Examples
La jce
La extensión de criptografía de Java (JCE) es un marco integrado en la JVM para permitir a los
desarrolladores utilizar la criptografía de forma fácil y segura en sus programas. Para ello,
proporciona una interfaz simple y portátil a los programadores, mientras utiliza un sistema de
proveedores JCE para implementar de forma segura las operaciones criptográficas subyacentes.
Una de las mejores prácticas comúnmente aceptadas para manejar claves en tiempo de ejecución es
almacenarlas solo como matrices de byte , y nunca como cadenas. Esto se debe a que las cadenas
Java son inmutables y no se pueden "borrar" o "borrar a cero" manualmente en la memoria;
mientras que una referencia a una cadena puede ser eliminada, la cadena exacta permanecerá en la
memoria hasta que su segmento de memoria sea recolectado y reutilizado. Un atacante tendría una
ventana grande en la que podría volcar la memoria del programa y encontrar fácilmente la clave.
Por el contrario, las matrices de byte son mutables y sus contenidos pueden sobrescribirse en su
lugar; es una buena idea 'poner a cero' sus llaves tan pronto como ya no las necesite.
Contenido necesita
Preocupaciones de redes
Contenido necesita
Aleatoriedad y tu
Contenido necesita
Para la mayoría de las aplicaciones, la clase java.utils.Random es una fuente perfectamente fina
de datos "aleatorios". Si necesita elegir un elemento aleatorio de una matriz, o generar una
https://riptutorial.com/es/home 1055
cadena aleatoria, o crear un identificador "único" temporal, probablemente debería usar Random .
Hashing y Validación
Una función hash criptográfica es un miembro de una clase de funciones con tres propiedades
vitales; Consistencia, singularidad e irreversibilidad.
Consistencia: dados los mismos datos, una función hash siempre devolverá el mismo valor. Es
decir, si X = Y, f (x) siempre será igual a f (y) para la función hash f.
Unicidad: no hay dos entradas para una función hash que resultarán en la misma salida. Es decir,
si X! = Y, f (x)! = F (y), para cualquier valor de X e Y.
Muchas funciones carecen de al menos uno de estos atributos. Por ejemplo, se sabe que MD5 y SHA1
tienen colisiones, es decir, dos entradas que tienen la misma salida, por lo que carecen de
singularidad. Algunas funciones que actualmente se consideran seguras son SHA-256 y SHA-512.
https://riptutorial.com/es/home 1056
Capítulo 161: ServiceLoader
Observaciones
ServiceLoader se puede usar para obtener instancias de clases que amplían un tipo dado (=
servicio) que se especifican en un archivo empaquetado en un archivo .jar . El servicio que se
extiende / implementa a menudo es una interfaz, pero esto no es necesario.
Para que ServiceLoader descubra, debe ServiceLoader un archivo de texto con el nombre del nombre
de tipo completo del servicio implementado dentro del directorio META-INF/services en el archivo
jar. Este archivo contiene un nombre completo de una clase que implementa el servicio por línea.
Examples
Servicio de registrador
El siguiente ejemplo muestra cómo crear una instancia de una clase para el registro a través del
ServiceLoader .
Servicio
package servicetest;
import java.io.IOException;
package servicetest.logger;
import servicetest.Logger;
@Override
public void log(String message) {
System.err.println(message);
}
@Override
public void close() {
}
package servicetest.logger;
https://riptutorial.com/es/home 1057
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import servicetest.Logger;
@Override
public void log(String message) throws IOException {
writer.append(message);
writer.newLine();
}
@Override
public void close() throws IOException {
writer.close();
}
servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger
Uso
El siguiente método main escribe un mensaje a todos los registradores disponibles. Los
registradores se ServiceLoader instancias utilizando ServiceLoader .
// iterate through instances of available loggers, writing the message to each one
Iterator<Logger> iterator = loader.iterator();
while (iterator.hasNext()) {
try (Logger logger = iterator.next()) {
logger.log(message);
}
}
}
https://riptutorial.com/es/home 1058
creación de instancias (pero no el cableado), se puede construir un mecanismo de inyección de
dependencia simple en Java SE. Con la interfaz y la implementación de ServiceLoader, la
separación se vuelve natural y los programas se pueden extender convenientemente. En realidad,
una gran cantidad de API de Java están implementadas basadas en el ServiceLoader
package example;
long getBalance();
}
package example.impl;
import example.AccountingService;
Además, accounting-impl.jar contiene un archivo que declara que este contenedor proporciona una
implementación de AccountingService . El archivo debe tener una ruta que comience con META-
INF/services/ y debe tener el mismo nombre que el nombre completo de la interfaz:
• META-INF/services/example.AccountingService
example.impl.DefaultAccountingService
Dado que ambos archivos están en el classpath del programa, que consume el AccountingService ,
se puede obtener una instancia del Servicio utilizando el ServiceLauncher
https://riptutorial.com/es/home 1059
}
Tenga en cuenta que al invocar next() creará una nueva instancia. Si desea reutilizar una
instancia, debe utilizar el método iterator iterator() del ServiceLoader o el bucle for-each
como se muestra arriba.
https://riptutorial.com/es/home 1060
Capítulo 162: Servicio de impresión de Java
Introducción
La API de Java Print Service proporciona funcionalidades para descubrir servicios de impresión y
enviar solicitudes de impresión para ellos.
Examples
Para descubrir todos los servicios de impresión disponibles, podemos usar la clase
PrintServiceLookup . Veamos cómo:
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
Este programa, cuando se ejecuta en un entorno Windows, imprimirá algo como esto:
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
https://riptutorial.com/es/home 1061
System.out.println("Default print service name: " + defaultPrintService.getName());
}
• los datos que se imprimirán (consulte Creación del documento que se imprimirá )
• un conjunto de atributos
printJob.print(doc, pras);
Doc es una interfaz y la API del servicio de impresión Java proporciona una implementación
simple llamada SimpleDoc .
• el propio contenido de datos de impresión (un correo electrónico, una imagen, un documento,
etc.)
• el formato de datos de impresión, denominado DocFlavor (tipo MIME + clase de
representación).
Antes de crear el objeto Doc , debemos cargar nuestro documento desde algún lugar. En el
ejemplo, cargaremos un archivo específico del disco:
Entonces, ahora tenemos que elegir un DocFlavor que coincida con nuestro contenido. La clase
DocFlavor tiene un montón de constantes para representar los tipos de datos más habituales.
Vamos a elegir el INPUT_STREAM.PDF uno:
https://riptutorial.com/es/home 1062
Ahora, podemos crear una nueva instancia de SimpleDoc :
El objeto doc ahora se puede enviar a la solicitud de trabajo de impresión (consulte Creación de
un trabajo de impresión desde un servicio de impresión ).
Antes de elegir uno de ellos y qué valor tendrá cada uno, primero debemos crear un conjunto de
atributos:
pras.add(new Copies(5));
pras.add(MediaSize.ISO_A4);
pras.add(OrientationRequested.PORTRAIT);
pras.add(PrintQuality.NORMAL);
El objeto pras ahora se puede enviar a la solicitud de trabajo de impresión (consulte Creación
de un trabajo de impresión desde un servicio de impresión ).
La API del servicio de impresión de Java proporciona algunas funcionalidades para informarse
sobre estos escenarios. Todo lo que tenemos que hacer es:
Cuando cambie el estado del trabajo de impresión, se nos notificará. Podemos hacer lo que sea
necesario, por ejemplo:
import javax.print.event.PrintJobEvent;
https://riptutorial.com/es/home 1063
import javax.print.event.PrintJobListener;
printJob.addPrintJobListener(new LoggerPrintJobListener());
printJob.print(doc, pras);
pje.getPrintJob().getAttributes();
https://riptutorial.com/es/home 1064
import javax.print.event.PrintJobEvent;
import javax.print.event.PrintJobAdapter;
printJob.addPrintJobListener(new LoggerPrintJobAdapter());
printJob.print(doc, pras);
https://riptutorial.com/es/home 1065
Capítulo 163: Singletons
Introducción
Un singleton es una clase que solo tiene una sola instancia. Para obtener más información sobre
el patrón de diseño Singleton, consulte el tema Singleton en la etiqueta Patrones de diseño .
Examples
Enum Singleton
Java SE 5
La JVM ofrece una garantía de que los valores de enumeración no se instanciarán más de una vez,
lo que otorga al patrón de enumeración de enumeración una defensa muy fuerte contra los ataques
de reflexión.
Esta es la forma recomendada de implementar el patrón de singleton, como lo explica Joshua Bloch
en Effective Java.
Este tipo de Singleton es seguro para subprocesos y evita el bloqueo innecesario después de que
se haya creado la instancia de Singleton.
Java SE 5
// instance of class
private static volatile MySingleton instance = null;
// Private constructor
private MySingleton() {
// Some code for constructing object
}
https://riptutorial.com/es/home 1066
//The singleton instance doesn't exist, lock and check again
synchronized(MySingleton.class) {
result = instance;
if(result == null) {
instance = result = new MySingleton();
}
}
}
return result;
}
}
private Singleton() {}
Se puede argumentar que este ejemplo es efectivamente una inicialización perezosa. La sección
12.4.1 de la especificación del lenguaje Java establece:
Por lo tanto, mientras no haya otros campos estáticos o métodos estáticos en la clase, la
instancia de Singleton no se inicializará hasta que se invoque el método getInstance() primera
vez.
private Singleton() {}
}
https://riptutorial.com/es/home 1067
Esto inicializa la variable INSTANCE en la primera llamada a Singleton.getInstance() ,
aprovechando las garantías de seguridad de subprocesos del idioma para la inicialización
estática sin necesidad de sincronización adicional.
Esta implementación también se conoce como patrón singleton de Bill Pugh. [Wiki]
En este ejemplo, la clase base Singleton proporciona el método getMessage() que devuelve "Hello
world!" mensaje.
/*
Enumeration that represents possible classes of singleton instance.
If unknown, we'll go with base class - Singleton.
*/
enum SingletonKind {
UNKNOWN,
LOWERCASE,
UPPERCASE
}
//Base class
class Singleton{
/*
Extended classes has to be private inner classes, to prevent extending them in
uncontrolled manner.
*/
private class UppercaseSingleton extends Singleton {
private UppercaseSingleton(){
super();
}
@Override
public String getMessage() {
return super.getMessage().toUpperCase();
}
}
@Override
public String getMessage() {
return super.getMessage().toLowerCase();
}
}
https://riptutorial.com/es/home 1068
private static Singleton instance;
/*
By using this method prior to getInstance() method, you effectively change the
type of singleton instance to be created.
*/
public static void setKind(SingletonKind kind) {
Singleton.kind = kind;
}
/*
If needed, getInstance() creates instance appropriate class, based on value of
singletonKind field.
*/
public static Singleton getInstance()
throws NoSuchMethodException,
IllegalAccessException,
InvocationTargetException,
InstantiationException {
if(instance==null){
synchronized (Singleton.class){
if(instance==null){
Singleton singleton = new Singleton();
switch (kind){
case UNKNOWN:
instance = singleton;
break;
case LOWERCASE:
/*
I can't use simple
LowercaseSingleton.class.getDeclaredConstructor(Singleton.class);
break;
https://riptutorial.com/es/home 1069
case UPPERCASE:
UppercaseSingleton.class.getDeclaredConstructor(Singleton.class);
ucConstructor.setAccessible(true);
instance = ucConstructor.newInstance(singleton);
}
}
}
}
return instance;
}
//Singleton.setKind(SingletonKind.UPPERCASE);
//Singleton.setKind(SingletonKind.LOWERCASE);
https://riptutorial.com/es/home 1070
Capítulo 164: Sockets de Java
Introducción
Los sockets son una interfaz de red de bajo nivel que ayuda a crear una conexión entre dos
programas, principalmente clientes que pueden estar o no ejecutándose en la misma máquina.
Observaciones
TCP es adecuado para aplicaciones que requieren alta confiabilidad, y el tiempo de transmisión
es relativamente menos crítico.
UDP es adecuado para aplicaciones que necesitan una transmisión rápida y eficiente, como los
juegos. La naturaleza sin estado de UDP también es útil para servidores que responden a pequeñas
consultas de un gran número de clientes.
Existe una garantía absoluta de que los datos transferidos permanecen intactos y llegan en el
mismo orden en que se enviaron en caso de TCP.
mientras que no hay garantía de que los mensajes o paquetes enviados alcancen en absoluto en
UDP.
Examples
Nuestro servidor TCP echo back será un hilo separado. Es simple como es un comienzo. Solo
devolverá lo que sea que envíe, pero en mayúscula.
// This class implements server sockets. A server socket waits for requests to come
// in over the network only when it is allowed through the local firewall
ServerSocket serverSocket;
@Override
public void run(){
https://riptutorial.com/es/home 1071
try {
// We want the server to continuously accept connections
while(!Thread.interrupted()){
}
// Close the server once done.
serverSocket.close();
} catch (IOException ex) {
Logger.getLogger(CAPECHOServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void run(){
while(!Thread.interrupted()){
try {
// Log with the port number and machine ip
Logger.getLogger((this.getClass().getName())).log(Level.INFO, "Listening for
Clients at {0} on {1}", new Object[]{serverSocket.getLocalPort(),
InetAddress.getLocalHost().getHostAddress()});
Socket client = serverSocket.accept(); // Accept client conncetion
// Now get DataInputStream and DataOutputStreams
DataInputStream istream = new DataInputStream(client.getInputStream()); // From
client's input stream
DataOutputStream ostream = new DataOutputStream(client.getOutputStream());
// Important Note
/*
The server's input is the client's output
The client's input is the server's output
*/
// Send a welcome message
ostream.writeUTF("Welcome!");
try {
serverSocket.close();
} catch (IOException ex) {
Logger.getLogger(CAPECHOServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
https://riptutorial.com/es/home 1072
Welcome!
Bueno, la conexión se perdió porque la terminamos. A veces tendríamos que programar nuestro
propio cliente TCP. En este caso, necesitamos que un cliente solicite información del usuario y
la envíe a través de la red para recibir la información en mayúsculas.
Si el servidor envía los datos primero, el cliente debe leer los datos primero.
Socket server;
Scanner key; // Scanner for input
@Override
public void run(){
DataInputStream istream = null;
DataOutputStream ostream = null;
try {
istream = new DataInputStream(server.getInputStream()); // Familiar lines
ostream = new DataOutputStream(server.getOutputStream());
System.out.println(istream.readUTF()); // Print what the server sends
System.out.print(">");
String tosend = key.nextLine();
ostream.writeUTF(tosend); // Send whatever the user typed to the server
System.out.println(istream.readUTF()); // Finally read what the server sends
before exiting.
} catch (IOException ex) {
Logger.getLogger(CAPECHOClient.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
istream.close();
ostream.close();
server.close();
} catch (IOException ex) {
Logger.getLogger(CAPECHOClient.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
ostream.writeUTF("Welcome!");
https://riptutorial.com/es/home 1073
Y ahora ejecuta el servidor y el cliente, deberías tener una salida similar a esta
Welcome!
>
https://riptutorial.com/es/home 1074
Capítulo 165: SortedMap
Introducción
Examples
Punto clave :-
Ejemplo
// Get an iterator
Iterator i = set.iterator();
// Display elements
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
https://riptutorial.com/es/home 1075
Capítulo 166: StringBuffer
Introducción
Examples
Puntos clave :-
Métodos: -
class Test {
public static void main(String args[])
{
String str = "study";
str.concat("tonight");
System.out.println(str); // Output: study
https://riptutorial.com/es/home 1076
Lea StringBuffer en línea: https://riptutorial.com/es/java/topic/10757/stringbuffer
https://riptutorial.com/es/home 1077
Capítulo 167: StringBuilder
Introducción
La clase StringBuilder de Java se utiliza para crear una cadena mutable (modificable). La clase
StringBuilder de Java es la misma que la clase StringBuffer, excepto que no está sincronizada.
Está disponible desde JDK 1.5.
Sintaxis
• nuevo StringBuilder ()
Observaciones
La creación de un nuevo StringBuilder con tipo char como parámetro daría como resultado que se
llame al constructor con int capacity argumento y no a la String string argumento:
Examples
Para evitar esto, debe utilizarse StringBuilder , que permite crear la String en O(s.length() *
n) lugar:
https://riptutorial.com/es/home 1078
final int n = ...
final String s = ...
• La clase StringBuffer ha estado presente desde Java 1.0 y proporciona una variedad de
métodos para construir y modificar un "búfer" que contiene una secuencia de caracteres.
• La clase StringBuilder se agregó en Java 5 para abordar los problemas de rendimiento con la
clase StringBuffer original. Las API para las dos clases son esencialmente las mismas. La
principal diferencia entre StringBuffer y StringBuilder es que el primero es seguro para
subprocesos y está sincronizado y el segundo no.
int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.
Las clases StringBuffer y StringBuilder son adecuadas tanto para ensamblar como para modificar
cadenas; es decir, proporcionan métodos para reemplazar y eliminar caracteres, así como
agregarlos en varios. Las dos clases de remisión son específicas a la tarea de ensamblar
cadenas.
https://riptutorial.com/es/home 1079
// The same thing using the `String.format` convenience method
System.out.print(String.format("One=%d, color=%s%n", one, color));
La clase StringJoiner no es ideal para la tarea anterior, por lo que aquí hay un ejemplo de
StringJoiner formatear una matriz de cadenas.
https://riptutorial.com/es/home 1080
Capítulo 168: sun.misc.Unsafe
Observaciones
La clase Unsafe permite que un programa haga cosas que no están permitidas por el compilador de
Java. Los programas normales deben evitar el uso Unsafe .
ADVERTENCIAS
1. Sicomete un error al utilizar las API no Unsafe , es probable que sus aplicaciones causen
que la JVM se bloquee y / o muestre síntomas que son difíciles de diagnosticar.
2. LaAPI Unsafe está sujeta a cambios sin previo aviso. Si lo usa en su código, es posible
que deba volver a escribir el código al cambiar las versiones de Java.
Examples
Si bien este ejemplo se compilará, es probable que falle en tiempo de ejecución a menos que la
clase Insegura se haya cargado con el cargador de clases primario. Para asegurarse de que esto
suceda, la JVM debe cargarse con los argumentos apropiados, como:
https://riptutorial.com/es/home 1081
Inseguro se almacena como un campo privado al que no se puede acceder directamente. El
constructor es privado y el único método para acceder a public static Unsafe getUnsafe() tiene
acceso privilegiado. Mediante el uso de la reflexión, hay una solución alternativa para que los
campos privados sean accesibles:
static {
Unsafe unsafe = null;
try {
final PrivilegedExceptionAction<Unsafe> action = () -> {
final Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = AccessController.doPrivileged(action);
} catch (final Throwable t) {
throw new RuntimeException("Exception accessing Unsafe", t);
}
UNSAFE = unsafe;
}
Usos de inseguros
Utilizar API
La familia de métodos get y put son relativos a un objeto dado. Si el objeto es nulo, se trata
como una dirección absoluta.
https://riptutorial.com/es/home 1082
UNSAFE.putLong(this, fieldOffset , newValue);
Algunos métodos solo se definen para int y longs. Puedes usar estos métodos en flotantes y
dobles usando floatToRawIntBits , intBitsToFloat, doubleToRawLongBits , longBitsToDouble`
https://riptutorial.com/es/home 1083
Capítulo 169: súper palabra clave
Examples
1. Nivel de constructor
2. Nivel de método
3. Nivel variable
Nivel de constructor
super palabra clave super se utiliza para llamar al constructor de la clase padre. Este
constructor puede ser constructor por defecto o constructor parametrizado.
class Parentclass
{
Parentclass(){
System.out.println("Constructor of Superclass");
}
}
class Subclass extends Parentclass
{
Subclass(){
/* Compile adds super() here at the first line
* of this constructor implicitly
*/
System.out.println("Constructor of Subclass");
}
Subclass(int n1){
/* Compile adds super() here at the first line
* of this constructor implicitly
*/
System.out.println("Constructor with arg");
}
void display(){
System.out.println("Hello");
}
public static void main(String args[]){
// Creating object using default constructor
Subclass obj= new Subclass();
//Calling sub class method
obj.display();
//Creating object 2 using arg constructor
Subclass obj2= new Subclass(10);
obj2.display();
}
}
https://riptutorial.com/es/home 1084
Nivel de método
super palabra clave super también se puede utilizar en caso de anulación del método. super
palabra clave super se puede utilizar para invocar o llamar al método de clase padre.
class Parentclass
{
//Overridden method
void display(){
System.out.println("Parent class method");
}
}
class Subclass extends Parentclass
{
//Overriding method
void display(){
System.out.println("Child class method");
}
void printMsg(){
//This would call Overriding method
display();
//This would call Overridden method
super.display();
}
public static void main(String args[]){
Subclass obj= new Subclass();
obj.printMsg();
}
}
Nota : Si no hay una modificación de método, entonces no necesitamos usar la palabra clave super
para llamar al método de clase principal.
Nivel variable
super se utiliza para referirse a la variable de instancia de clase primaria inmediata. En caso
de herencia, puede haber posibilidad de que la clase base y la clase derivada puedan tener
miembros de datos similares. Para diferenciar entre el miembro de datos de la clase base / padre
y la clase derivada / hijo, en el contexto de la clase derivada, los datos de la clase base los
miembros deben estar precedidos por una super palabra clave.
https://riptutorial.com/es/home 1085
}
}
Nota : Si no escribimos una super palabra clave antes del nombre del miembro de datos de la
clase base, se hará referencia como miembro de datos de la clase actual y el miembro de datos de
la clase base se ocultará en el contexto de la clase derivada.
https://riptutorial.com/es/home 1086
Capítulo 170: Tabla de picadillo
Introducción
Hashtable es una clase en las colecciones Java que implementa la interfaz Map y extiende la
clase de diccionario.
Examples
Tabla de picadillo
import java.util.*;
public class HashtableDemo {
public static void main(String args[]) {
// create and populate hash table
Hashtable<Integer, String> map = new Hashtable<Integer, String>();
map.put(101,"C Language");
map.put(102, "Domain");
map.put(104, "Databases");
System.out.println("Values before remove: "+ map);
// Remove value for key 102
map.remove(102);
System.out.println("Values after remove: "+ map);
}
}
https://riptutorial.com/es/home 1087
Capítulo 171: ThreadLocal
Observaciones
Se utiliza mejor para objetos que dependen de elementos internos durante la invocación de una
llamada, pero de lo contrario no tienen estado, como SimpleDateFormat , Marshaller
Examples
Java ThreadLocal se utiliza para crear variables locales de subprocesos. Se sabe que los
subprocesos de un Objeto comparten sus variables, por lo que la variable no es segura para
subprocesos. Podemos usar la sincronización para la seguridad de los subprocesos, pero si
queremos evitar la sincronización, ThreadLocal nos permite crear variables que son locales para
el subproceso, es decir, solo ese subproceso puede leer o escribir en esas variables, por lo que
los otros subprocesos ejecutan el mismo fragmento de código. no podrá acceder a las variables
ThreadLocal de los demás.
Esto puede ser usado, podemos usar variables ThreadLocal . en situaciones en las que tiene un
grupo de subprocesos como, por ejemplo, en un servicio web. Por ejemplo, la creación de un
objeto SimpleDateFormat cada vez que se realiza cada solicitud requiere mucho tiempo y no se
puede crear uno estático, ya que SimpleDateFormat no es seguro para subprocesos, por lo que
podemos crear un ThreadLocal para que podamos realizar operaciones seguras para subprocesos sin
la sobrecarga de crear SimpleDateFormat cada hora.
Cada hilo tiene su propia variable ThreadLocal y pueden usar los métodos get() y set() para
obtener el valor predeterminado o cambiar su valor local a Thread.
ThreadLocal instancias de ThreadLocal suelen ser campos estáticos privados en clases que desean
asociar el estado con un hilo.
Aquí hay un pequeño ejemplo que muestra el uso de ThreadLocal en el programa java y demuestra
que cada hilo tiene su propia copia de la variable ThreadLocal .
package com.examples.threads;
import java.text.SimpleDateFormat;
import java.util.Random;
https://riptutorial.com/es/home 1088
// SimpleDateFormat is not thread-safe, so give one to each thread
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new
ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
@Override
public void run() {
System.out.println("Thread Name= "+Thread.currentThread().getName()+" default
Formatter = "+formatter.get().toPattern());
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
formatter.set(new SimpleDateFormat());
Salida:
https://riptutorial.com/es/home 1089
Thread Name= 6 formatter = M/d/yy h:mm a
Como podemos ver en la salida, Thread-0 ha cambiado el valor de formateador pero aún así el
formateador predeterminado de thread-2 es el mismo que el valor inicializado.
En este ejemplo, solo tenemos un objeto, pero se comparte entre / ejecuta en diferentes
subprocesos. El uso normal de los campos para guardar el estado no sería posible porque el otro
hilo también lo vería (o probablemente no lo vería).
En Foo contamos desde cero. En lugar de guardar el estado en un campo, almacenamos nuestro
número actual en el objeto ThreadLocal, al que se puede acceder de forma estática. Tenga en
cuenta que la sincronización en este ejemplo no está relacionada con el uso de ThreadLocal, sino
que garantiza una mejor salida de la consola.
@Override
public void run() {
for (int i = 0; i < ITERATIONS; i++) {
synchronized (threadLocal) {
//Although accessing a static field, we get our own (previously saved) value.
int value = threadLocal.get();
System.out.println(Thread.currentThread().getName() + ": " + value);
try {
threadLocal.notifyAll();
if (i < ITERATIONS - 1) {
threadLocal.wait();
}
} catch (InterruptedException ex) {
https://riptutorial.com/es/home 1090
}
}
}
}
}
Desde la salida podemos ver que cada hilo cuenta por sí mismo y no usa el valor del otro:
Thread 1: 0
Thread 2: 0
Thread 1: 1
Thread 2: 1
Thread 1: 2
Thread 2: 2
Thread 1: 3
Thread 2: 3
Thread 1: 4
Thread 2: 4
Thread 1: 5
Thread 2: 5
Thread 1: 6
Thread 2: 6
Thread 1: 7
Thread 2: 7
Thread 1: 8
Thread 2: 8
Thread 1: 9
Thread 2: 9
https://riptutorial.com/es/home 1091
Capítulo 172: Tipo de conversión
Sintaxis
Examples
Se puede convertir un char a / desde cualquier tipo numérico utilizando las asignaciones de
punto de código especificadas por Unicode. Un char se representa en la memoria como un valor
entero de 16 bits sin signo (2 bytes), por lo que la conversión a byte (1 byte) eliminará 8 de
esos bits (esto es seguro para los caracteres ASCII). Los métodos de utilidad de la clase de
Character utilizan int (4 bytes) para transferir a / desde valores de punto de código, pero un
short (2 bytes) también sería suficiente para almacenar un punto de código Unicode.
Los primitivos numéricos se pueden convertir de dos maneras. La conversión implícita ocurre
cuando el tipo de origen tiene un rango más pequeño que el tipo de destino.
//Implicit casting
byte byteVar = 42;
short shortVar = byteVar;
int intVar = shortVar;
long longVar = intvar;
float floatVar = longVar;
double doubleVar = floatVar;
La conversión explícita se debe realizar cuando el tipo de origen tiene un rango mayor que el
tipo de destino.
//Explicit casting
double doubleVar = 42.0d;
float floatVar = (float) doubleVar;
long longVar = (long) floatVar;
int intVar = (int) longVar;
short shortVar = (short) intVar;
byte byteVar = (byte) shortVar;
https://riptutorial.com/es/home 1092
Fundición de objetos
Al igual que con los primitivos, los objetos pueden ser lanzados tanto explícita como
implícitamente.
La conversión implícita ocurre cuando el tipo de origen extiende o implementa el tipo de destino
(conversión a una superclase o interfaz).
Java proporciona el operador instanceof para probar si un objeto es de un tipo determinado o una
subclase de ese tipo. El programa puede elegir lanzar o no ese objeto en consecuencia.
https://riptutorial.com/es/home 1093
Capítulo 173: Tipos atómicos
Introducción
Los tipos atómicos de Java son tipos mutables simples que proporcionan operaciones básicas que
son seguras para subprocesos y atómicas sin tener que recurrir al bloqueo. Están diseñados para
usarse en casos en que el bloqueo sería un cuello de botella concurrente, o donde existe riesgo
de bloqueo o bloqueo.
Parámetros
Parámetro Descripción
Observaciones
Examples
Para código simple de múltiples hilos, el uso de la sincronización es aceptable. Sin embargo, el
uso de la sincronización tiene un impacto de vida, y a medida que la base de código se vuelve
más compleja, aumenta la probabilidad de que termine con un punto muerto , un hambre o un
bloqueo de vida .
En casos de concurrencia más compleja, el uso de variables atómicas suele ser una mejor
alternativa, ya que permite acceder a una variable individual de una manera segura para
subprocesos sin la sobrecarga de usar métodos sincronizados o bloques de código.
https://riptutorial.com/es/home 1094
Hay una notable excepción de que no hay tipos float y double . Estos se pueden simular mediante
el uso de Float.floatToIntBits(float) y Float.intBitsToFloat(int) para float , así como
Double.doubleToLongBits(double) y Double.longBitsToDouble(long) para dobles.
Si está dispuesto a usar sun.misc.Unsafe , puede usar cualquier variable primitiva como atómica
utilizando la operación atómica en sun.misc.Unsafe . Todos los tipos primitivos deben
convertirse o codificarse en int o longs para usarlos de esta manera. Para más sobre esto vea:
sun.misc.Unsafe .
/**
* Increments the integer at the given index
*/
public synchronized void count(int number) {
if (number >= 0 && number < counters.length) {
counters[number]++;
}
}
/**
* Obtains the current count of the number at the given index,
* or if there is no number at that index, returns 0.
*/
public synchronized int getCount(int number) {
return (number >= 0 && number < counters.length) ? counters[number] : 0;
}
}
Si un hilo intenta adquirir el bloqueo mientras otro lo retiene, el hilo que intenta iniciarse
se bloqueará (detendrá) en el paso 1 hasta que se libere el bloqueo. Si hay varios hilos en
espera, uno de ellos lo obtendrá y los otros continuarán bloqueados.
• Si hay mucha disputa por el bloqueo (es decir, un montón de subprocesos intenta
adquirirlo), entonces se pueden bloquear algunos subprocesos durante mucho tiempo.
https://riptutorial.com/es/home 1095
• Cuando hay varios subprocesos bloqueados en el mismo bloqueo, no hay ninguna garantía de
que ninguno de ellos se trate de manera "justa" (es decir, se garantiza que cada subproceso
está programado para ejecutarse). Esto puede conducir a la hambruna de hilos .
/**
* Increments the integer at the given index
*/
public void count(int number) {
if (number >= 0 && number < counters.length) {
counters[number].incrementAndGet();
}
}
/**
* Obtains the current count of the object at the given index,
* or if there is no number at that index, returns 0.
*/
public int getCount(int number) {
return (number >= 0 && number < counters.length) ?
counters[number].get() : 0;
}
}
Pero lo más importante es que podemos eliminar la palabra clave synchronized porque ya no se
requiere el bloqueo. Esto funciona porque las operaciones incrementAndGet() y get() son atómicas
y seguras para subprocesos . En este contexto, significa que:
• Cada contador en la matriz solo será observable en el estado "antes" de una operación (como
un "incremento") o en el estado "después".
• Suponiendo que la operación ocurra en el tiempo T , ningún hilo podrá ver el estado "antes"
después del tiempo T
Además, mientras que dos subprocesos podrían intentar actualizar la misma instancia de
AtomicInteger al mismo tiempo, las implementaciones de las operaciones aseguran que solo se
produzca un incremento a la vez en la instancia dada. Esto se hace sin bloqueo, lo que a menudo
resulta en un mejor rendimiento.
https://riptutorial.com/es/home 1096
Estas instrucciones de bajo nivel se utilizan para implementar operaciones de alto nivel en las
API de las respectivas clases AtomicXxx . Por ejemplo, (de nuevo, en pseudocódigo tipo C):
int increment() {
while (TRUE) {
int old = num;
int new = old + 1;
if (old == compare_and_swap(&num, old, new)) {
return new;
}
}
}
Incidentalmente, las instrucciones CAS suelen ser utilizadas por la JVM para implementar el
bloqueo no controlado . Si la JVM puede ver que un bloqueo no está bloqueado actualmente,
intentará usar un CAS para adquirir el bloqueo. Si el CAS tiene éxito, entonces no hay necesidad
de realizar la costosa programación de subprocesos, el cambio de contexto, etc. Para obtener más
información sobre las técnicas utilizadas, consulte Bloqueo sesgado en HotSpot .
https://riptutorial.com/es/home 1097
Capítulo 174: Tipos de datos de referencia
Examples
Dónde:
Lo que pasa:
int i = 10;
Desreferenciación
Cuando una referencia tiene el valor null , la desreferenciación da como resultado una excepción
NullPointerException :
https://riptutorial.com/es/home 1098
Capítulo 175: Tipos de datos primitivos
Introducción
Los 8 tipos de datos primitivos byte , short , int , long , char , boolean , float y double son
los tipos que almacenan la mayoría de los datos numéricos sin procesar en los programas Java.
Sintaxis
• int aInt = 8; // La parte definitoria (número) de esta declaración int se llama un literal.
• int hexInt = 0x1a; // = 26; Puedes definir literales con valores hexadecimales prefijados
con 0x .
• int binInt = 0b11010; // = 26; También puedes definir literales binarios; prefijado con 0b
.
• long goodLong = 10000000000L; // Por defecto, los literales enteros son de tipo int. Al
agregar la L al final del literal, le está diciendo al compilador que el literal es largo.
Sin esto, el compilador arrojaría un error de "Número entero demasiado grande".
• doble aDouble = 3.14; // Los literales de punto flotante son de tipo doble de forma
predeterminada.
• flotar aFloat = 3.14F; // Por defecto, este literal habría sido un doble (y causó un error
de "Tipos incompatibles"), pero al agregar una F le decimos al compilador que es un
flotador.
Observaciones
Java tiene 8 tipos de datos primitivos , a saber, boolean , byte , short , char , int , long ,
float y double . (Todos los demás tipos son tipos de referencia . Esto incluye todos los tipos
de matriz y los tipos / clases de objetos integrados que tienen un significado especial en el
lenguaje Java; por ejemplo, String , Class y Throwable y sus subclases).
El resultado de todas las operaciones (suma, resta, multiplicación, etc.) en un tipo primitivo
es al menos un int , por lo que sumar un short a un short produce un int , al igual que agregar
un byte a un byte , o un char a un char . Si desea asignar el resultado de eso a un valor del
mismo tipo, debe convertirlo. p.ej
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);
Dado el tamaño del código de operación de un byte de la Máquina Virtual Java, los
tipos de codificación en códigos de operación ejercen presión sobre el diseño de su
https://riptutorial.com/es/home 1099
conjunto de instrucciones. Si cada instrucción escrita admitiera todos los tipos de
datos en tiempo de ejecución de la Máquina Virtual Java, habría más instrucciones de
las que podrían representarse en un byte . [...] Se pueden usar instrucciones
separadas para convertir entre tipos de datos no compatibles y compatibles según sea
necesario.
Examples
El primitivo int
Un tipo de datos primitivos como int contiene valores directamente en la variable que lo está
utilizando, mientras que una variable que se declaró utilizando Integer contiene una referencia
al valor.
De acuerdo con la API de Java : "La clase Integer ajusta un valor del tipo primitivo int en un
objeto. Un objeto de tipo Integer contiene un campo único cuyo tipo es int".
Por defecto, int es un entero con signo de 32 bits. Puede almacenar un valor mínimo de -2 31 , y
un valor máximo de 2 31 - 1.
Si necesita almacenar un número fuera de este rango, en long debe usar long . Si se excede el
rango de valores de int produce un desbordamiento de enteros, lo que hace que el valor que
exceda el rango se agregue al sitio opuesto del rango (positivo se convierte en negativo y
viceversa). El valor es ((value - MIN_VALUE) % RANGE) + MIN_VALUE , o ((value + 2147483648) %
4294967296) - 2147483648
El primitivo corto
Un short es un entero con signo de 16 bits. Tiene un valor mínimo de -2 15 (-32,768), y un valor
máximo de 2 15 ‑1 (32,767)
https://riptutorial.com/es/home 1100
Los valores máximo y mínimo de short se pueden encontrar en:
El primitivo largo
De forma predeterminada, long es un entero con signo de 64 bits (en Java 8, puede ser firmado o
sin signo). Firmado, puede almacenar un valor mínimo de -2 63 , y un valor máximo de 2 63 - 1, y
sin firmar puede almacenar un valor mínimo de 0 y un valor máximo de 2 64 - 1
//an "L" must be appended to the end of the number, because by default,
//numbers are assumed to be the int type. Appending an "L" makes it a long
//as 549755813888 (2 ^ 39) is larger than the maximum value of an int (2^31 - 1),
//"L" must be appended
long bigNumber = 549755813888L;
Nota: la letra "L" adjunta al final del literal long distingue entre mayúsculas y minúsculas,
sin embargo, es una buena práctica usar mayúscula, ya que es más fácil distinguirla del dígito
uno:
2L == 2l; // true
Advertencia: Java almacena en caché instancias de objetos enteros del rango -128 a 127. El
razonamiento se explica aquí:
https://blogs.oracle.com/darcy/entry/boxing_and_caches_integer_valueof
https://riptutorial.com/es/home 1101
Para comparar correctamente los valores de 2 objetos largos, use el siguiente código (desde Java
1.7 en adelante):
La comparación de un largo primitivo con un objeto largo no dará como resultado un falso
negativo como la comparación de 2 objetos con == hace.
El primitivo booleano
El byte primitivo
Un byte es un entero con signo de 8 bits. Puede almacenar un valor mínimo de -2 7 (-128), y un
valor máximo de 2 7 - 1 (127)
https://riptutorial.com/es/home 1102
El flotador primitivo
Un float es un número de punto flotante IEEE 754 de 32 bits de precisión simple. Por defecto,
los decimales se interpretan como dobles. Para crear un float , simplemente agregue una f al
literal decimal.
Los flotadores manejan las cinco operaciones aritméticas comunes: suma, resta, multiplicación,
división y módulo.
Nota: Lo siguiente puede variar ligeramente como resultado de errores de punto flotante. Algunos
resultados se han redondeado con fines de claridad y legibilidad (es decir, el resultado impreso
del ejemplo de adición fue en realidad 34.600002).
// addition
float result = 37.2f + -2.6f; // result: 34.6
// subtraction
float result = 45.1f - 10.3f; // result: 34.8
// multiplication
float result = 26.3f * 1.7f; // result: 44.71
// division
float result = 37.1f / 4.8f; // result: 7.729166
// modulus
float result = 37.1f % 4.8f; // result: 3.4999971
Debido a la forma en que se almacenan los números de punto flotante (es decir, en forma
binaria), muchos números no tienen una representación exacta.
Si bien el uso de float está bien para la mayoría de las aplicaciones, no se debe usar float ni
double para almacenar representaciones exactas de números decimales (como cantidades
monetarias), o números donde se requiera mayor precisión. En su lugar, se debe utilizar la clase
BigDecimal .
float f1 = 0f;
float f2 = -0f;
https://riptutorial.com/es/home 1103
System.out.println(f1 == f2); // true
System.out.println(1f / f1); // Infinity
System.out.println(1f / f2); // -Infinity
System.out.println(Float.POSITIVE_INFINITY / Float.POSITIVE_INFINITY); // NaN
El doble primitivo
Debido a la forma en que se almacenan los números de punto flotante, muchos números no tienen
una representación exacta.
Si bien el uso del double está bien para la mayoría de las aplicaciones, no se debe usar ni
float ni double para almacenar números precisos, como la moneda. En su lugar, se debe usar la
clase BigDecimal
double d1 = 0d;
double d2 = -0d;
System.out.println(d1 == d2); // true
System.out.println(1d / d1); // Infinity
System.out.println(1d / d2); // -Infinity
System.out.println(Double.POSITIVE_INFINITY / Double.POSITIVE_INFINITY); // NaN
El primitivo char
Un char puede almacenar un solo carácter Unicode de 16 bits. Un literal de carácter está
encerrado entre comillas simples
https://riptutorial.com/es/home 1104
char defaultChar; // defaultChar == \u0000
Para definir un valor de char of ' se debe utilizar una secuencia de escape (carácter precedido
por una barra invertida):
También es posible añadir a un char . Por ejemplo, para iterar en cada letra minúscula, puede
hacer lo siguiente:
Java y la mayoría de los otros lenguajes almacenan números integrales negativos en una
representación llamada notación de complemento a 2 .
Para una representación binaria única de un tipo de datos que utiliza n bits, los valores se
codifican así:
Los bits n-1 menos significativos almacenan un número integral positivo x en representación
integral. El valor más significativo almacena un poco con el valor s . El valor representado por
esos bits es
x - s * 2 n-1
es decir, si el bit más significativo es 1, entonces un valor que es solo 1 mayor que el número
que podría representar con los otros bits ( 2 n-2 + 2 n-3 + ... + 2 1 + 2 0 = 2 n-1 - 1 ) se resta
permitiendo una representación binaria única para cada valor de - 2 n-1 (s = 1; x = 0) a 2 n-1 -
1 (s = 0; x = 2 n-1 - 1).
Esto también tiene el efecto secundario agradable, que puede agregar las representaciones
binarias como si fueran números binarios positivos:
v1 = x1 - s1 * 2n-1
v2 = x2 - s2 * 2n-1
https://riptutorial.com/es/home 1105
x1 + x2
s1 s2 resultado adicional
desbordamiento
0 0 No x1 + x2 = v1 + v2
x1 + x2 - 2n-1 = x1 + x2 - s2 * 2n-1
0 1 No
= v1 + v2
Tenga en cuenta que este hecho hace que sea fácil encontrar la representación binaria del
inverso aditivo (es decir, el valor negativo):
Observe que agregar el complemento bit a bit al número resulta en que todos los bits son 1.
Ahora agregue 1 para hacer que el valor se desborde y obtendrá el elemento neutral 0 (todos los
bits 0).
Por lo que el valor negativo de un número i se puede calcular utilizando (ignorando posible
promoción a int aquí)
(~i) + 1
https://riptutorial.com/es/home 1106
Primitivo Tipo de caja Tamaño de memoria de primitivo / en caja
Los objetos en caja siempre requieren 8 bytes para la administración de tipo y memoria, y como
el tamaño de los objetos es siempre un múltiplo de 8, todos los tipos en caja requieren un total
de 16 bytes . Además , cada uso de un objeto en caja implica almacenar una referencia que
representa otros 4 u 8 bytes, según las opciones de JVM y JVM.
En las operaciones de uso intensivo de datos, el consumo de memoria puede tener un gran impacto
en el rendimiento. El consumo de memoria aumenta aún más cuando se usan matrices: una matriz
float[5] solo requerirá 32 bytes; mientras que un Float[5] almacena 5 valores distintos de
valores nulos requerirá un total de 112 bytes (en 64 bits sin punteros comprimidos, esto aumenta
a 152 bytes).
Las sobrecargas de espacio de los tipos encajonados se pueden mitigar hasta cierto punto por los
cachés de valores encajonados. Algunos de los tipos en caja implementan un caché de instancias.
Por ejemplo, de forma predeterminada, la clase Integer almacenará en caché las instancias para
representar números en el rango de -128 a +127 . Sin embargo, esto no reduce el costo adicional
derivado de la indirección de memoria adicional.
Si crea una instancia de un tipo encuadrado ya sea mediante autofijación o llamando al método
static valueOf(primitive) , el sistema de tiempo de ejecución intentará utilizar un valor
almacenado en caché. Si su aplicación utiliza muchos valores en el rango que se almacena en la
memoria caché, esto puede reducir sustancialmente la penalización de memoria al usar tipos en
caja. Ciertamente, si está creando instancias de valor en caja "a mano", es mejor usar valueOf
lugar de new . (La new operación siempre crea una nueva instancia). Sin embargo, si la mayoría
de sus valores no están en el rango almacenado en la memoria caché, puede ser más rápido llamar
new y guardar la búsqueda de caché.
Primitivas de conversión
En Java, podemos convertir entre valores enteros y valores de punto flotante. Además, dado que
cada carácter corresponde a un número en la codificación Unicode, char tipos se pueden convertir
a y desde los tipos de enteros y de coma flotante. boolean es el único tipo de datos primitivo
que no se puede convertir ao desde cualquier otro tipo de datos primitivos.
https://riptutorial.com/es/home 1107
En consecuencia, una conversión de reducción se produce cuando un valor de un tipo de datos se
convierte en un valor de otro tipo de datos que ocupa menos bits que el anterior. La pérdida de
datos puede ocurrir en este caso.
Java realiza ampliaciones de conversiones automáticamente. Pero si desea realizar una conversión
de restricción (si está seguro de que no se produzcan pérdidas de datos), entonces se puede
forzar Java para realizar la conversión usando una construcción del lenguaje conocido como un
cast .
Ampliación de la conversión:
int a = 1;
double d = a; // valid conversion to double, no cast needed (widening)
Reducción de la conversión:
double d = 18.96
int b = d; // invalid conversion to int, will throw a compile-time error
int b = (int) d; // valid conversion to int, but result is truncated (gets rounded down)
// This is type-casting
// Now, b = 18
Tabla que muestra el rango de tamaño y valores de todos los tipos primitivos:
-128 a +127
-32,768 a +32,767
En t 32 bits firmado -2 31 a 2 31 - 1 0
-2,147,483,648 a +2,147,483,647
-9,223,372,036,854,775,808 a
9,223,372,036,854,775,807
https://riptutorial.com/es/home 1108
tipo de representación valor por
rango de valores
datos numérica defecto
negativo)
0 a 65,535
Notas:
1. Los mandatos de la Especificación del lenguaje Java que los tipos integrales firmados (
byte a long ) usan una representación binaria de complemento a dos, y los tipos de punto
flotante usan representaciones binarias estándar de punto flotante IEE 754.
2. Java 8 y versiones posteriores proporcionan métodos para realizar operaciones aritméticas
no firmadas en int y long . Si bien estos métodos permiten que un programa trate los
valores de los tipos respectivos como no firmados, los tipos siguen siendo tipos con signo.
3. El punto flotante más pequeño que se muestra arriba es subnormal ; Es decir, tienen menos
precisión que un valor normal . Los números normales más pequeños son 1.175494351e − 38 y
2.2250738585072014e − 308
4. Un char representa convencionalmente una unidad de código Unicode / UTF-16.
5. Aunque un valor boolean contiene solo un bit de información, su tamaño en memoria varía
según la implementación de la Máquina Virtual Java (vea el tipo booleano ).
https://riptutorial.com/es/home 1109
Capítulo 176: Tipos de referencia
Examples
• Fuerte referencia
• Referencia débil
• Referencia suave
• Referencia fantasma
1. fuerte referencia
El titular de la variable mantiene una fuerte referencia al objeto creado. Mientras esta
variable esté MyObject y mantenga este valor, el recolector de basura no recopilará la instancia
de MyObject .
2. Referencia débil
Cuando no desea mantener un objeto por más tiempo y necesita borrar / liberar la memoria
asignada para un objeto tan pronto como sea posible, esta es la manera de hacerlo.
Simplemente, una referencia débil es una referencia que no es lo suficientemente fuerte como
para obligar a un objeto a permanecer en la memoria. Las referencias débiles le permiten
aprovechar la capacidad del recolector de basura para determinar la accesibilidad para usted,
por lo que no tiene que hacerlo usted mismo.
myObjectRef.get();
3. Referencia suave
Las referencias blandas son ligeramente más fuertes que las débiles. Puede crear un objeto de
referencia suave de la siguiente manera:
Pueden aferrarse a la memoria con más fuerza que la referencia débil. Si tiene suficientes
recursos / recursos de memoria, el recolector de basura no limpiará las referencias blandas con
https://riptutorial.com/es/home 1110
tanto entusiasmo como las referencias débiles.
Las referencias blandas son útiles para usar en el almacenamiento en caché. Puede crear objetos
de referencia suave como un caché, donde se guardarán hasta que se agote la memoria. Cuando su
memoria no puede proporcionar suficientes recursos, el recolector de basura eliminará las
referencias blandas.
4. Referencia fantasma
Este es el tipo de referencia más débil. Si creó una referencia de objeto utilizando la
Referencia fantasma, el método get() siempre devolverá nulo.
El uso de esta referencia es que "los objetos de referencia fantasma, que se ponen en cola
después de que el recopilador determina que sus referentes pueden ser reclamados. Las
referencias fantasma se usan más a menudo para programar acciones de limpieza premente de una
manera más flexible que la posible Mecanismo de finalización de Java ". - De Phantom Reference
Javadoc de Oracle.
https://riptutorial.com/es/home 1111
Capítulo 177: Tokenizador de cuerdas
Introducción
El conjunto de delimitadores (los caracteres que separan los tokens) se puede especificar en el
momento de la creación o por token.
Examples
import java.util.StringTokenizer;
public class Simple{
public static void main(String args[]){
StringTokenizer st = new StringTokenizer("apple ball cat dog"," ");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
}
}
Salida:
manzana
bola
gato
perro
Salida:
manzana
bola de gato
perro
https://riptutorial.com/es/home 1112
Capítulo 178: TreeMap y TreeSet
Introducción
TreeMap y TreeSet son colecciones básicas de Java agregadas en Java 1.2. TreeMap es una
implementación de Map ordenada y mutable . De manera similar, TreeSet es una implementación de
Set ordenada y mutable .
TreeMap se implementa como un árbol rojo-negro, que proporciona tiempos de acceso O(log n) .
TreeSet se implementa utilizando un TreeMap con valores ficticios.
Examples
Java SE 7
Java SE 7
treeMap.put(10, "ten");
treeMap.put(4, "four");
treeMap.put(1, "one");
treeSet.put(12, "twelve");
Una vez que tenemos algunos elementos en el mapa, podemos realizar algunas operaciones:
También podemos iterar sobre los elementos del mapa usando un iterador o un bucle foreach. Tenga
en cuenta que las entradas se imprimen de acuerdo con su orden natural , no el orden de
inserción:
Java SE 7
https://riptutorial.com/es/home 1113
Primero, creamos un conjunto vacío, e insertamos algunos elementos en él:
Java SE 7
Java SE 7
treeSet.add(10);
treeSet.add(4);
treeSet.add(1);
treeSet.add(12);
Una vez que tenemos algunos elementos en el conjunto, podemos realizar algunas operaciones:
System.out.println(treeSet.first()); // Prints 1
System.out.println(treeSet.last()); // Prints 12
System.out.println(treeSet.size()); // Prints 4, since there are 4 elemens in the set
System.out.println(treeSet.contains(12)); // Prints true
System.out.println(treeSet.contains(15)); // Prints false
También podemos iterar sobre los elementos del mapa usando un iterador o un bucle foreach. Tenga
en cuenta que las entradas se imprimen de acuerdo con su orden natural , no el orden de
inserción:
Java SE 7
Dado que TreeMap sy TreeSet s mantienen llaves / elementos de acuerdo con su orden natural . Por
TreeMap tanto, TreeMap claves TreeMap y los elementos TreeSet tienen que ser comparables entre
sí.
https://riptutorial.com/es/home 1114
TreeSet<Person2> set = ...
set.add(new Person(1,"first","last",Date.from(Instant.now())));
Para solucionarlo, supongamos que queremos ordenar instancias de Person función del orden de sus
private int id ( private int id ). Podríamos hacerlo de una de dos maneras:
@Override
public int compareTo(Person o) {
return Integer.compare(this.id, o.id); //Compare by id
}
}
Java SE 8
1. Es muy importante no modificar los campos utilizados para ordenar una vez que una instancia
se haya insertado en un TreeSet / TreeMap . En el ejemplo anterior, si cambiamos el id de
una persona que ya está insertada en la colección, podríamos encontrar un comportamiento
inesperado.
https://riptutorial.com/es/home 1115
sgn(x.compareTo(z)) == sgn(y.compareTo(z)) , para todas las z.
TreeMap y TreeSet no son colecciones seguras para subprocesos, por lo que se debe tener cuidado
para garantizar que se utilicen en programas de subprocesos múltiples.
Tanto TreeMap como TreeSet son seguros cuando se leen, incluso al mismo tiempo, por varios
subprocesos. Por lo tanto, si se crearon y rellenaron con un solo subproceso (por ejemplo, al
inicio del programa), y solo luego se leyeron, pero no se modificaron por varios subprocesos, no
hay razón para la sincronización o el bloqueo.
Sin embargo, si se lee y se modifica al mismo tiempo, o si se modifica al mismo tiempo por más
de un hilo, la colección puede generar una ConcurrentModificationException o comportarse de
manera inesperada. En estos casos, es imperativo sincronizar / bloquear el acceso a la colección
utilizando uno de los siguientes métodos:
1. Utilizando Collections.synchronizedSorted.. :
...
//Thread 1
synchronized (set) {
set.add(4);
}
...
//Thread 2
synchronized (set) {
set.remove(5);
}
...
//Thread 1
lock.writeLock().lock();
set.add(4);
lock.writeLock().unlock();
https://riptutorial.com/es/home 1116
...
//Thread 2
lock.readLock().lock();
set.contains(5);
lock.readLock().unlock();
https://riptutorial.com/es/home 1117
Capítulo 179: Usando la palabra clave estática
Sintaxis
Examples
Como la palabra clave static se usa para acceder a los campos y métodos sin una clase
instanciada, se puede usar para declarar constantes para usar en otras clases. Estas variables
se mantendrán constantes en cada instanciación de la clase. Por convención, las variables static
siempre son ALL_CAPS y usan guiones bajos en lugar de camel. ex:
static E STATIC_VARIABLE_NAME
Como las constantes no pueden cambiar, la static también se puede usar con el modificador final
:
Que se puede usar en cualquier clase como una constante, por ejemplo:
Static proporciona un método o almacenamiento de variables que no se asigna para cada instancia
de la clase. Más bien, la variable estática se comparte entre todos los miembros de la clase.
Incidentalmente, tratar de tratar la variable estática como un miembro de la instancia de clase
dará como resultado una advertencia:
https://riptutorial.com/es/home 1118
a.test = 1; // Warning
Apple.test = 1; // OK
Apple.test2 = 1; // Illegal: test2 is not static
a.test2 = 1; // OK
Los métodos que se declaran estáticos se comportan de la misma manera, pero con una restricción
adicional:
En general, es mejor declarar métodos genéricos que se aplican a diferentes instancias de una
clase (como los métodos de clonación) static , mientras que los métodos como equals() no son
estáticos. El main método de un programa Java es siempre estática, lo que significa que la
palabra clave this no se puede utilizar dentro de main() .
Las variables y los métodos estáticos no forman parte de una instancia. Siempre habrá una sola
copia de esa variable, sin importar cuántos objetos cree de una clase en particular.
Por ejemplo, es posible que desee tener una lista inmutable de constantes, sería una buena idea
mantenerla estática e inicializarla solo una vez dentro de un método estático. Esto le daría un
aumento significativo de rendimiento si está creando varias instancias de una clase en
particular de forma regular.
Además, también puedes tener un bloque estático en una clase. Puede usarlo para asignar un valor
predeterminado a una variable estática. Se ejecutan solo una vez cuando la clase se carga en la
memoria.
Todos los campos y métodos de una clase utilizados dentro de un método estático de esa clase
deben ser estáticos o locales. Si intenta utilizar variables o métodos de instancia (no
estáticos), su código no se compilará.
https://riptutorial.com/es/home 1119
public int getDaysLeftInWeek(){
return Week.daysOfTheWeek-dayOfTheWeek; // this is valid
}
https://riptutorial.com/es/home 1120
Capítulo 180: Usando otros lenguajes de scripting en Java
Introducción
Java en sí mismo es un lenguaje extremadamente poderoso, pero su poder se puede extender aún más
gracias a JSR223 (Solicitud de especificación de Java 223) que presenta un motor de script
Observaciones
La API de scripting de Java permite que los scripts externos interactúen con Java
La API de scripting puede permitir la interacción entre el script y java. Los lenguajes de
scripting deben tener una implementación de Script Engine en el classpath.
Por defecto, JavaScript (también conocido como ECMAScript) es proporcionado por nashorn de forma
predeterminada. Cada Script Engine tiene un contexto de script donde todas las variables,
funciones y métodos se almacenan en enlaces. En ocasiones, es posible que desee utilizar varios
contextos, ya que admiten la redirección de la salida a un Escritor con búfer y el error a otro.
Hay muchas otras bibliotecas de motor de script como Jython y JRuby. Mientras estén en la ruta
de clase, puede evaluar el código.
Podemos usar enlaces para exponer variables en el script. Necesitamos varios enlaces en algunos
casos, ya que la exposición de las variables al motor básicamente consiste en exponer las
variables solo a ese motor, a veces es necesario exponer ciertas variables como el entorno del
sistema y la ruta que es la misma para todos los motores del mismo tipo. En ese caso, requerimos
un enlace que es un alcance global. Exponer las variables que lo exponen a todos los motores de
script creados por el mismo EngineFactory
Examples
/*
* Note Nashorn is only available for Java-8 onwards
* You can use rhino from ScriptEngineManager.getEngineByName("js");
*/
ScriptEngine engine;
ScriptContext context;
public Bindings scope;
https://riptutorial.com/es/home 1121
// Get a buffered reader for input
BufferedReader br = new BufferedReader(new FileReader(file));
// Evaluate code, with input as bufferdReader
engine.eval(br);
} catch (FileNotFoundException ex) {
Logger.getLogger(JSEngine.class.getName()).log(Level.SEVERE, null, ex);
} catch (ScriptException ex) {
// Script Exception is basically when there is an error in script
Logger.getLogger(JSEngine.class.getName()).log(Level.SEVERE, null, ex);
}
}
// Apply the bindings to the context and set the engine's default context
public void startBatch(int SCP){
context.setBindings(scope, SCP);
engine.setContext(context);
}
Como se puede ver la variable expuesta x se ha impreso. Ahora probando con un archivo.
print(x);
function test(){
print("hello test.js:test");
https://riptutorial.com/es/home 1122
}
test();
Suponiendo que test.js está en el mismo directorio que su aplicación, debería tener una salida
similar a esta
hello world
hello test.js:test
https://riptutorial.com/es/home 1123
Capítulo 181: Usando ThreadPoolExecutor en aplicaciones MultiThreaded.
Introducción
Al crear una aplicación basada en datos y rendimiento, puede ser muy útil completar las tareas
que requieren mucho tiempo de manera asíncrona y tener varias tareas ejecutándose
simultáneamente. Este tema presentará el concepto de usar ThreadPoolExecutors para completar
múltiples tareas de sincronización simultánea.
Examples
Es posible que algunas aplicaciones deseen crear las llamadas tareas "Incendio y olvido" que
pueden activarse periódicamente y no es necesario devolver ningún tipo de valor devuelto al
finalizar la tarea asignada (por ejemplo, depuración de archivos temporales antiguos, registros
rotativos, guardado automático) estado).
En este ejemplo, crearemos dos clases: una que implementa la interfaz Runnable y otra que
contiene un método main ().
AsyncMaintenanceTaskCompleter.java
import lombok.extern.java.Log;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@Log
public class AsyncMaintenanceTaskCompleter implements Runnable {
private int taskNumber;
} catch (InterruptedException e) {
log.warning(e.getMessage());
}
}
}
AsyncExample1
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
https://riptutorial.com/es/home 1124
for(int i = 0; i < 10; i++){
executorService.execute(new AsyncMaintenanceTaskCompleter(i));
}
executorService.shutdown();
}
}
Observaciones de la nota: hay varias cosas que se deben tener en cuenta en la salida anterior,
Realización de tareas asíncronas donde se necesita un valor de retorno utilizando una instancia
de clase invocable
https://riptutorial.com/es/home 1125
A menudo es necesario ejecutar una tarea de larga duración y utilizar el resultado de esa tarea
una vez que se haya completado.
En este ejemplo, crearemos dos clases: una que implementa la interfaz <T> invocable (donde T es
el tipo que queremos devolver) y otra que contiene un método main ().
AsyncValueTypeTaskCompleter.java
import lombok.extern.java.Log;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@Log
public class AsyncValueTypeTaskCompleter implements Callable<Integer> {
private int taskNumber;
@Override
public Integer call() throws Exception {
int timeout = ThreadLocalRandom.current().nextInt(1, 20);
try {
log.info(String.format("Task %d is sleeping", taskNumber));
TimeUnit.SECONDS.sleep(timeout);
log.info(String.format("Task %d is done sleeping", taskNumber));
} catch (InterruptedException e) {
log.warning(e.getMessage());
}
return timeout;
}
}
AsyncExample2.java
import lombok.extern.java.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@Log
public class AsyncExample2 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++){
Future<Integer> submittedFuture = executorService.submit(new
AsyncValueTypeTaskCompleter(i));
futures.add(submittedFuture);
}
executorService.shutdown();
while(!futures.isEmpty()){
for(int j = 0; j < futures.size(); j++){
https://riptutorial.com/es/home 1126
Future<Integer> f = futures.get(j);
if(f.isDone()){
try {
int timeout = f.get();
log.info(String.format("A task just completed after sleeping for %d
seconds", timeout));
futures.remove(f);
} catch (InterruptedException | ExecutionException e) {
log.warning(e.getMessage());
}
}
}
}
}
}
https://riptutorial.com/es/home 1127
INFO: A task just completed after sleeping for 6 seconds
Dec 28, 2016 3:07:25 PM AsyncValueTypeTaskCompleter call
INFO: Task 1 is done sleeping
Dec 28, 2016 3:07:25 PM AsyncExample2 main
INFO: A task just completed after sleeping for 10 seconds
Dec 28, 2016 3:07:27 PM AsyncValueTypeTaskCompleter call
INFO: Task 6 is done sleeping
Dec 28, 2016 3:07:27 PM AsyncExample2 main
INFO: A task just completed after sleeping for 12 seconds
Dec 28, 2016 3:07:29 PM AsyncValueTypeTaskCompleter call
INFO: Task 7 is done sleeping
Dec 28, 2016 3:07:29 PM AsyncExample2 main
INFO: A task just completed after sleeping for 14 seconds
Dec 28, 2016 3:07:31 PM AsyncValueTypeTaskCompleter call
INFO: Task 4 is done sleeping
Dec 28, 2016 3:07:31 PM AsyncExample2 main
INFO: A task just completed after sleeping for 16 seconds
Observaciones de la Nota:
Si bien un buen diseño de software a menudo maximiza la reutilización del código, a veces puede
ser útil definir tareas asíncronas en línea en su código a través de expresiones Lambda para
maximizar la legibilidad del código.
En este ejemplo, crearemos una sola clase que contenga un método main (). Dentro de este método,
usaremos expresiones Lambda para crear y ejecutar instancias de Callable y Runnable <T>.
AsyncExample3.java
import lombok.extern.java.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
@Log
public class AsyncExample3 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<Integer>> futures = new ArrayList<>();
for(int i = 0; i < 5; i++){
final int index = i;
executorService.execute(() -> {
int timeout = getTimeout();
https://riptutorial.com/es/home 1128
log.info(String.format("Runnable %d has been submitted and will sleep for %d
seconds", index, timeout));
try {
TimeUnit.SECONDS.sleep(timeout);
} catch (InterruptedException e) {
log.warning(e.getMessage());
}
log.info(String.format("Runnable %d has finished sleeping", index));
});
Future<Integer> submittedFuture = executorService.submit(() -> {
int timeout = getTimeout();
log.info(String.format("Callable %d will begin sleeping", index));
try {
TimeUnit.SECONDS.sleep(timeout);
} catch (InterruptedException e) {
log.warning(e.getMessage());
}
log.info(String.format("Callable %d is done sleeping", index));
return timeout;
});
futures.add(submittedFuture);
}
executorService.shutdown();
while(!futures.isEmpty()){
for(int j = 0; j < futures.size(); j++){
Future<Integer> f = futures.get(j);
if(f.isDone()){
try {
int timeout = f.get();
log.info(String.format("A task just completed after sleeping for %d
seconds", timeout));
futures.remove(f);
} catch (InterruptedException | ExecutionException e) {
log.warning(e.getMessage());
}
}
}
}
}
Observaciones de la Nota:
1. Las expresiones Lambda tienen acceso a variables y métodos que están disponibles para el
ámbito en el que están definidas, pero todas las variables deben ser finales (o
efectivamente finales) para su uso dentro de una expresión lambda.
2. No tenemos que especificar si nuestra expresión Lambda es Callable o Runnable <T>
explícitamente, el tipo de retorno se deduce automáticamente por el tipo de retorno.
https://riptutorial.com/es/home 1129
Capítulo 182: Varargs (Argumento Variable)
Observaciones
Un argumento del método "varargs" permite a las personas que llaman de ese método especificar
múltiples argumentos del tipo designado, cada uno como un argumento separado. Se especifica en
la declaración del método mediante tres períodos ASCII ( ... ) después del tipo base.
El método en sí recibe esos argumentos como una única matriz, cuyo tipo de elemento es el tipo
del argumento varargs. La matriz se crea automáticamente (aunque las personas que llaman todavía
pueden pasar una matriz explícita en lugar de pasar múltiples valores como argumentos de métodos
separados).
Debe seguir las reglas anteriores, de lo contrario el programa dará un error de compilación.
Examples
Los tres períodos posteriores al tipo de parámetro final indican que el argumento final se puede
pasar como una matriz o como una secuencia de argumentos. Varargs solo se puede utilizar en la
posición del argumento final.
Utilizando varargs como parámetro para una definición de método, es posible pasar una matriz o
una secuencia de argumentos. Si se pasa una secuencia de argumentos, se convierten
automáticamente en una matriz.
Este ejemplo muestra una matriz y una secuencia de argumentos que se pasan al método
printVarArgArray() , y cómo se tratan de manera idéntica en el código dentro del método:
// this method will print the entire contents of the parameter passed in
void printVarArgArray(int... x) {
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + ",");
}
}
//Using an array:
int[] testArray = new int[]{10, 20};
obj.printVarArgArray(testArray);
https://riptutorial.com/es/home 1130
System.out.println(" ");
Salida:
10,20,
5,6,5,8,6,31
void method(String... a, int... b , int c){} //Compile time error (multiple varargs )
void method(int... a, String b){} //Compile time error (varargs must be the last argument
https://riptutorial.com/es/home 1131
Capítulo 183: Visibilidad (control de acceso a los miembros de una clase)
Sintaxis
Observaciones
Los modificadores de nivel de acceso determinan si otras clases pueden usar un campo en
particular o invocar un método en particular. Hay dos niveles de control de acceso:
Una clase puede ser declarada con el modificador public , en cuyo caso esa clase es visible para
todas las clases en cualquier lugar. Si una clase no tiene modificador (el valor predeterminado,
también conocido como paquete-privado ), es visible solo dentro de su propio paquete.
En el nivel de miembro, también puede usar el modificador public o ningún modificador ( paquete-
privado ) al igual que con las clases de nivel superior, y con el mismo significado. Para los
miembros, hay dos modificadores de acceso adicionales: private y protected . El modificador
private especifica que solo se puede acceder al miembro en su propia clase. El modificador
protected especifica que solo se puede acceder al miembro dentro de su propio paquete (como con
el paquete privado ) y, además, mediante una subclase de su clase en otro paquete.
La siguiente tabla muestra el acceso a los miembros permitido por cada modificador.
Niveles de acceso:
public Y Y Y Y
protected Y Y Y norte
Examples
Miembros de la interfaz
https://riptutorial.com/es/home 1132
public String TEXT = "Hello";
int ANSWER = 42;
public class X {
}
class Y {
}
}
Los miembros de la interfaz siempre tienen visibilidad pública, incluso si se omite public
palabra clave public . Entonces, tanto foo() , bar() , TEXT , ANSWER , X e Y tienen visibilidad
pública. Sin embargo, el acceso aún puede estar limitado por la interfaz que contiene, ya que
MyInterface tiene visibilidad pública, se puede acceder a sus miembros desde cualquier lugar,
pero si MyInterface hubiera tenido visibilidad del paquete, sus miembros solo serían accesibles
desde el mismo paquete.
Visibilidad pública
public Test(){
}
}
Ahora intentemos crear una instancia de la clase. En este ejemplo, podemos acceder al number
porque es public .
Visibilidad privada
private visibilidad private permite que una variable solo sea accesible por su clase. A menudo
se utilizan en conjunto con captadores y setters public .
class SomeClass {
private int variable;
https://riptutorial.com/es/home 1133
}
package javax.swing;
public abstract class JComponent extends Container … {
…
static boolean DEBUG_GRAPHICS_LOADED;
…
}
package javax.swing;
public class DebugGraphics extends Graphics {
…
static {
JComponent.DEBUG_GRAPHICS_LOADED = true;
}
…
}
Visibilidad Protegida
Causas de visibilidad protegida significa que este miembro es visible para su paquete, junto con
cualquiera de sus subclases.
Como ejemplo:
package com.stackexchange.docs;
public class MyClass{
protected int variable; //This is the variable that we are trying to access
public MyClass(){
variable = 2;
};
}
Ahora extenderemos esta clase e intentaremos acceder a uno de sus miembros protected .
https://riptutorial.com/es/home 1134
package some.other.pack;
import com.stackexchange.docs.MyClass;
public class SubClass extends MyClass{
public SubClass(){
super();
System.out.println(super.variable);
}
}
También podría acceder a un miembro protected sin extenderlo si accede desde el mismo paquete.
Tenga en cuenta que este modificador solo funciona en miembros de una clase, no en la clase en
sí.
Hubo una vez un modificador private protected (ambas palabras clave a la vez) que podría
aplicarse a métodos o variables para hacerlos accesibles desde una subclase fuera del paquete,
pero hacerlos privados a las clases en ese paquete. Sin embargo, esto fue eliminado en la
versión de Java 1.0 .
https://riptutorial.com/es/home 1135
Capítulo 184: XJC
Introducción
XJC es una herramienta de Java SE que compila un archivo de esquema XML en clases Java
completamente anotadas.
Sintaxis
• xjc [opciones] archivo de esquema / URL / dir / jar ... [-b bindinfo] ...
Parámetros
Parámetro Detalles
Observaciones
La herramienta XJC está disponible como parte del JDK. Permite crear un código java anotado con
anotaciones JAXB adecuadas para (des) ordenación.
Examples
El siguiente esquema xml (xsd) define una lista de usuarios con el name y la reputation
atributos.
<?xml version="1.0"?>
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ns="http://www.stackoverflow.com/users"
elementFormDefault="qualified"
targetNamespace="http://www.stackoverflow.com/users">
<xs:element name="users" type="ns:Users"/>
<xs:complexType name="Users">
<xs:sequence>
<xs:element type="ns:User" name="user" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="User">
<xs:attribute name="name" use="required" type="xs:string"/>
<xs:attribute name="reputation" use="required">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
</xs:restriction>
https://riptutorial.com/es/home 1136
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>
Usando xjc
Esto requiere que la ruta a la herramienta xjc (binarios JDK) esté en la variable de ruta del
sistema operativo.
xjc schema.xsd
Archivos de resultados
Habrá algunos comentarios adicionales, pero básicamente los archivos Java generados se ven así:
package com.stackoverflow.users;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Users", propOrder = {
"user"
})
public class Users {
package com.stackoverflow.users;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "User")
public class User {
https://riptutorial.com/es/home 1137
protected int reputation;
package com.stackoverflow.users;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;
@XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
package-info.java
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.stackoverflow.com/users",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.stackoverflow.users;
https://riptutorial.com/es/home 1138
Capítulo 185: XOM - Modelo de objetos XML
Examples
Para cargar los datos XML con XOM , tendrá que crear un Builder desde el cual puede construirlo
en un Document .
Para obtener el elemento raíz, el padre primario más alto en el archivo xml, necesita usar
getRootElement() en la instancia del Document .
Ahora, la clase Element tiene muchos métodos prácticos que hacen que la lectura de xml sea
realmente fácil. Algunos de los más útiles se enumeran a continuación:
• getChildElements(String name) : devuelve una instancia de Elements que actúa como una
matriz de elementos
• getFirstChildElement(String name) : devuelve el primer elemento secundario con esa
etiqueta.
• getValue() : devuelve el valor dentro del elemento.
• getAttributeValue(String name) : devuelve el valor de un atributo con el nombre
especificado.
Cuando llama a getChildElements() obtiene una instancia de Elements . A partir de esto, puede
recorrer y llamar al método get(int index) para recuperar todos los elementos que contiene.
Archivo XML:
https://riptutorial.com/es/home 1139
Código para leerlo e imprimirlo:
import java.io.File;
import java.io.IOException;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.ParsingException;
// get the name element and its children: first and last
Element nameElement = person.getFirstChildElement("name");
Element firstNameElement = nameElement.getFirstChildElement("first");
Element lastNameElement = nameElement.getFirstChildElement("last");
https://riptutorial.com/es/home 1140
// get the favorite color element
Element favColorElement = person.getFirstChildElement("fav_color");
try {
fName = firstNameElement.getValue();
lName = lastNameElement.getValue();
age = Integer.parseInt(ageElement.getValue());
ageUnit = ageElement.getAttributeValue("unit");
favColor = favColorElement.getValue();
Escribir en un archivo XML utilizando XOM es muy similar a leerlo, excepto que en este caso
estamos creando instancias en lugar de recuperarlas de la raíz.
Para hacer un nuevo elemento use el Element(String name) constructor Element(String name) .
Querrá crear un elemento raíz para poder agregarlo fácilmente a un Document .
La clase Element tiene algunos métodos prácticos para editar elementos. Se enumeran a
continuación:
https://riptutorial.com/es/home 1141
Una vez que haya agregado todos sus elementos a su elemento raíz, puede convertirlo en un
Document . Document tomará un Element como argumento en su constructor.
Puede usar un Serializer para escribir su XML en un archivo. Deberá crear un nuevo flujo de
salida para analizar en el constructor de Serializer .
Ejemplo
Código:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import nu.xom.Attribute;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.ParsingException;
import nu.xom.Serializer;
// make the name element and it's children: first and last
Element nameElement = new Element("name");
Element firstNameElement = new Element("first");
Element lastNameElement = new Element("last");
https://riptutorial.com/es/home 1142
nameElement.appendChild(lastNameElement);
public Person(String lName, String fName, String ageUnit, String favColor, int age){
this.lName = lName;
this.fName = fName;
this.age = age;
this.ageUnit = ageUnit;
this.favColor = favColor;
}
https://riptutorial.com/es/home 1143
Lea XOM - Modelo de objetos XML en línea: https://riptutorial.com/es/java/topic/5091/xom---
modelo-de-objetos-xml
https://riptutorial.com/es/home 1144
Creditos
S.
Capítulos Contributors
No
Jonathan, Makoto, rajah9, RamenChef, The Guy with The Hat, Uri
3 Afirmando
Agassi
Ajuste de rendimiento
5 Gene Marin, jatanp, Stephen C, Vogel612
de Java
Análisis XML
6 utilizando las API de GPI
JAXP
https://riptutorial.com/es/home 1145
8 Apache Commons Lang Jonathan Barbero
AppDynamics y TIBCO
BusinessWorks
11 Alexandre Grimaud
Instrumentation para
una fácil integración
https://riptutorial.com/es/home 1146
Kreschishin, Maxim Plevako, Maximillian Laumeister, MC Emperor,
Menasheh, Michael Piefel, michaelbahr, Miljen Mikic, Minhas
Kamal, Mitch Talmadge, Mohamed Fadhl, Muhammed Refaat, Muntasir
, Mureinik, Mzzzzzz, NageN, Nathaniel Ford, Nayuki, nicael,
Nigel Nop, niyasc, noɥʇʎԀʎzɐɹƆ, Nuri Tasdemir, Ocracoke,
OldMcDonald, Onur, orccrusher99, Ortomala Lokni, Panda, Paolo
Forgia, Paul Bellora, Paweł Albecki, PeerNet, Peter Gordon,
phatfingers, Pimgd, Piyush, ppeterka, Přemysl Šťastný, PSN,
Pujan Srivastava, QoP, Radiodef, Radouane ROUFID, Raidri,
Rajesh, Rakitić, Ram, RamenChef, Ravi Chandra, René Link, Reut
Sharabani, Richard Hamilton, Robert Columbia, rolfedh, rolve,
Roman Cherepanov, roottraveller, Ross, Ryan Hilbert, Sam
Hazleton, sandbo00, Saurabh, Sayakiss, sebkur, Sergii Bishyr,
sevenforce, shmosel, Shoe, Siguza, Simulant, Slayther, Smi,
solidcell, Spencer Wieczorek, Squidward, stackptr, stark,
Stephen C, Stephen Leppik, Sualeh Fatehi, sudo, Sumurai8,
Sunnyok, syb0rg, tbodt, tdelev, tharkay, Thomas, ThunderStruct,
Tol182, ʇolɐǝz ǝɥʇ qoq, tpunt, Travis J, Tunaki, Un3qual,
Unihedron, user6653173, uzaif, vasili111, VedX, Ven, Victor G.,
Vikas Gupta, vincentvanjoe, Vogel612, Wilson, Winter, X.lophix,
YCF_L, Yohanes Khosiawan , yuku, Yury Fedorov, zamonier, Φ
Xocę Пepeúpa ツ
Calendario y sus
22 Bob Rivers, cdm, kann, Makoto, mnoronha, ppeterka, Ram, VGR
subclases
Características de
23 compuhosny, RamenChef
Java SE 7
Características de
24 compuhosny, RamenChef, sun-solar-arrow
Java SE 8
Clase - Reflexión de
27 gobes, KIRAN KUMAR MATAM
Java
https://riptutorial.com/es/home 1147
A_Arnold, alain.janinm, arcy, Bob Rivers, Christian Wilkie,
explv, Jabir, Jean-Baptiste Yunès, John Smith, Matt Clark,
28 Clase de fecha Miles, NamshubWriter, Nicktar, Nishant123, Ph0bi4, ppeterka,
Ralf Kleberhoff, Ram, skia.heliou, Squidward, Stephen C, Vinod
Kumar Kashyap
Codificación de
37 Ilya
caracteres
https://riptutorial.com/es/home 1148
Colecciones
41 mnoronha, ppeterka, Viacheslav Vedenin
alternativas
Colecciones
42 GPI, Kenster, Powerlord, user2296600
concurrentes
Comandos de tiempo de
43 RamenChef
ejecución
Creando imágenes
52 alain.janinm, Dariusz, kajacx, Kenster, mnoronha
programáticamente
Desmontaje y
53 ipsi, mnoronha
Descompilación.
https://riptutorial.com/es/home 1149
garg10may, nishizawa23, Pseudonym Patel, RamenChef, Smit,
54 Despliegue de Java
Stephen C
Ediciones, versiones,
lanzamientos y
58 Gal Dreiman, screab, Stephen C
distribuciones de
Java
El Comando de Java -
61 4444, Ben, mnoronha, Stephen C, Vogel612
'java' y 'javaw'
63 Enchufes Ordiel
https://riptutorial.com/es/home 1150
Leppik, Steve Harris, tonirush, TuringTux, user3105453
Errores de Java -
17slim, Andrii Abramov, Daniel Nugent, dorukayhan, fabian,
67 Nulls y
François Cassin, Miles, Stephen C, Zircon
NullPointerException
Errores de Java -
Dorian, GPI, John Starich, Jorn Vernee, Michał Rybak, mnoronha,
68 Problemas de
ppeterka, Sharon Rozinsky, steffen, Stephen C, xTrollxDudex
rendimiento
Errores de Java - Uso Bhoomika, bruno, dimo414, Gal Dreiman, hd84335, SachinSarawgi,
70
de excepciones scorpp, Stephen C, Stephen Leppik, user3105453
Escogiendo
72 John DiFini
Colecciones
https://riptutorial.com/es/home 1151
Niroshan, JudgingNotJudging, Kevin Raoofi, Malt, Mark Green,
Matt, Matthew Trout, Matthias Braun, ncmathsadist, nobeh,
Ortomala Lokni, Paŭlo Ebermann, Paweł Albecki, Petter Friberg,
philnate, Pujan Srivastava, Radouane ROUFID, RamenChef, rolve,
Saclyr Barlonium, Sergii Bishyr, Skylar Sutton, solomonope,
Stephen C, Stephen Leppik, timbooo, Tunaki, Unihedron,
vincentvanjoe, Vlasec, Vogel612, webo80, William Ritson,
Wolfgang, Xaerxess, xploreraj, Yogi, Ze Rubeus
Fechas y hora Bilbo Baggins, bowmore, Michael Piefel, Miles, mnoronha, Simon,
81
(java.time. *) Squidward, Tarun Maganti, Vogel612, ΦXocę Пepeúpa ツ
FTP (Protocolo de
84 transferencia de Kelvin Kellner
archivos)
Gestión de memoria de Daniel M., engineercoding, fgb, John Nash, jwd630, mnoronha,
89
Java OverCoder, padippist, RamenChef, Squidward, Stephen C
https://riptutorial.com/es/home 1152
Vernee, Kai, Kevin DiTraglia, kiuby_88, Lahiru Ashan, Luan Nico
, maheshkumar, Mshnik, Muhammed Refaat, OldMcDonald, Oleg
Sklyar, Ortomala Lokni, PM 77-1, Prateek Agarwal, QoP, Radouane
ROUFID, RamenChef, Ravindra babu, Shog9, Simulant, SjB, Slava
Babin, Stephen C, Stephen Leppik, still_learning, Sudhir Singh,
Theo, ToTheMaximum, uhrm, Unihedron, Vasiliy Vlasov, Vucko
Implementaciones del
95 sistema de plugin Alexiy
Java
https://riptutorial.com/es/home 1153
BenBrahim, Unihedron, VGR, Vishal Biyani, Vogel612, vsminkov,
vvtx, Wilson, winseybash, xwoker, yuku, Yury Fedorov, Zachary
David Saunders, Zack Teater, Ze Rubeus, ΦXocę Пepeúpa ツ
Interfaces
100 Andreas
funcionales
Interfaz de
101 desilijic
herramientas JVM
Interfaz de salida de
102 Suketu Patel
cola
Interfaz nativa de Coffee Ninja, Fjoni Yzeiri, Jorn Vernee, RamenChef, Stephen C,
104
Java user1803551
Invocación de método
105 RamenChef, smichel, Stephen C, user1803551, Vasiliy Vlasov
remoto (RMI)
La clase
115 mnoronha, RamenChef, Stephen C
java.util.Objects
https://riptutorial.com/es/home 1154
117 Lectores y escritores JD9999, KIRAN KUMAR MATAM, Mureinik, Stephen C, VatsalSura
Máquina virtual de
129 Dushman, RamenChef, Rory McCrossan, Stephen Leppik
Java (JVM)
Método dinámico de
130 Jeet
envío
Métodos de la fábrica
131 Jacob G.
de recolección
https://riptutorial.com/es/home 1155
richersoon, Ruslan Bes, Stephen C, Stephen Leppik, Vasiliy
Vlasov
Modelo de memoria de
133 Shree, Stephen C, Suminda Sirinath S. Dharmasena
Java
Operaciones de punto Dariusz, hd84335, HTNW, Ilya, Mr. P, Petter Friberg, ravthiru,
144
flotante de Java Stephen C, Stephen Leppik, Vogel612
Procesamiento de
148 argumentos de línea Burkhard, Michael von Wenckstern, Stephen C
de comando
https://riptutorial.com/es/home 1156
nickguletskii, Olivier Durin, OlivierTheOlive, Panda,
parakmiakos, Paweł Albecki, ppeterka, RamenChef, Ravindra babu,
rd22, RudolphEst, snowe2010, Squidward, Stephen C, Sudhir Singh
, Tobias Friedinger, Unihedron, Vasiliy Vlasov, Vlad-HC,
Vogel612, wolfcastle, xTrollxDudex, YCF_L, Yury Fedorov, ZX9
Programación paralela
151 con el framework Fork Community, Joe C
/ Join.
Referencias de
157 Andrii Abramov, arcy, Vasiliy Vlasov
objetos
Registro
158 bn., Christophe Weis, Emil Sierżęga, P.J.Meisch, vallismortis
(java.util.logging)
Seguridad y
159 John Nash, shibli049
criptografía
Servicio de impresión
161 Danilo Guimaraes, Leonardo Pina
de Java
https://riptutorial.com/es/home 1157
4444, Daniel Nugent, Grexis, Stephen C, Suminda Sirinath S.
167 sun.misc.Unsafe
Dharmasena
Tipos de datos de Do Nhu Vy, giucal, Jorn Vernee, Lord Farquaad, Yohanes
173
referencia Khosiawan
Tokenizador de
176 M M
cuerdas
Usando otros
179 lenguajes de Nikhil R
scripting en Java
Usando
ThreadPoolExecutor en
180 Brendon Dugan
aplicaciones
MultiThreaded.
Varargs (Argumento Daniel Nugent, Dushman, Omar Ayala, Rafael Pacheco, RamenChef,
181
Variable) VGR, xsami
Visibilidad (control
Aasmund Eldhuset, Abhishek Balaji R, Catalina Island, Daniel M.
de acceso a los
182 , intboolstring, Jonathan, Mark Yisri, Mureinik, NageN,
miembros de una
ParkerHalo, Stephen C, Vogel612
clase)
XOM - Modelo de
184 Arthur, Makoto
objetos XML
https://riptutorial.com/es/home 1158