Comandos para compilar código fuente y ejecutar programas Java

Escrito por picodotdev el , actualizado el .
java planeta-codigo programacion
Enlace permanente Comentarios

Java

Aún recuerdo cuando empecé a programar con el lenguaje Java sobre el año 1997 que la compilación y ejecución del código la hacía manualmente con los comandos javac java y jar en un máquina Intel Pentium a 120 Mhz con tan solo 8 MiB, más tarde 32 MiB, con Windows 95 y Java 1.2, momento en el que ni siquiera había un IDE ni las herramientas de construcción modernas como Maven y Gradle, había que descargar manualmente las librerías de dependencias en forma de archivos jar que se requiriesen. Luego con JBuilder como IDE este se encargaba de realizar la compilación y ejecución y no hacía falta utilizar estos comandos directamente.

Ahora con herramientas como Gradle además de compilar y ejecutar el programa incluso las dependencias son descargadas de forma automática de repositorios donde se ubican versionadas incluso de forma transitiva, descargando las dependencias de las dependencias.

Usar estos dos comandos directamente ya no es necesario pero como curiosidad comentaré como es su uso ya que siguen formando parte del entorno de desarrollo mínimo de Java para editar, compilar y ejecutar programas. El comando javac sirve para compilar los archivos de código fuente, dado que los paquetes del código fuente de Java se corresponden con directorios en el sistema de archivos el código fuente se ha de ubicar de forma consistente entre la estructura de directorio y el código fuente. Suponiendo que que hay las siguientes clases que hacen uso de la librería log4j2 y están ubicadas en el directorio src/main/java con la misma convención que utiliza Gradle el comando para realizar la compilación y copiar los recursos es el siguiente.

Estructura de directorios de un proyecto

Las herramientas de construcción Maven y Gradle siguen una convención en la estructura de directorios y archivos para los proyectos Java. Esta convención proporciona que la estructuta de directorios sea la misma en todos los proyectos Java y hace innecesaria una configuración específica para cada proyecto lo que hace a los proyectos más sencillos y fáciles de empezar. El código fuente se ubica en el directorio src/main/java y las clases compiladas se generan en el directorio target o build.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ tree
.
├── jar.sh
├── javac.sh
├── java-jar.sh
├── java.sh
├── libraries
│   ├── log4j-api-2.11.1.jar
│   └── log4j-core-2.11.1.jar
├── src
│   └── main
│       ├── java
│       │   └── io
│       │       └── github
│       │           └── picodotdev
│       │               └── blogbitix
│       │                   └── java8
│       │                       └── helloworld
│       │                           └── Main.java
│       ├── misc
│       │   └── MANIFEST.MF
│       └── resources
│           └── log4j2.xml
└── target
    └── classes

14 directories, 9 files
tree.sh

El programa Hola Mundo en Java

El siguiente es el programa mínimo de Java similar al Hola Mundo por el que se suele empezar a programar en cualquier lenguaje de programación, al ejecutarse simplemente emite un mensaje en la consola. El método main es un método estático, con un ámbito de visibilidad público, está dentro de una clase, recibe un array de strings con los argumentos con los que ha invocado su ejecución y retorna void. El método System.out.println() recibe un string y lo emite en la salida estándar del programa.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package io.github.picodotdev.blogbitix.java8.helloworld;

import java.util.Arrays;
import java.util.stream.Collectors;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class Main {

    private static Logger logger = LogManager.getLogger(Main.class);

    public static void main(String[] args) {
        logger.info("Arguments: {}", Arrays.asList(args).stream().collect(Collectors.joining(", ")));
    }
}
Main.java

Comando para compilar código fuente Java

Para compilar el código fuente Java se usa el compilador de Java, el compilador de Java es un programa que a partir del código fuente genera archivos de bytecode, el programa y comando del compilador de Java es javac.

Con el parámetro -classpath se indica la ubicación de las librerías o dependencias que requiriere el código fuente, con el parámetro -sourcepath el directorio raíz de los archivos de código fuente, el parámetro -source indica la versión del lenguaje del código fuente, -target la versión de la máquina virtual del bytecode que generará el compilador y con el parámetro -d el directorio donde generan los archivos class con el bytecode.

1
2
3
#!/usr/bin/env bash
javac -classpath "libraries/*" -sourcepath src/main/java -source 1.8 -target 1.8 -d target/classes src/main/java/io/github/picodotdev/blogbitix/java8/helloworld/Main.java
cp -r src/main/resources/* target/classes
javac.sh

Comando para ejecutar un programa Java

Una vez generados los archivos de bytecode a partir de la compilación del código fuente su ejecución se realiza con el comando java donde hay que indicar las ubicaciones del los archivos class y las librerías jar necesarias que necesiten, la clase principal con el punto de entrada del programa que contenga un método public static void main(String[] args) y los parámetros del programa que se reciben en el parámetro args del método main. En la ejecución del programa la máquina virtual de Java interpreta el bytecode que consiste en traducir a código máquina ejecutable por el procesador del sistema anfitrión.

1
2
#!/usr/bin/env bash
java -classpath "target/classes:libraries/*" io.github.picodotdev.blogbitix.java8.helloworld.Main "$@"
java.sh
1
2
$ ./java.sh arg1 arg2 arg3
16:13:45.386 [main] INFO  io.github.picodotdev.blogbitix.java8.helloworld.Main Arguments: arg1, arg2, arg3
java-run.sh

Comando para crear una librería Java ejecutable

La distribución de los archivos class se suele realizar usando librerías jar y estas se construyen usando el comando jar. El archivo de manifiesto es un descriptor en el que se puede indicar la clase de entrada sin tener que especificarla en el comando java haciendo los archivo jar similar a un ejecutable.

1
2
#!/usr/bin/env bash
jar cvfm holamundojava8.jar src/main/misc/MANIFEST.MF -C target/classes .
jar.sh
1
2
Main-Class: io.github.picodotdev.blogbitix.java8.helloworld.Main
Class-Path: libraries/log4j-api-2.11.1.jar libraries/log4j-core-2.11.1.jar
MANIFEST.MF

Y la ejecución de del programa contenido en el archivo jar.

1
2
#!/usr/bin/env bash
java -jar holamundojava8.jar "$@"
java-jar.sh
1
2
$ ./java-jar.sh arg1 arg2 arg3
16:20:33.848 [main] INFO  io.github.picodotdev.blogbitix.java8.helloworld.Main Arguments: arg1, arg2, arg3
java-jar-run.sh

Así es la compilación y ejecución de código Java en Java 8 y anteriores, con la introducción de la modularidad a partir de Java 9 esto cambia ya que el classpath queda obsoleto y es reemplazado por el equivalente con módulos module-path.

Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub.

Comparte el artículo: