0% found this document useful (0 votes)
65 views

Java 8 Release: Language Compiler Libraries Tools Runtime (JVM)

This document provides an overview of the new features introduced in Java 8. It discusses the major changes to the Java language, compiler, libraries, tools, and runtime. Some of the key additions covered include lambdas and functional interfaces, default and static interface methods, streams and date/time API improvements in the libraries, and JVM enhancements. The tutorial aims to demonstrate usage of the new Java 8 capabilities.
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
65 views

Java 8 Release: Language Compiler Libraries Tools Runtime (JVM)

This document provides an overview of the new features introduced in Java 8. It discusses the major changes to the Java language, compiler, libraries, tools, and runtime. Some of the key additions covered include lambdas and functional interfaces, default and static interface methods, streams and date/time API improvements in the libraries, and JVM enhancements. The tutorial aims to demonstrate usage of the new Java 8 capabilities.
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 25

Table Of Contents

1. Introduction
2. New Features in Java language
2.1. Lambdas and Functional Interfaces
2.2. Interface Default and Static Methods
2.3. Method References
2.4. Repeating annotations
2.5. Better Type Inference
2.6. Extended Annotations Support
3. New Features in Java compiler
3.1. Parameter names
4. New Features in Java libraries
4.1. Optional
4.2. Streams
4.3. Date/Time API (JSR 310)
4.4. Nashorn JavaScript engine
4.5. Base64
4.6. Parallel Arrays
4.7. Concurrency
5. New Java tools
5.1. Nashorn engine: jjs
5.2. Class dependency analyzer: jdeps
6. New Features in Java runtime (JVM)
7. Conclusions
8. Resources

1. Introduction
With no doubts, Java 8 release is the greatest thing in the Java world since Java 5 (released quite a while ago,
back in 2004). It brings tons of new features to the Java as a language, its compiler, libraries, tools and the JVM
(Java virtual machine) itself. In this tutorial we are going to take a look on all these changes and demonstrate the
different usage scenarios on real examples.

The tutorial consists of several parts where each one touches the specific side of the platform:

 language
 compiler
 libraries
 tools
 runtime (JVM)
2. New Features in Java language
Java 8 is by any means a major release. One might say it took so long to finalize in order to implement the
features every Java developer was looking for. In this section we are going to cover most of them.

(Java 8 es de ninguna manera una versión importante. Se podría decir que tomó mucho tiempo finalizar
para implementar las características que todo desarrollador de Java estaba buscando. En esta sección
vamos a cubrir la mayoría de ellos.)

2.1. Lambdas and Functional Interfaces


Lambdas (also known as closures) are the biggest and most awaited language change in the whole Java 8
release. They allow us to treat functionality as a method argument (passing functions around), or treat a code
as data: the concepts every functional developer is very familiar with. Many languages on JVM platform
(Groovy, Scala, …) have had lambdas since day one, but Java developers had no choice but hammer the
lambdas with boilerplate anonymous classes.

(Las lambdas (también conocidas como cierres) son el cambio de idioma más grande y esperado en toda la
versión de Java 8. Nos permiten tratar la funcionalidad como un argumento de método (pasando funciones),
o tratar un código como datos: los conceptos con los que cada desarrollador funcional está muy
familiarizado. Muchos idiomas en la plataforma JVM (Groovy, Scala, ...) han tenido lambdas desde el primer
día, pero los desarrolladores de Java no tuvieron más remedio que martillar los lambdas con clases
anónimas repetitivas.)

Lambdas design discussions have taken a lot of time and community efforts. But finally, the trade-offs have
been found, leading to new concise and compact language constructs. In its simplest form, a lambda could
be represented as a comma-separated list of parameters, the –> symbol and the body.

(Las discusiones de diseño de Lambdas han llevado mucho tiempo y esfuerzos de la comunidad. Pero
finalmente, se han encontrado las compensaciones, que conducen a nuevas construcciones de lenguaje
concisas y compactas. En su forma más simple, una lambda podría representarse como una lista de
parámetros separados por comas, el símbolo -> y el cuerpo.)

For example:

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

Please notice the type of argument e is being inferred by the compiler. Alternatively, you may explicitly
provide the type of the parameter, wrapping the definition in brackets. For example:

(Tenga en cuenta el tipo de argumento e está siendo inferido por el compilador. Alternativamente, puede
proporcionar explícitamente el tipo del parámetro, ajustando la definición entre paréntesis. Por ejemplo:)

Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );

In case lambda’s body is more complex, it may be wrapped into square brackets, as the usual function
definition in Java. For example:

(En caso de que el cuerpo lambda sea más complejo, puede estar entre corchetes, como la definición de
función habitual en Java. Por ejemplo:)
Arrays.asList( "a", "b", "d" ).forEach( e -> {
    System.out.print( e );
    System.out.print( e );
} );

Lambdas may reference the class members and local variables (implicitly making them effectively final if
they are not). For example, those two snippets are equivalent:

(Lambdas puede hacer referencia a los miembros de la clase y las variables locales (haciéndolos
implícitamente definitivos si no lo son). Por ejemplo, esos dos fragmentos son equivalentes:)

String separator = ",";


Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );

And:

final String separator = ",";


Arrays.asList( "a", "b", "d" ).forEach(
    ( String e ) -> System.out.print( e + separator ) );

Lambdas may return a value. The type of the return value will be inferred by compiler.

(Lambdas puede devolver un valor. El compilador deducirá el tipo del valor de retorno.)

The return statement is not required if the lambda body is just a one-liner. The two code snippets below are
equivalent:

(La declaración de devolución no es necesaria si el cuerpo lambda es solo una línea. Los dos fragmentos de
código a continuación son equivalentes:)

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );

And:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {


    int result = e1.compareTo( e2 );
    return result;
} );

Language designers put a lot of thought on how to make already existing functionality lambda-friendly. As a
result, the concept of functional interfaces has emerged. The function interface is an interface with just one
single method. As such, it may be implicitly converted to a lambda expression.

