Java
Java is a high-level, object-oriented programming language developed by Sun Microsystems (now owned by Oracle) and released in 1995. It is known for its portability ("write once, run anywhere"), robustness, and widespread adoption across various sectors of the software industry.
Key Features
1. Object-Orientation
Java is a strongly object-oriented language, where almost everything is an object. This promotes:
- Encapsulation: Hiding implementation details
- Inheritance: Code reuse through class hierarchies
- Polymorphism: The ability of objects to take on different forms
- Abstraction: Representing complex concepts in a simplified way
2. Platform Independence
Java code is compiled into bytecode, which is executed by the Java Virtual Machine (JVM). This allows Java programs to run on any device that has a JVM, regardless of the underlying operating system.
3. Automatic Memory Management
Java uses a garbage collector that automatically manages memory allocation and deallocation, reducing the likelihood of memory leaks and null pointer errors.
4. Strong and Static Typing
Java is a strongly typed language, which means that a variable's type is checked at compile time, reducing runtime errors.
5. Multithreading
Java offers native support for concurrent programming through threads, allowing multiple tasks to be executed simultaneously.
Basic Syntax
Structure of a Java Program
// Package declaration
package com.example;
// Imports
import java.util.List;
import java.util.ArrayList;
// Class declaration
public class JavaExample {
// Instance variable
private String message;
// Constructor
public JavaExample(String message) {
this.message = message;
}
// Method
public void displayMessage() {
System.out.println(message);
}
// Main method (entry point)
public static void main(String[] args) {
JavaExample example = new JavaExample("Hello, world!");
example.displayMessage();
}
}
Data Types
Primitive Types
- byte: 8 bits, values from -128 to 127
- short: 16 bits, values from -32,768 to 32,767
- int: 32 bits, values from -2^31 to 2^31-1
- long: 64 bits, values from -2^63 to 2^63-1
- float: 32 bits, single-precision floating-point
- double: 64 bits, double-precision floating-point
- char: 16 bits, a single Unicode character
- boolean: true or false
Reference Types
- Classes: String, ArrayList, HashMap, etc.
- Interfaces: List, Map, Set, etc.
- Arrays: int[], String[], Object[], etc.
Control Structures
Conditionals
// If-else
if (condition) {
// code if true
} else if (anotherCondition) {
// code if the first condition is false and the second is true
} else {
// code if both conditions are false
}
// Switch
switch (variable) {
case value1:
// code for value1
break;
case value2:
// code for value2
break;
default:
// default code
}
Loops
// For
for (int i = 0; i < 10; i++) {
// code to be repeated
}
// While
while (condition) {
// code to be repeated while the condition is true
}
// Do-While
do {
// code to be executed at least once
} while (condition);
// For-each (enhanced for)
for (Type element : collection) {
// code to process each element
}
Object-Oriented Programming in Java
Classes and Objects
// Class definition
public class Person {
// Attributes (instance variables)
private String name;
private int age;
// Constructor
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Methods
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void introduce() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
// Creating and using objects
Person person1 = new Person("John", 30);
person1.introduce();
Inheritance
// Base class
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void makeSound() {
System.out.println("Generic animal sound");
}
}
// Derived class
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("Woof woof!");
}
public void wagTail() {
System.out.println(name + " is wagging its tail");
}
}
Interfaces
// Interface definition
public interface Flyer {
void fly();
double getMaxAltitude();
}
// Implementing the interface
public class Bird implements Flyer {
@Override
public void fly() {
System.out.println("The bird is flying");
}
@Override
public double getMaxAltitude() {
return 1000.0;
}
}
Polymorphism
// Using polymorphism
Animal animal1 = new Dog("Rex");
Animal animal2 = new Cat("Felix");
animal1.makeSound(); // Output: "Woof woof!"
animal2.makeSound(); // Output: "Meow!"
// Polymorphic list
List<Animal> animals = new ArrayList<>();
animals.add(new Dog("Rex"));
animals.add(new Cat("Felix"));
for (Animal animal : animals) {
animal.makeSound(); // Calls the appropriate method for each type
}
Advanced Features
Generics
// Generic class definition
public class Box<T> {
private T content;
public void add(T content) {
this.content = content;
}
public T get() {
return content;
}
}
// Using generics
Box<String> textBox = new Box<>();
textBox.add("Hello, world!");
String text = textBox.get();
Box<Integer> numberBox = new Box<>();
numberBox.add(42);
int number = numberBox.get();
Lambdas and Streams (Java 8+)
// Lambda expressions
List<String> names = Arrays.asList("Ana", "Carlos", "Bruno", "Diana");
// Sorting using lambda
names.sort((s1, s2) -> s1.compareTo(s2));
// Filtering using lambda
List<String> namesWithC = names.stream()
.filter(name -> name.startsWith("C"))
.collect(Collectors.toList());
// Transformation using lambda
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
// Reduction using lambda
int totalCharacters = names.stream()
.mapToInt(String::length)
.sum();
Optional (Java 8+)
// Using Optional to avoid NullPointerException
public Optional<User> findUserById(Long id) {
// Search in the database
User user = repository.findById(id);
return Optional.ofNullable(user);
}
// Consuming an Optional
Optional<User> result = findUserById(123L);
result.ifPresent(user -> System.out.println("User found: " + user.getName()));
// Default value if not found
User user = result.orElse(new User("Default User"));
// Throw exception if not found
User foundUser = result.orElseThrow(() -> new UserNotFoundException("User not found"));
Annotations
// Defining a custom annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String value() default "";
int counter() default 0;
}
// Using annotations
public class AnnotationExample {
@MyAnnotation(value = "test", counter = 5)
public void annotatedMethod() {
// Implementation
}
// Processing annotations at runtime
public static void main(String[] args) throws Exception {
Method method = AnnotationExample.class.getMethod("annotatedMethod");
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("Value: " + annotation.value());
System.out.println("Counter: " + annotation.counter());
}
}
}
Java Ecosystem
Build Tools
- Maven: Dependency management and build automation
- Gradle: Flexible build automation system
Popular Frameworks
- Spring: Framework for developing enterprise applications
- Hibernate: ORM (Object-Relational Mapping) framework
- Jakarta EE (formerly Java EE): Platform for developing enterprise applications
- Quarkus: Framework for Kubernetes-native Java applications
- Micronaut: Framework for microservices and serverless applications
Testing Tools
- JUnit: Framework for unit tests
- Mockito: Framework for creating mock objects in tests
- AssertJ: Library for fluent assertions
- Selenium: User interface test automation
Java in the Project
In the context of our feedback system project, Java is used to implement the following microservices:
- User Management: User management, authentication, and authorization
- Feedback Request: Creation and management of feedback requests
- Feedback Response: Processing of feedback responses
These microservices are implemented using Spring Boot, which simplifies the development of Java applications by providing automatic configurations and a convention-based programming model.
Implementation Example with Spring Boot
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
@HasType("ADMIN")
public Page<UserDTO> listUsers(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.findUsers(name, PageRequest.of(page, size));
}
@PostMapping
@HasType("ADMIN")
public ResponseEntity<UserDTO> createUser(@RequestBody @Valid UserDTO userDTO) {
UserDTO createdUser = userService.createUser(userDTO);
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}
@GetMapping("/{id}")
@HasType("ADMIN")
public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PutMapping("/{id}")
@HasType("ADMIN")
public ResponseEntity<UserDTO> updateUser(
@PathVariable Long id,
@RequestBody @Valid UserDTO userDTO) {
return ResponseEntity.ok(userService.updateUser(id, userDTO));
}
@DeleteMapping("/{id}")
@HasType("ADMIN")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
Conclusion
Java is a versatile and robust language that continues to be widely used in the development of enterprise applications, including microservices-based systems. Its strong typing, object-oriented nature, and mature ecosystem make it a solid choice for developing complex and mission-critical applications.
In the context of our project, Java provides the foundation for implementing the main microservices, ensuring the system's reliability, maintainability, and scalability.