
1. Introduction
1.1. What is Java?
Java is a general-purpose, object-oriented programming language designed to be highly portable. With the motto "write once, run anywhere," Java allows you to develop applications that run on multiple platforms without having to recompile the code. This feature has made Java a mainstay of software development in both the business world and academia and emerging technology.
1.2. Brief History and Impact on Computing
Since its introduction in 1995, Java has evolved to become one of the most popular programming languages. Originally developed by Sun Microsystems, its Java Virtual Machine (JVM)-based architecture has enabled complex applications to run with high performance and security on a variety of devices, from servers to mobile devices. Its impact on the internet, the creation of robust frameworks, and its continued evolution make it a benchmark for secure and scalable development in 2025.
2. Fundamental Java Concepts
2.1. The Origins of Java
Born in a context where the need for interoperability was high, Java was designed to offer security, portability, and a clear syntax derived from languages like C and C++. Its creation drove a shift in application development for the internet and embedded devices, marking the beginning of a new era in computing.
2.2. Relationship with C, C++ and C#
Although Java shares a similar syntax with C and C++, its foundation focuses on avoiding common problems in these languages, such as manual memory management and the complexity of multiple inheritance. On the other hand, C# was partly inspired by Java and has made competing design decisions; however, Java has distinguished itself with its "platform-neutral" philosophy and a very active developer community.
2.3. Java's Contribution to the Internet
Java revolutionized web application development with its ability to compile to bytecode, allowing the same code to run on any device with a JVM installed. This feature has been integral to the growth of server-side applications, web security, and mobile application development.
3. Evolution of the Java Language
3.1. History of the Java Language
From its first version in the 1990s to the arrival of Java 21, the language has undergone numerous iterations. Each update has introduced improvements in performance, syntax, and functionality, adapting to the needs of both business programming and new technological trends.
3.2. The Role of Java in Computing in 2025
Java remains essential in 2025, being used in critical applications in finance, telecommunications, embedded systems, and high-availability web services. Three pillars stand out:
3.2.1. Security
The JVM's robust architecture and strict resource access control in Java provide a secure environment against vulnerabilities. The inclusion of mechanisms such as sandboxing and code-level security policies make Java one of the most reliable languages for sensitive applications.
3.2.2. Portability
The generated bytecode allows Java code to run on any operating system that has the JVM installed, making migration between platforms almost transparent.
3.2.3. The Magic of Bytecode
The Java compilation process transforms source code into bytecode—a set of instructions interpreted by the JVM—enabling hardware independence and runtime optimization, ensuring competitive performance and high scalability.
4. Terminology and Paradigms in Java
4.1. Object-Oriented Programming (OOP)
The Object-Oriented Programming (OOP) It is a development paradigm that organizes code around objects, rather than independent functions and data. This approach allows for more intuitive modeling of systems, approximating the way humans think about the real world.
Java is a language that is designed from its foundations to work with OOP, making use of concepts such as encapsulation, inheritance, polymorphism, and abstraction, which allow the construction of modular, reusable and easy-to-maintain programs.
What is an object and what is a class?
In OOP, the objects represent instances of classes, which are structures that define the behavior and characteristics of a specific type of entity.
Simple example of a class and an object in Java:
// Definición de la clase Persona public class Persona { String nombre; int edad; // Constructor de la clase public Persona(String nombre, int edad) { this.nombre = nombre; this.edad = edad; } // Método para mostrar información public void mostrarInfo() { System.out.println("Nombre: " + nombre + ", Edad: " + edad); } } // Clase principal con el método main public class Main { public static void main(String[] args) { // Creación de un objeto de la clase Persona Persona persona1 = new Persona("Carlos", 30); persona1.mostrarInfo(); // Salida: Nombre: Carlos, Edad: 30 } }
In this example, the class Persona
defines two attributes (nombre
and edad
), a builder and a method (mostrarInfo()
). Then, in class Main
, a is created object (persona1
) and the method is called to display its information.
1. Encapsulation
The encapsulation It consists of hiding the internal details of an object and allowing access only through defined methods. This improves code security and modularity.
Example of encapsulation:
public class CuentaBancaria { private double saldo; // Atributo privado, no accesible directamente // Constructor public CuentaBancaria(double saldoInicial) { saldo = saldoInicial; } // Método para depositar dinero public void depositar(double cantidad) { saldo += cantidad; } // Método para consultar el saldo public double consultarSaldo() { return saldo; } } // Uso en una clase principal public class Banco { public static void main(String[] args) { CuentaBancaria cuenta = new CuentaBancaria(1000); cuenta.depositar(500); System.out.println("Saldo actual €: " + cuenta.consultarSaldo()); // Salida: 1500 } }
Here, the attribute saldo
is private (private
), which prevents direct access. Instead, public methods (depositar
and consultarSaldo
) to interact with it, which reinforces the security and integrity of the data.
2. Inheritance
The inheritance allows a class (subclase
) get features from another class (superclase
). This facilitates code reuse and class specialization.
Example of inheritance:
// Clase base public class Animal { public void hacerSonido() { System.out.println("El animal hace un sonido"); } } // Clase derivada (hereda de Animal) public class Perro extends Animal { @Override public void hacerSonido() { System.out.println("El perro ladra"); } } // Uso de herencia en el programa principal public class Zoologico { public static void main(String[] args) { Animal miAnimal = new Animal(); miAnimal.hacerSonido(); // Salida: El animal hace un sonido Perro miPerro = new Perro(); miPerro.hacerSonido(); // Salida: El perro ladra } }
The class Perro
inherits of Animal
, overwriting (@Override
) the method hacerSonido()
. Thanks to inheritance, Perro
you can use the behavior of Animal
and modify it according to your needs.
3. Polymorphism
He polymorphism allows the same method to be executed in different ways depending on the object that calls it. This is achieved through the overwrite (@Override
) in inherited classes.
Example of polymorphism:
// Clase base public class Vehiculo { public void acelerar() { System.out.println("El vehículo está acelerando."); } } // Clase derivada public class Coche extends Vehiculo { @Override public void acelerar() { System.out.println("El coche acelera rápidamente."); } } // Otra clase derivada public class Bicicleta extends Vehiculo { @Override public void acelerar() { System.out.println("La bicicleta avanza lentamente."); } } // Uso del polimorfismo en el programa public class Carretera { public static void main(String[] args) { Vehiculo v1 = new Coche(); Vehiculo v2 = new Bicicleta(); v1.acelerar(); // Salida: El coche acelera rápidamente. v2.acelerar(); // Salida: La bicicleta avanza lentamente. } }
Here, although v1
and v2
are declared as Vehiculo
, at runtime each object executes its own version of the method acelerar()
, showing the effect of polymorphism.
The Object-Oriented Programming (OOP) is fundamental in Java and allows you to create flexible, organized and reusable systems. By using encapsulation, inheritance and polymorphism, developers can design robust applications with less redundancy and greater code clarity.
In Java 21, the OOP paradigm continues to evolve with improvements such as Records, Sealed Classes and the implementation of more expressive patterns through Pattern Matching, which further enhances code security and maintainability.
4.2. Other Paradigms: Functional and Concurrent
Beyond OOP, Java has incorporated elements of functional programming into recent versions (e.g., lambdas and streams). Likewise, the evolution of the language in high-concurrency environments has led to the introduction of advanced tools such as Virtual Threads, which simplify and optimize the management of concurrent tasks.
5. Java 21: Features and What's New
5.1. New Features and Improvements
Java 21 brings a series of improvements that boost both performance and developer productivity. Key new features include:
- Virtual Threads and Structured Concurrency: Facilitating the creation of lightweight threads and the management of multiple concurrent tasks in a more secure and scalable way.
- Improved Records and Sealed Classes: These mechanisms allow you to create immutable classes and restrict inheritance to a controlled set of subclasses, improving the clarity and security of the design.
- Pattern Matching for Switch: Syntax refinements that allow you to work with different data types in a more expressive and less error-prone manner.
- Internal Optimizations and Better Memory Management: It provides performance improvements in high-demand scenarios, reducing resource management overhead.
5.2. Practical Examples in Java 21
Below are some code examples that illustrate the new features in Java SE 21 LTS:
Virtual Threads
public class VirtualThread { public static void main(String[] args) throws InterruptedException { // Creación y ejecución de un hilo virtual Thread virtualThread = Thread.ofVirtual().start(() -> { System.out.println("¡Hola desde un hilo virtual en Java 21!"); }); virtualThread.join(); } }
Sealed Classes and Records
// Definición de una interfaz sellada public sealed interface Shape permits Circle, Rectangle {} // Clase final que implementa Shape public final class Circle implements Shape { private final double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } } // Clase final para un rectángulo public final class Rectangle implements Shape { private final double width; private final double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } public double getWidth() { return width; } public double getHeight() { return height; } } // Uso de un record para representar un punto public record Point(int x, int y) {}
Pattern Matching on Switch
public String getShapeName(Shape shape) { return switch (shape) { case Circle c -> "Círculo"; case Rectangle r -> "Rectángulo"; // En versiones futuras se pueden agregar más casos default -> throw new IllegalStateException("Forma desconocida: " + shape); }; }
These examples illustrate how Java 21 combines traditional robustness with innovations that simplify safe, concurrent development.
6. Java Documentation and Resources
6.1. The Official Java Documentation
Oracle's official documentation and the OpenJDK community are primary sources for a thorough understanding of each language version. It's imperative to consult these resources to stay up-to-date on best practices and new APIs.
6.2. Bleeding Techniques and Code Conventions
Proper indentation and consistent use of naming conventions are essential for code readability and maintainability. It's recommended to follow official style guides (such as Oracle's) and use automatic formatting tools.
6.3. Table of Reserved Words of the Language and Other Elements
In Java, reserved words (or keywords) are lexemes that have a fixed, special meaning for the compiler. This means they cannot be used to name classes, methods, variables, or other identifiers, as they are intended to define the structure and behavior of the language. In addition to these "historical" words, new words have been incorporated in newer versions of Java, some of them as contextual reserved words, which provide improvements in code conciseness and readability (for example, for type inference or handling immutable and sealed classes).
Below is a complete table with the traditional reserved words and some of the new features introduced in later versions (from Java 9 onwards):
Table of Reserved and Contextual Words in Java
Reserved Word | Brief description | Notes / Version |
---|---|---|
abstract | Declare abstract classes or methods. | Prevents direct instantiation. |
assert | Allows assertions to be made for debugging. | Introduced in Java SE 1.4. |
boolean | Defines the primitive data type for logical values. | |
break | Interrupts the execution of a cycle or block switch . | |
byte | Declares variables of 8-bit integer data type. | |
case | Define each option in a statement switch . | |
catch | Catch exceptions thrown in a block try . | |
char | Primitive type to represent a character. | |
class | Declare a class. | |
const | Reserved but not currently in use. | Reserved for future use. |
continue | Interrupts the current iteration of a loop and moves on to the next. | |
default | Defines the default case in a switch or default methods in interfaces. | |
do | Start a cycle do-while . | |
double | Primitive type for double-precision decimal numbers. | |
else | Alternative in a statement if . | |
enum | Declares an enumerated type. | |
extends | Indicates that a class inherits from another or an interface extends another. | |
final | Declare constants or prevent inheritance/overwriting. | |
finally | Defines a block that is executed after try /catch , regardless of the outcome. | |
float | Primitive type for single-precision decimal numbers. | |
for | Start a cycle for . | |
goto | Reserved but not used in Java. | Reserved for future use. |
if | Start a condition. | |
implements | Indicates that a class implements one or more interfaces. | |
import | Allows you to include classes or packages in a source file. | |
instanceof | Checks whether an object is an instance of a given class or interface. | |
int | Primitive type for 32-bit integers. | |
interface | Declare an interface. | |
long | Primitive type for 64-bit integers. | |
native | Indicates that a method is implemented in native code (e.g., C/C++). | |
new | Creates a new instance of an object. | |
null | Literal representing the absence of a value. | |
package | Declares the package to which the class belongs. | |
private | Defines restricted access to the class scope. | |
protected | Defines access at the package and subclass level. | |
public | Indicates public access, without restrictions. | |
return | Returns a value from a method or terminates its execution. | |
short | Primitive type for 16-bit integers. | |
static | Declare members belonging to the class, not to specific instances. | |
strictfp | Restricts precision and behavior in float calculations. | |
super | Refers to the immediate parent class. | |
switch | Starts a multiple-select statement. | |
synchronized | Mark methods or blocks for secure access in concurrent environments. | |
this | Refers to the current instance. | |
throw | Explicitly throws an exception. | |
throws | Declare the exceptions that a method can propagate. | |
transient | Indicates that an attribute should not be serialized. | |
try | Start exception handling. | |
void | Specifies that a method does not return any value. | |
volatile | Marks a variable as susceptible to asynchronous changes, avoiding local caching. | |
while | Starts a cycle based on a condition. | |
var | Allows you to declare variables with type inference. | Contextual reserved word (since Java 10). |
record | Defines an immutable class in a compact way, ideal for storing data. | Introduced in Java 16. |
sealed | Restricts which classes can extend or implement a sealed class or interface. | Introduced in Java 17. |
permits | Explicitly list the classes that can extend a sealed class. | Introduced in Java 17. |
non-sealed | Allows a subclass of a sealed class to renounce the seal, opening inheritance. | Introduced in Java 17. |
yield | It is used in expressions of switch to return a value. | Consolidated in Java 14 (previously in preview since Java 13). |
module | Begins the declaration of a module in the Java module system. | Introduced in Java 9. |
open | Indicates that a module allows reflection on certain packages. | Introduced in Java 9. |
requires | Specifies the dependency of a module. | Introduced in Java 9. |
exports | Declares which packages in a module are available to other modules. | Introduced in Java 9. |
opens | Similar to exports , but allows runtime reflection. | Introduced in Java 9. |
uses | Declare the dependency on the implementation of a service. | Introduced in Java 9. |
provides | Indicates that a module offers an implementation of a specific service. | Introduced in Java 9. |
Additional Considerations
- Contextual Reserved Words: Some words, like
var
, are reserved in certain contexts. This means that their special meaning applies only in predefined situations (for example, in the declaration of a variable), but they can be used as identifier names in other contexts where their meaning is not activated. - Evolution of Language: With each new version, Java introduces improvements that include new words or reinterpret existing ones. For example, innovations associated with type inference, immutable records, and inheritance control (such as
sealed
,permits
andnon-sealed
) have expanded the repertoire of words in the language, facilitating more secure and expressive development. - Modules and the Module System: Words related to modularization (
module
,requires
,exports
, etc.) reflect the paradigm shift introduced in Java 9, which makes it easier to organize and maintain large-scale applications.
This comprehensive and detailed framework not only serves as a quick reference for developers, but also helps them understand how the language's core elements evolve to meet the demands of modern programming.
7. Libraries and Development Tools
7.1. Standard Class Libraries
Java has an extensive set of libraries that cover everything from data management (java.util) to input/output operations (java.io or java.nio), networking, security, and web development. These libraries allow developers to implement complex features without reinventing the wheel.
7.2. Frameworks and Tools (Spring, Hibernate, etc.)
For the development of business applications, frameworks such as Spring either Jakarta EE They offer robust and scalable structures. On the other hand, Hibernate It simplifies object-relational mapping (ORM), facilitating interaction with databases. These tools enhance the language by providing integrated solutions to common industry challenges.
7.3. Dependency Management with Maven and Gradle
The use of automation tools such as Maven and Gradle It's essential for Java project management. It allows you to efficiently define, manage, and resolve library dependencies, as well as automate the compilation, testing, and packaging of applications.
Tool | Main Use | File Example |
---|---|---|
Maven | Dependency management and project construction | pom.xml |
Gradle | Flexible alternative to Maven with customizable scripts | build.gradle |
8. Practical Development in Java
8.1. Solving Syntactic and Common Errors
Identifying and correcting syntax errors is an essential part of Java development. Using IDEs (such as IntelliJ IDEA or Eclipse) and compiling with javac
They help detect errors at compile time. Static analysis tools (such as SonarQube) are also useful for maintaining clean and robust code.
8.2. My First Java Application: Step-by-Step Example
The traditional “Hello World” is still an excellent starting point for learning basic syntax.
public class HolaMundo { public static void main(String[] args) { System.out.println("¡Hola, mundo!"); } }
Steps to compile and run:
- Save the code in a file called
HolaMundo.java
. - Compile with:
$ javac HolaMundo.java
Run with:
$ java HolaMundo
8.3. Compiling without IDE
It is often valuable to know how to compile from the command line. This is achieved by using the compiler javac
and subsequently executing the bytecode with java
This approach is useful for integration into scripts or server environments.
8.4. Advanced Examples: Concurrency, Streams, and Virtual Threads
Example with Streams:
import java.util.Arrays; public class Stream { public static void main(String[] args) { int[] nums = {1, 2, 3, 4, 5}; Arrays.stream(nums) .map(n -> n * n) .forEach(System.out::println); } }
Example with Virtual Threads:
public class VirtualThread { public static void main(String[] args) throws InterruptedException { Thread.startVirtualThread(() -> System.out.println("Ejecutando en un hilo virtual")); } }
These examples demonstrate everything from basic syntax to leveraging new features for concurrent tasks and data processing.
9. Tests and Good Practices
9.1. General Recommendations for Good Programming
- Readability: Use meaningful names for classes, methods, and variables.
- Modularity: Separate the logic into well-defined modules or classes.
- Comments and Documentation: Be sure to document your code and use documentation tools (such as Javadoc).
- Code Review: Conduct periodic reviews to identify improvements and potential errors.
9.2. Unit Testing, TDD, and Exception Handling
Test-driven development (TDD) and the use of testing frameworks such as JUnit They are recommended practices that guarantee the robustness of the code.
Example of unit test in JUnit 5:
import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; public class CalculatorTest { @Test public void testSuma() { int resultado = Calculator.sumar(2, 3); assertEquals(5, resultado); } }
Likewise, proper exception handling is essential to prevent unexpected application crashes. Use exception blocks. try-catch and logs errors using logging frameworks.
9.3. Debugging, Optimization, and Logging
- Depuration: Use the debuggers built into IDEs to track and correct errors at runtime.
- Optimization: Profile the application to identify bottlenecks and use tools like VisualVM for performance analysis.
- Logging: Implement libraries like Log4j or SLF4J to log events, which will facilitate monitoring and diagnostics in production environments.
10. Summary and Conclusions
Java 21 solidifies the language's trajectory through innovations that maintain its relevance in the modern software development landscape. From the introduction of Virtual Threads to improvements in syntax and data handling with Records and Sealed Classes, Java 21 demonstrates a continued commitment to efficiency, security, and portability. Furthermore, the integration of functional programming practices and robust support for object-oriented design ensure that this language remains a solid choice for projects of any scale.
I don't expect you to know or understand everything, but rather to see the examples, read, and in future chapters we will cover all the topics in this Java SE 21 course.
11. References and Useful Links
- Official Oracle Java Documentation: https://docs.oracle.com/en/java/
- OpenJDK: https://openjdk.java.net/
- Java Code Style Guide (Oracle): https://www.oracle.com/java/technologies/javase/codeconventions-contents.html
- Communities and Forums (StackOverflow, GitHub): Essential resources to resolve doubts and learn about Java development trends.