(Los diseñadores de idiomas pensaron mucho sobre cómo hacer que la funcionalidad ya existente sea
compatible con lambda. Como resultado, ha surgido el concepto de interfaces funcionales. La interfaz de
funciones es una interfaz con un solo método. Como tal, se puede convertir implícitamente en una expresión
lambda)

The java.lang.Runnable and java.util.concurrent.Callable are two great examples of functional interfaces.


In practice, the functional interfaces are fragile: if someone adds just one another method to the interface
definition, it will not be functional anymore and compilation process will fail. To overcome this fragility and
explicitly declare the intent of the interface as being functional, Java 8 adds special annotation
@FunctionalInterface (all existing interfaces in Java library have been annotated with @FunctionalInterface
as well). Let us take a look on this simple functional interface definition:

(Java.lang.Runnable y java.util.concurrent.Callable son dos excelentes ejemplos de interfaces


funcionales. En la práctica, las interfaces funcionales son frágiles: si alguien agrega otro método a la
definición de interfaz, ya no será funcional y el proceso de compilación fallará. Para superar esta fragilidad y
declarar explícitamente la intención de la interfaz como funcional, Java 8 agrega una anotación especial
@FunctionalInterface (todas las interfaces existentes en la biblioteca Java también se han anotado con
@FunctionalInterface). Echemos un vistazo a esta sencilla definición de interfaz funcional:)

@FunctionalInterface
public interface Functional {
    void method();
}

One thing to keep in mind: default and static methods do not break the functional interface contract and may
be declared:

@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();
        
    default void defaultMethod() {           
    }       
}

Lambdas are the largest selling point of Java 8. It has all the potential to attract more and more developers to
this great platform and provide state of the art support for functional programming concepts in pure Java. For
more details please refer to official documentation.

(Lambdas es el mayor punto de venta de Java 8. Tiene todo el potencial para atraer a más y más
desarrolladores a esta gran plataforma y proporcionar soporte de última generación para conceptos de
programación funcional en Java puro. Para más detalles, consulte la documentación oficial)

2.2. Interface’s Default and Static Methods


Java 8 extends interface declarations with two new concepts: default and static methods. Default
methods make interfaces somewhat similar to traits but serve a bit different goal. They allow adding new
methods to existing interfaces without breaking the binary compatibility with the code written for older
versions of those interfaces.

(Java 8 extiende las declaraciones de interfaz con dos conceptos nuevos: métodos predeterminados y
métodos estáticos. Los métodos predeterminados hacen que las interfaces sean algo similares a los rasgos
pero tienen un objetivo un poco diferente. Permiten agregar nuevos métodos a las interfaces existentes sin
romper la compatibilidad binaria con el código escrito para versiones anteriores de esas interfaces)

The difference between default methods and abstract methods is that abstract methods are required to be
implemented. But default methods are not. Instead, each interface must provide so called default
implementation and all the implementers will inherit it by default (with a possibility to override this default
implementation if needed). Let us take a look on example below.
(La diferencia entre los métodos predeterminados y los métodos abstractos es que los métodos abstractos
deben implementarse. Pero los métodos predeterminados no lo son. En cambio, cada interfaz debe
proporcionar la llamada implementación predeterminada y todos los implementadores la heredarán de
manera predeterminada (con la posibilidad de anular esta implementación predeterminada si es necesario).
Echemos un vistazo al ejemplo a continuación)

private interface Defaulable {


    // Interfaces now allow default methods, the implementer may or
    // may not implement (override) them.
    default String notRequired() {
        return "Default implementation";
    }       
}
        
private static class DefaultableImpl implements Defaulable {
}
    
private static class OverridableImpl implements Defaulable {
    @Override
    public String notRequired() {
        return "Overridden implementation";
    }
}

The interface Defaulable declares a default method notRequired() using keyword default as part of the


method definition. One of the classes, DefaultableImpl, implements this interface leaving the default method
implementation as-is. Another one, OverridableImpl , overrides the default implementation and provides its
own.

(La interfaz Defaulable declara un método predeterminado notRequired() utilizando la palabra clave
default como parte de la definición del método. Una de las clases, DefaultableImpl, implementa esta
interfaz dejando la implementación del método predeterminado tal cual. Otro, OverridableImpl, anula la
implementación predeterminada y proporciona la suya)

Another interesting feature delivered by Java 8 is that interfaces can declare (and provide implementation) of
static methods. Here is an example.

(Otra característica interesante entregada por Java 8 es que las interfaces pueden declarar (y proporcionar
implementación) de métodos estáticos. Aquí hay un ejemplo)

private interface DefaulableFactory {


    // Interfaces now allow static methods
    static Defaulable create( Supplier< Defaulable > supplier ) {
        return supplier.get();
    }
}

The small code snippet below glues together the default methods and static methods from the examples
above.

(El pequeño fragmento de código a continuación pega los métodos predeterminados y los métodos estáticos
de los ejemplos anteriores)

public static void main( String[] args ) {


    Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
    System.out.println( defaulable.notRequired() );
        
    defaulable = DefaulableFactory.create( OverridableImpl::new );
    System.out.println( defaulable.notRequired() );
}

The console output of this program looks like that:

(La salida de la consola de este programa se ve así:)

Default implementation
Overridden implementation

Default methods implementation on JVM is very efficient and is supported by the byte code instructions for
method invocation. Default methods allowed existing Java interfaces to evolve without breaking the
compilation process.

(La implementación de métodos predeterminados en JVM es muy eficiente y está respaldada por las
instrucciones del código de bytes para la invocación de métodos. Los métodos predeterminados permitieron
que las interfaces Java existentes evolucionaran sin interrumpir el proceso de compilación)

The good examples are the plethora of methods added


to java.util.Collection interface: stream(), parallelStream(), forEach(), removeIf(), …

Though being powerful, default methods should be used with a caution: before declaring method as default it
is better to think twice if it is really needed as it may cause ambiguity and compilation errors in complex
hierarchies. For more details please refer to official documentation.

(Aunque son potentes, los métodos predeterminados deben usarse con precaución: antes de declarar el
método predeterminado, es mejor pensarlo dos veces si es realmente necesario, ya que puede causar
ambigüedad y errores de compilación en jerarquías complejas. Para más detalles, consulte la
documentación oficial.)

2.3. Method References


Method references provide the useful syntax to refer directly to exiting methods or constructors of Java
classes or objects (instances). With conjunction of Lambdas expressions, method references make the
language constructs look compact and concise, leaving off boilerplate.
Below, considering the class Car as an example of different method definitions, let us distinguish four
supported types of method references.

(Las referencias de métodos proporcionan la sintaxis útil para referirse directamente a los métodos o
constructores existentes de clases u objetos Java (instancias). Con la conjunción de expresiones de
Lambdas, las referencias de métodos hacen que las construcciones del lenguaje se vean compactas y
concisas, dejando fuera de serie.
A continuación, considerando la clase Car como un ejemplo de diferentes definiciones de métodos,
distingamos cuatro tipos de referencias de métodos compatibles.)

public static class Car {


    public static Car create( final Supplier< Car > supplier ) {
        return supplier.get();
    }             
        
    public static void collide( final Car car ) {
        System.out.println( "Collided " + car.toString() );
    }
        
    public void follow( final Car another ) {
        System.out.println( "Following the " + another.toString() );
    }
        
    public void repair() {  
        System.out.println( "Repaired " + this.toString() );
    }
}

The first type of method references is constructor reference with the syntax Class::new or alternatively, for
generics, Class< T >::new. Please notice that the constructor has no arguments.

(El primer tipo de referencias de método es la referencia del constructor con la sintaxis Class::new o
alternativamente, para
genéricos, Class<T>::new. Tenga en cuenta que el constructor no tiene argumentos.)

final Car car = Car.create( Car::new );


final List< Car > cars = Arrays.asList( car );

The second type is reference to static method with the syntax Class::static_method. Please notice that the
method accepts exactly one parameter of type Car.

(El segundo tipo es una referencia al método estático con la sintaxis Class::static_method. Tenga en
cuenta que el método acepta exactamente un parámetro de tipo Car.)

cars.forEach( Car::collide );

The third type is reference to instance method of arbitrary object of specific type with the
syntax Class::method. Please notice, no arguments are accepted by the method.

(El tercer tipo es referencia al método de instancia de objeto arbitrario de tipo específico con la sintaxis
Class::method. Tenga en cuenta que el método no acepta argumentos.)

cars.forEach( Car::repair );

And the last, fourth type is reference to instance method of particular class instance the
syntax instance::method. Please notice that method accepts exactly one parameter of type Car.

(Y el último, cuarto tipo es una referencia al método de instancia de una instancia de clase particular, la
sintaxis instance::method. Tenga en cuenta que el método acepta exactamente un parámetro del tipo Car.)

final Car police = Car.create( Car::new );


cars.forEach( police::follow );

Running all those examples as a Java program produces following output on a console (the
actual Car instances might be different):
(Ejecutar todos esos ejemplos como un programa Java produce el siguiente resultado en una consola (las
instancias reales de Car pueden ser diferentes):)

Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d

For more examples and details on method references, please refer to official documentation.

2.4. Repeating annotations


Since Java 5 introduced the annotations support, this feature became very popular and is very widely used.
However, one of the limitations of annotation usage was the fact that the same annotation cannot be
declared more than once at the same location. Java 8 breaks this rule and introduced the repeating
annotations. It allows the same annotation to be repeated several times in place it is declared.

(Desde que Java 5 introdujo el soporte de anotaciones, esta característica se hizo muy popular y es muy
utilizada. Sin embargo, una de las limitaciones del uso de anotaciones fue el hecho de que la misma
anotación no se puede declarar más de una vez en la misma ubicación. Java 8 rompe esta regla e introdujo
las anotaciones repetitivas. Permite que la misma anotación se repita varias veces en el lugar en que se
declara.)

The repeating annotations should be themselves annotated with @Repeatable annotation. In fact, it is not a
language change but more a compiler trick as underneath the technique stays the same. Let us take a look
on quick example:

(Las anotaciones que se repiten deben anotarse con la anotación @Repeatable. De hecho, no es un cambio
de idioma, sino más bien un truco del compilador, ya que debajo de la técnica permanece igual. Echemos
un vistazo al ejemplo rápido:)

package com.javacodegeeks.java8.repeatable.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class RepeatingAnnotations {

    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    public @interface Filters {
        Filter[] value();
    }
    
    @Target( ElementType.TYPE )
    @Retention( RetentionPolicy.RUNTIME )
    @Repeatable( Filters.class )
    public @interface Filter {
        String value();
    };
    
    @Filter( "filter1" )
    @Filter( "filter2" )
    public interface Filterable {       
    }
    
    public static void main(String[] args) {
        for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
            System.out.println( filter.value() );
        }
    }
}

As we can see, there is an annotation class Filter annotated with @Repeatable( Filters.class ).


The Filters is just a holder of Filter annotations but Java compiler tries hard to hide its presence from the
developers. As such, the interface Filterable has Filter annotation defined twice (with no mentions
of Filters).

(Como podemos ver, hay una clase de anotación Filter anotada con @Repeatable(Filters.class). The
Filters es solo un titular de anotaciones de Filter, pero el compilador de Java se esfuerza por ocultar su
presencia a los desarrolladores. Como tal, la interfaz Filtrable tiene una anotación de Filtro definida dos
veces (sin menciones de Filtros).)

Also, the Reflection API provides new method getAnnotationsByType() to return repeating annotations of
some type (please notice that Filterable.class.getAnnotation( Filters.class ) will return the instance
of Filters injected by the compiler).

(Además, la API Reflection proporciona un nuevo método getAnnotationsByType () para devolver


anotaciones repetitivas de algún tipo (tenga en cuenta que Filterable.class.getAnnotation (Filters.class)
devolverá la instancia de Filtros inyectados por el compilador).)

The program output looks like that:

(La salida del programa se ve así:)

filter1
filter2

For more details please refer to official documentation.

2.5. Better Type Inference


Java 8 compiler has improved a lot on type inference. In many cases the explicit type parameters could be
inferred by compiler keeping the code cleaner. Let us take a look on one of the examples.

(El compilador de Java 8 ha mejorado mucho en la inferencia de tipos. En muchos casos, los parámetros de
tipo explícito pueden inferirse por el compilador manteniendo el código más limpio. Echemos un vistazo a
uno de los ejemplos.)

package com.javacodegeeks.java8.type.inference;
public class Value< T >
{
    public static< T > T defaultValue()
{
        return null;
    }
    
    public T getOrDefault( T value, T defaultValue )
{
        return ( value != null ) ? value : defaultValue;
    }
}

And here is the usage of Value<String> type.

package com.javacodegeeks.java8.type.inference;

public class TypeInference


{
    public static void main(String[] args)
{
        final Value< String > value = new Value<>();
        value.getOrDefault( "22", Value.defaultValue() );
    }
}

The type parameter of Value.defaultValue()is inferred and is not required to be provided. In Java 7, the
same example will not compile and should be rewritten to Value.< String >defaultValue().

(El parámetro tipo de Value.defaultValue() se infiere y no se requiere que se proporcione. En Java 7, el


mismo ejemplo no se compilará y debería reescribirse en Value.<String>defaultValue().)

2.6. Extended Annotations Support


Java 8 extends the context where annotation might be used. Now, it is possible to annotate mostly
everything: local variables, generic types, super-classes and implementing interfaces, even the method’s
exceptions declaration. Couple of examples are show below.

(Java 8 extiende el contexto donde se puede usar la anotación. Ahora, es posible anotar casi todo: variables
locales, tipos genéricos, superclases e interfaces de implementación, incluso la declaración de excepciones
del método. Un par de ejemplos se muestran a continuación.)

package com.javacodegeeks.java8.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;

public class Annotations


{
    @Retention( RetentionPolicy.RUNTIME )
    @Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )

    public @interface NonEmpty {       


    }
        
    public static class Holder< @NonEmpty T > extends @NonEmpty Object
{
        public void method() throws @NonEmpty Exception
{          
        }
    }
        
    @SuppressWarnings( "unused" )
    public static void main(String[] args)
{
        final Holder< String > holder = new @NonEmpty Holder< String >();      
        @NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();      
    }
}

The ElementType.TYPE_USE and ElementType.TYPE_PARAMETER are two new element types to


describe the applicable annotation context. The Annotation Processing API also underwent some minor
changes to recognize those new type annotations in the Java programming language.

(ElementType.TYPE_USE y ElementType.TYPE_PARAMETER son dos nuevos tipos de elementos para


describir el contexto de anotación aplicable. La API de procesamiento de anotaciones también sufrió
algunos cambios menores para reconocer esas nuevas anotaciones de tipo en el lenguaje de programación
Java.)

3. New Features in Java compiler


3.1. Parameter names
Literally for ages Java developers are inventing different ways to preserve method parameter names in Java
byte-code and make them available at runtime (for example, Paranamer library). And finally, Java 8 bakes
this demanding feature into the language (using Reflection API and Parameter.getName() method) and the
byte-code (using new javac compiler argument –parameters).

(Literalmente durante siglos, los desarrolladores de Java están inventando diferentes formas de preservar
los nombres de los parámetros de los métodos en código de bytes de Java y hacerlos disponibles en tiempo
de ejecución (por ejemplo, la biblioteca Paranamer). Y finalmente, Java 8 incorpora esta exigente
característica al lenguaje (usando la API de Reflection y el método Parameter.getName()) y el código de
bytes (usando el nuevo argumento del compilador javac –parameters).)

package com.javacodegeeks.java8.parameter.names;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class ParameterNames


{
    public static void main(String[] args) throws Exception
{
        Method method = ParameterNames.class.getMethod( "main", String[].class );
        for( final Parameter parameter: method.getParameters() ) {
            System.out.println( "Parameter: " + parameter.getName() );
        }
    }
}

If you compile this class without using –parameters argument and then run this program, you will see
something like that:

Parameter: arg0

With –parameters argument passed to the compiler the program output will be different (the actual name of
the parameter will be shown):

Parameter: args

For experienced Maven users the –parameters argument could be added to the compiler using configuration


section of the maven-compiler-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
        <compilerArgument>-parameters</compilerArgument>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

Latest Eclipse Kepler SR2 release with Java 8 (please check out this download instructions) support
provides useful configuration option to control this compiler setting as the picture below shows.

(El último lanzamiento de Eclipse Kepler SR2 con Java 8 (consulte estas instrucciones de descarga) es una
opción de configuración útil para controlar esta configuración del compilador como se muestra en la imagen
a continuación.)

Additionally, to verify the availability of parameter names, there is a handy


method isNamePresent() provided by Parameter class.

(Además, para verificar la disponibilidad de los nombres de los parámetros, existe un método útil
isNamePresent () proporcionado por la clase Parameter.)

4. New Features in Java libraries


Java 8 adds a lot of new classes and extends existing ones in order to provide better support of modern
concurrency, functional programming, date/time, and many more.

4.1. Optional
The famous NullPointerException is by far the most popular cause of Java application failures. Long time
ago the great Google Guava project introduced the Optionals as a solution to NullPointerExceptions,
discouraging codebase pollution with null checks and encouraging developers to write cleaner code.
Inspired by Google Guava, the Optional is now a part of Java 8 library.

(La famosa NullPointerException es, con mucho, la causa más popular de fallas en las aplicaciones Java.
Hace mucho tiempo, el gran proyecto Google Guava introdujo los Optionals como una solución a
NullPointerExceptions, desalentando la contaminación de la base de código con comprobaciones null y
alentando a los desarrolladores a escribir un código más limpio. Inspirado por Google Guava, el Optional
ahora es parte de la biblioteca Java 8.)

Optional is just a container: it can hold a value of some type T or just be null. It provides a lot of useful
methods so the explicit null checks have no excuse anymore. Please refer to official Java 8
documentation for more details.

(Optional es solo un contenedor: puede contener un value de algún tipo T o simplemente ser null.
Proporciona muchos métodos útiles para que las comprobaciones nulas explícitas ya no tengan excusa.
Consulte la documentación oficial de Java 8 para obtener más detalles.)

We are going to take a look on two small examples of Optional usages: with the nullable value and with the
value which does not allow nulls.

Optional< String > fullName = Optional.ofNullable( null );


System.out.println( "Full Name is set? " + fullName.isPresent() );       
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );

The isPresent() method returns true if this instance of Optional has non-null value and false otherwise.


The orElseGet() method provides the fallback mechanism in case Optional has null value by accepting the
function to generate the default one. The map() method transforms the current Optional’s value and returns
the new Optional instance. The orElse() method is similar to orElseGet() but instead of function it accepts
the default value. Here is the output of this program:

(El método isPresent() devuelve verdadero si esta instancia de Opcional tiene un valor no nulo y falso en
caso contrario. El método orElseGet() proporciona el mecanismo de reserva en caso de que Optional
tenga un valor nulo al aceptar la función para generar el valor predeterminado. El método map() transforma
el valor del Optional actual y devuelve la nueva instancia Optional. El método orElse() es similar a
orElseGet() pero, en lugar de funcionar, acepta el valor predeterminado. Aquí está la salida de este
programa:)

Full Name is set? false


Full Name: [none]
Hey Stranger!

Let us briefly look on another example:

Optional< String > firstName = Optional.of( "Tom" );


System.out.println( "First Name is set? " + firstName.isPresent() );       
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
System.out.println();

And here is the output:


First Name is set? true
First Name: Tom
Hey Tom!

For more details please refer to official documentation.

4.2. Streams
The newly added Stream API (java.util.stream) introduces real-world functional-style programming into the
Java. This is by far the most comprehensive addition to Java library intended to make Java developers
significantly more productive by allowing them to write effective, clean, and concise code.
Stream API makes collections processing greatly simplified (but it is not limited to Java collections only as we
will see later). Let us take start off with simple class called Task.

(La API Stream recientemente agregada (java.util.stream) introduce programación de estilo funcional del
mundo real en Java. Esta es, con mucho, la adición más completa a la biblioteca de Java destinada a hacer
que los desarrolladores de Java sean significativamente más productivos al permitirles escribir código
efectivo, limpio y conciso.
Stream API simplifica enormemente el procesamiento de colecciones (pero no se limita a las colecciones de
Java solo como veremos más adelante). Comencemos con una clase simple llamada Tarea.)

public class Streams 


{
    private enum Status {
        OPEN, CLOSED
    };
    
    private static final class Task
{
        private final Status status;
        private final Integer points;
        Task( final Status status, final Integer points ) {
            this.status = status;
            this.points = points;
        }
        
        public Integer getPoints() {
            return points;
        }
        
        public Status getStatus() {
            return status;
        }
        
        @Override
        public String toString() {
            return String.format( "[%s, %d]", status, points );
        }
    }
}

Task has some notion of points (or pseudo-complexity) and can be either OPEN or CLOSED. And then let us
introduce a small collection of tasks to play with.

(La tarea tiene una noción de puntos (o pseudo-complejidad) y puede estar ABIERTA o CERRADA. Y luego
presentamos una pequeña colección de tareas para jugar.)
final Collection< Task > tasks = Arrays.asList(
    new Task( Status.OPEN, 5 ),
    new Task( Status.OPEN, 13 ),
    new Task( Status.CLOSED, 8 )
);

The first question we are going to address is how many points in total all OPEN tasks have? Up to Java 8,
the usual solution for it would be some sort of foreach iteration. But in Java 8 the answers is streams: a
sequence of elements supporting sequential and parallel aggregate operations.

(La primera pregunta que vamos a abordar es cuántos puntos en total tienen todas las tareas OPEN. Hasta
Java 8, la solución habitual para ello sería algún tipo de iteración foreach. Pero en Java 8 las respuestas
son flujos: una secuencia de elementos que admiten operaciones agregadas secuenciales y paralelas.)

// Calculate total points of all active tasks using sum()


final long totalPointsOfOpenTasks = tasks
    .stream()
    .filter( task -> task.getStatus() == Status.OPEN )
    .mapToInt( Task::getPoints )
    .sum();
        
System.out.println( "Total points: " + totalPointsOfOpenTasks );

And the output on the console looks like that:

Total points: 18

There are a couple of things going on here. Firstly, the tasks collection is converted to its stream
representation. Then, the filter operation on stream filters out all CLOSED tasks. On next step,
the mapToInt operation converts the stream of Tasks to the stream of Integers
using Task::getPoints method of the each task instance. And lastly, all points are summed up
using sum method, producing the final result.

(Hay un par de cosas pasando aquí. En primer lugar, la colección de tareas se convierte en su
representación de flujo. Luego, la operación de filtro en flujo filtra todas las tareas CLOSE. En el siguiente
paso, la operación mapToInt convierte la secuencia de Tasks en la secuencia de enteros utilizando el
método Task::getPoints de cada instancia de tarea. Y, por último, todos los puntos se suman utilizando el
método de sum, produciendo el resultado final.)

Before moving on to the next examples, there are some notes to keep in mind about streams ( more details
here). Stream operations are divided into intermediate and terminal operations.

(Antes de pasar a los siguientes ejemplos, hay algunas notas a tener en cuenta sobre las transmisiones
(más detalles aquí). Las operaciones de flujo se dividen en operaciones intermedias y terminales.)

Intermediate operations return a new stream. They are always lazy, executing an intermediate operation
such as filter does not actually perform any filtering, but instead creates a new stream that, when traversed,
contains the elements of the initial stream that match the given predicate
Terminal operations, such as forEach or sum, may traverse the stream to produce a result or a side-effect.

(Las operaciones intermedias devuelven una nueva secuencia. Siempre son vagos, la ejecución de una
operación intermedia, como el filter, en realidad no realiza ningún filtrado, sino que crea una nueva
secuencia que, cuando se atraviesa, contiene los elementos de la secuencia inicial que coinciden con el
predicado dado.
Las operaciones de terminal, como forEach o sum, pueden atravesar la secuencia para producir un
resultado o un efecto secundario.)

After the terminal operation is performed, the stream pipeline is considered consumed, and can no longer be
used. In almost all cases, terminal operations are eager, completing their traversal of the underlying data
source.

(Después de que se realiza la operación del terminal, la tubería de flujo se considera consumida y ya no se
puede usar. En casi todos los casos, las operaciones de terminal están ansiosas, completando su recorrido
de la fuente de datos subyacente.)

Yet another value proposition of the streams is out-of-the box support of parallel processing. Let us take a
look on this example, which does sums the points of all the tasks.

(Otra propuesta de valor de los flujos es el soporte inmediato de procesamiento paralelo. Echemos un
vistazo a este ejemplo, que resume los puntos de todas las tareas.)

// Calculate total points of all tasks


final double totalPoints = tasks
   .stream()
   .parallel()
   .map( task -> task.getPoints() ) // or map( Task::getPoints )
   .reduce( 0, Integer::sum );
    
System.out.println( "Total points (all tasks): " + totalPoints );

It is very similar to the first example except the fact that we try to process all the tasks in  parallel and
calculate the final result using reduce method.

(Es muy similar al primer ejemplo, excepto el hecho de que intentamos procesar todas las tareas en paralelo
y calcular el resultado final utilizando el método reduce.)

Here is the console output:

Total points (all tasks): 26.0

Often, there is a need to performing a grouping of the collection elements by some criteria. Streams can help
with that as well as an example below demonstrates.

(A menudo, es necesario realizar una agrupación de los elementos de la colección según algunos criterios.
Las transmisiones pueden ayudar con eso, así como lo demuestra un ejemplo a continuación.)

// Group tasks by their status


final Map< Status, List< Task > > map = tasks
    .stream()
    .collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );

The console output of this example looks like that:


{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}

To finish up with the tasks example, let us calculate the overall percentage (or weight) of each task across
the whole collection, based on its points.

(Para finalizar con el ejemplo de tareas, calculemos el porcentaje general (o peso) de cada tarea en toda la
colección, en función de sus puntos.)

// Calculate the weight of each tasks (as percent of total points)


final Collection< String > result = tasks
    .stream()                                        // Stream< String >
    .mapToInt( Task::getPoints )                     // IntStream
    .asLongStream()                                  // LongStream
    .mapToDouble( points -> points / totalPoints )   // DoubleStream
    .boxed()                                         // Stream< Double >
    .mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream
    .mapToObj( percentage -> percentage + "%" )      // Stream< String>
    .collect( Collectors.toList() );                 // List< String >
        
System.out.println( result );

The console output is just here:

[19%, 50%, 30%]

And lastly, as we mentioned before, the Stream API is not only about Java collections. The typical I/O
operations like reading the text file line by line is a very good candidate to benefit from stream processing.

(Y, por último, como mencionamos anteriormente, la API Stream no solo se trata de colecciones Java. Las
operaciones de E / S típicas, como leer el archivo de texto línea por línea, son un muy buen candidato para
beneficiarse del procesamiento continuo.)

Here is a small example to confirm that.

final Path path = new File( filename ).toPath();


try( Stream< String > lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {
    lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
}

The onClose method called on the stream returns an equivalent stream with an additional close handler.
Close handlers are run when the close() method is called on the stream.

(El método onClose llamado en la secuencia devuelve una secuencia equivalente con un controlador de
cierre adicional. Los controladores de cierre se ejecutan cuando se llama al método close() en la
secuencia.)

Stream API together with Lambdas and Method References baked by Interface’s Default and Static


Methods is the Java 8 response to the modern paradigms in software development. For more details, please
refer to official documentation.
(Stream API junto con Lambdas y Referencias de métodos elaboradas por los métodos estáticos y
predeterminados de la interfaz es la respuesta de Java 8 a los paradigmas modernos en el desarrollo de
software. Para más detalles, consulte la documentación oficial.)

4.3. Date/Time API (JSR 310)


Java 8 makes one more take on date and time management by delivering New Date-Time API (JSR 310).
Date and time manipulation is being one of the worst pain points for Java developers. The
standard java.util.Date followed by java.util.Calendar hasn’t improved the situation at all (arguably, made it
even more confusing).

(Java 8 hace una nueva toma de gestión de fecha y hora al ofrecer la nueva API de fecha y hora (JSR 310).
La manipulación de fecha y hora es uno de los peores puntos débiles para los desarrolladores de Java. El
estándar java.util.Date seguido de java.util.Calendar no ha mejorado la situación (posiblemente, lo hizo
aún más confuso))

That is how Joda-Time was born: the great alternative date/time API for Java. The Java 8’s New Date-Time
API (JSR 310) was heavily influenced by Joda-Time and took the best of it. The new java.time package
contains all the classes for date, time, date/time, time zones, instants, duration, and clocks manipulation. In
the design of the API the immutability has been taken into account very seriously: no change allowed (the
tough lesson learnt from java.util.Calendar). If the modification is required, the new instance of respective
class will be returned.

(Así nació Joda-Time: la gran API alternativa de fecha / hora para Java. La nueva API de fecha y hora de
Java 8 (JSR 310) fue fuertemente influenciada por Joda-Time y tomó lo mejor de ella. El nuevo paquete
java.time contiene todas las clases de fecha, hora, fecha / hora, zonas horarias, instantes, duración y
manipulación de relojes. En el diseño de la API, la inmutabilidad se ha tenido muy en cuenta: no se permiten
cambios (la difícil lección aprendida de java.util.Calendar). Si se requiere la modificación, se devolverá la
nueva instancia de la clase respectiva)

Let us take a look on key classes and examples of their usages. The first class is Clock which provides
access to the current instant, date and time using a time-zone. Clock can be used instead
of System.currentTimeMillis() and TimeZone.getDefault().

(Echemos un vistazo a las clases clave y ejemplos de sus usos. La primera clase es Clock, que proporciona
acceso al instante actual, fecha y hora utilizando una zona horaria. El reloj se puede usar en lugar de
System.currentTimeMillis() y TimeZone.getDefault ())

// Get the system clock as UTC offset


final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );

The sample output on a console:

2014-04-12T15:19:29.282Z
1397315969360

Other new classes we are going to look at are LocaleDate and LocalTime. LocaleDate holds only the date
part without a time-zone in the ISO-8601 calendar system. Respectively, LocaleTime holds only the time
part without time-zone in the ISO-8601 calendar system. Both LocaleDate and LocaleTime could be
created from Clock.

(Otras nuevas clases que vamos a ver son LocaleDate y LocalTime. LocaleDate contiene solo la parte de
fecha sin una zona horaria en el sistema de calendario ISO-8601. Respectivamente, LocaleTime contiene
solo la parte de tiempo sin zona horaria en el sistema de calendario ISO-8601. Tanto LocaleDate como
LocaleTime podrían crearse desde Clock.)

// Get the local date and local time


final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );
        
System.out.println( date );
System.out.println( dateFromClock );
        
// Get the local date and local time
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );
        
System.out.println( time );
System.out.println( timeFromClock );

The sample output on a console:

2014-04-12
2014-04-12
11:25:54.568
15:25:54.568

The LocalDateTime combines together LocaleDate and LocalTime and holds a date with time but without a


time-zone in the ISO-8601 calendar system. A quick example is shown below.

(LocalDateTime combina LocalDate y LocalTime y mantiene una fecha con hora pero sin zona horaria en el
sistema de calendario ISO-8601. Un ejemplo rápido se muestra a continuación.)

// Get the local date/time


final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );
        
System.out.println( datetime );
System.out.println( datetimeFromClock );

The sample output on a console:

2014-04-12T11:37:52.309
2014-04-12T15:37:52.309

If case you need a date/time for particular timezone, the ZonedDateTime is here to help. It holds a date with
time and with a time-zone in the ISO-8601 calendar system. Here are a couple of examples for different
timezones.

(Si necesita una fecha / hora para una zona horaria en particular, ZonedDateTime está aquí para ayudarlo.
Tiene una fecha con hora y una zona horaria en el sistema de calendario ISO-8601. Aquí hay un par de
ejemplos para diferentes zonas horarias.)
// Get the zoned date/time
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now(clock);
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now(ZoneId.of( "America/Los_Angeles"));
        
System.out.println(zonedDatetime);
System.out.println(zonedDatetimeFromClock);
System.out.println(zonedDatetimeFromZone);

The sample output on a console:

2014-04-12T11:47:01.017-04:00[America/New_York]
2014-04-12T15:47:01.017Z
2014-04-12T08:47:01.017-07:00[America/Los_Angeles]

And finally, let us take a look on Duration class: an amount of time in terms of seconds and nanoseconds. It
makes very easy to compute the different between two dates. Let us take a look on that.

(Y finalmente, echemos un vistazo a la clase Duración: una cantidad de tiempo en términos de segundos y
nanosegundos. Hace muy fácil calcular la diferencia entre dos fechas. Echemos un vistazo a eso.)

// Get duration between two dates


final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );
final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );

The example above computes the duration (in days and hours) between two dates, 16 April 2014 and 16
April 2015. Here is the sample output on a console:

(El ejemplo anterior calcula la duración (en días y horas) entre dos fechas, 16 de abril de 2014 y 16 de abril
de 2015. Aquí está el resultado de muestra en una consola:)

Duration in days: 365


Duration in hours: 8783

The overall impression about Java 8’s new date/time API is very, very positive. Partially, because of the
battle-proved foundation it is built upon (Joda-Time), partially because this time it was finally tackled seriously
and developer voices have been heard. For more details please refer to official documentation.

(La impresión general sobre la nueva API de fecha / hora de Java 8 es muy, muy positiva. En parte, debido
a la base probada en batalla sobre la que se basa (Joda-Time), en parte porque esta vez finalmente se
abordó en serio y se han escuchado las voces de los desarrolladores. Para más detalles, consulte la
documentación oficial.)
4.4. Nashorn JavaScript engine
Java 8 comes with new Nashorn JavaScript engine which allows developing and running certain kinds of
JavaScript applications on JVM. Nashorn JavaScript engine is just another implementation of
javax.script.ScriptEngine and follows the same set of rules, permitting Java and JavaScript interoperability.

(Java 8 viene con el nuevo motor JavaScript de Nashorn que permite desarrollar y ejecutar ciertos tipos de
aplicaciones JavaScript en JVM. El motor JavaScript de Nashorn es solo otra implementación de
javax.script.ScriptEngine y sigue el mismo conjunto de reglas, lo que permite la interoperabilidad de Java y
JavaScript.)

Here is a small example.

ScriptEngineManager manager = new ScriptEngineManager();


ScriptEngine engine = manager.getEngineByName( "JavaScript" );
        
System.out.println( engine.getClass().getName() );
System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );

The sample output on a console:

jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2

We will get back to the Nashorn later in the section dedicated to new Java tools.

4.5. Base64
Finally, the support of Base64 encoding has made its way into Java standard library with Java 8 release. It is
very easy to use as following example shows off.

(Finalmente, el soporte de codificación Base64 ha llegado a la biblioteca estándar de Java con el


lanzamiento de Java 8. Es muy fácil de usar, como muestra el siguiente ejemplo.)

package com.javacodegeeks.java8.base64;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class Base64s {
    public static void main(String[] args) {
        final String text = "Base64 finally in Java 8!";
        
        final String encoded = Base64
            .getEncoder()
            .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
        System.out.println( encoded );
        
        final String decoded = new String(
            Base64.getDecoder().decode( encoded ),
            StandardCharsets.UTF_8 );
        System.out.println( decoded );
    }
}

The console output from program run shows both encoded and decoded text:

QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!

There are also URL-friendly encoder/decoder and MIME-friendly encoder/decoder provided by the Base64
class
(Base64.getUrlEncoder() / Base64.getUrlDecoder(), Base64.getMimeEncoder() / Base64.getMimeDeco
der()).

4.6. Parallel Arrays


Java 8 release adds a lot of new methods to allow parallel arrays processing. Arguably, the most important
one is parallelSort() which may significantly speedup the sorting on multicore machines. The following small
example demonstrates this new method family (parallelXxx) in action.

(La versión Java 8 agrega muchos métodos nuevos para permitir el procesamiento de matrices paralelas.
Podría decirse que el más importante es parallelSort () que puede acelerar significativamente la clasificación
en máquinas multinúcleo. El siguiente pequeño ejemplo muestra esta nueva familia de métodos
(parallelXxx) en acción.)

package com.javacodegeeks.java8.parallel.arrays;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;

public class ParallelArrays


{
    public static void main( String[] args ) {
        long[] arrayOfLong = new long [ 20000 ];       
        
        Arrays.parallelSetAll( arrayOfLong,
            index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
        Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
            i -> System.out.print( i + " " ) );
        System.out.println();
        
        Arrays.parallelSort( arrayOfLong );    
        Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
            i -> System.out.print( i + " " ) );
        System.out.println();
    }
}

This small code snippet uses method parallelSetAll() to fill up arrays with 20000 random values. After that,
the parallelSort() is being applied. The program outputs first 10 elements before and after sorting so to
ensure the array is really ordered. The sample program output may look like that (please notice that array
elements are randomly generated):

(Este pequeño fragmento de código utiliza el método parallelSetAll () para llenar matrices con 20000 valores
aleatorios. Después de eso, se aplica el parallelSort (). El programa genera los primeros 10 elementos antes
y después de la clasificación para garantizar que la matriz esté realmente ordenada. La salida del programa
de muestra puede verse así (tenga en cuenta que los elementos de la matriz se generan aleatoriamente):)

Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378
Sorted: 39 220 263 268 325 607 655 678 723 793

4.7. Concurrency
New methods have been added to the java.util.concurrent.ConcurrentHashMap class to support
aggregate operations based on the newly added streams facility and lambda expressions. Also, new
methods have been added to the java.util.concurrent.ForkJoinPool class to support a common pool
(check also our free course on Java concurrency).

(Se han agregado nuevos métodos a la clase java.util.concurrent.ConcurrentHashMap para admitir


operaciones agregadas basadas en el recurso de secuencias recién agregado y las expresiones lambda.
Además, se han agregado nuevos métodos a la clase java.util.concurrent.ForkJoinPool para admitir un
grupo común (consulte también nuestro curso gratuito sobre concurrencia de Java).)

The new java.util.concurrent.locks.StampedLock class has been added to provide a capability-based lock


with three modes for controlling read/write access (it might be considered as better alternative for
infamous java.util.concurrent.locks.ReadWriteLock).

(La nueva clase java.util.concurrent.locks.StampedLock se ha agregado para proporcionar un bloqueo


basado en la capacidad con tres modos para controlar el acceso de lectura / escritura (podría considerarse
como una mejor alternativa para el infame java.util.concurrent.locks.ReadWriteLock ))

New classes have been added to the java.util.concurrent.atomic package:

 DoubleAccumulator
 DoubleAdder
 LongAccumulator
 LongAdder

5. New Java tools


Java 8 comes with new set of command line tools. In this section we are going to look over most interesting
of them.
(Java 8 viene con un nuevo conjunto de herramientas de línea de comandos. En esta sección veremos los
más interesantes de ellos.)

5.1. Nashorn engine: jjs


jjs is a command line based standalone Nashorn engine. It accepts a list of JavaScript source code files as
arguments and runs them. For example, let us create a file func.js with following content:

(jjs es un motor de Nashorn independiente basado en la línea de comandos. Acepta una lista de archivos de
código fuente JavaScript como argumentos y los ejecuta. Por ejemplo, creemos un archivo func.js con el
siguiente contenido:)

function f() {
     return 1;
};
print( f() + 1 );

To execute this fie from command, let us pass it as an argument to jjs:

(Para ejecutar este archivo desde el comando, pasémoslo como un argumento a jjs:)

jjs func.js

The output on the console will be:

For more details please refer to official documentation.

5.2. Class dependency analyzer: jdeps


jdeps is a really great command line tool. It shows the package-level or class-level dependencies of Java
class files. It accepts .class file, a directory, or JAR file as an input. By default, jdeps outputs the
dependencies to the system output (console).

(jdeps es una gran herramienta de línea de comandos. Muestra las dependencias de nivel de paquete o
nivel de clase de los archivos de clase Java. Acepta un archivo .class, un directorio o un archivo JAR como
entrada. Por defecto, jdeps genera las dependencias a la salida del sistema (consola).)
As an example, let us take a look on dependencies report for the popular Spring Framework library. To make
example short, let us analyze only one JAR file: org.springframework.core-3.0.5.RELEASE.jar.

jdeps org.springframework.core-3.0.5.RELEASE.jar

This command outputs quite a lot so we are going to look on the part of it. The dependencies are grouped by
packages. If dependency is not available on a classpath, it is shown as not found.

(Este comando genera bastante, así que vamos a verlo por parte de él. Las dependencias se agrupan por
paquetes. Si la dependencia no está disponible en un classpath, se muestra como no encontrado.)

org.springframework.core-3.0.5.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar


   org.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.io                                           
      -> java.lang                                         
      -> java.lang.annotation                              
      -> java.lang.ref                                     
      -> java.lang.reflect                                 
      -> java.util                                         
      -> java.util.concurrent                              
      -> org.apache.commons.logging                         not found
      -> org.springframework.asm                            not found
      -> org.springframework.asm.commons                    not found
   org.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.lang                                         
      -> java.lang.annotation                              
      -> java.lang.reflect                                 
      -> java.util

For more details please refer to official documentation.

6. New Features in Java runtime (JVM)


The PermGen space is gone and has been replaced with Metaspace (JEP 122). The JVM options -
XX:PermSize and –XX:MaxPermSize have been replaced by -XX:MetaSpaceSize and -
XX:MaxMetaspaceSize respectively.

You might also like