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

Java Notes

The document is a comprehensive guide to Java programming, covering its features, environment setup, syntax basics, object-oriented programming principles, exception handling, collections framework, and multithreading. It explains key concepts such as the Java Virtual Machine, data types, control statements, and the Java Collections Framework. Additionally, it includes practical examples to illustrate programming techniques and best practices.

Uploaded by

Vivek Sunori
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Java Notes

The document is a comprehensive guide to Java programming, covering its features, environment setup, syntax basics, object-oriented programming principles, exception handling, collections framework, and multithreading. It explains key concepts such as the Java Virtual Machine, data types, control statements, and the Java Collections Framework. Additionally, it includes practical examples to illustrate programming techniques and best practices.

Uploaded by

Vivek Sunori
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 40

Java Comprehensive Guide:

From Basics to Advanced


1. Introduction to Java

What is Java?
• Java is a high-level, object-oriented programming language developed by Sun Microsystems
in 1995.
• Created by James Gosling, it was designed for platform independence.
• Key features: simplicity, portability, and robustness.
Features of Java:
1. Object-Oriented: Focuses on objects and data rather than procedures.
2. Platform-Independent: Write once, run anywhere using JVM.
3. Secure: Provides features like bytecode and exception handling.
4. Robust: Strong memory management and error handling.
5. Multithreaded: Allows multiple tasks in parallel.

Java Virtual Machine (JVM):


• Converts Java bytecode into machine code for execution.
• Ensures platform independence.
Java Runtime Environment (JRE):
• Provides libraries and JVM for running Java applications.
Java Development Kit (JDK):
• Includes JRE, compiler, and tools for developing Java programs.

Why Use Java?


1. Platform Independence: Can run on any operating system with JVM.
2. Security: Built-in features to handle vulnerabilities.
3. Scalability: Suitable for large and small applications.
4. Community Support: Vast libraries and frameworks available.

Applications of Java:
1. Web Development: Servlets, JSP, Spring Framework.
2. Mobile Applications: Android development.
3. Desktop Applications: GUI-based applications using JavaFX or Swing.
4. Enterprise Applications: Backend systems, banking applications.
5. Embedded Systems: Devices like Blu-ray players, sensors.
2. Setting Up the Environment
Installing Java (JDK and IDE):
1. Install JDK:
• Download JDK from Oracle's website.
• Install it and configure the JAVA_HOME environment variable.
2. Install an IDE:
• Popular options: IntelliJ IDEA, Eclipse, or VS Code.
• Download and set up your chosen IDE.

Writing and Running Your First Java Program:


1. Open your IDE or a text editor.
2. Create a new file called HelloWorld.java.
3. Write the following code:

public class HelloWorld {


public static void main(String[] args) {
System.out.println("Hello, World!");
}
}

4. Save the file and compile it using:


javac HelloWorld.java

5. Run the program:


java HelloWorld

6. Output:
Hello, World!

Understanding the Main Method and Syntax Basics:


1. Main Method:
• Entry point for any Java program.
• Syntax:
public static void main(String[] args)

• public: Accessible to all.


• static: Can be run without creating an object.
• void: Does not return any value.
• String[] args: Command-line arguments.
2. Syntax Basics:
• Every statement ends with a semicolon (;).
• Class names should start with an uppercase letter.
• Curly braces {} define the beginning and end of blocks.
3. Basics of Java
Data Types and Variables:
• Primitive Data Types:
• byte, short, int, long (integer types).
• float, double (decimal types).
• char (character).
• boolean (true/false).
• Non-Primitive Data Types:
• Classes, arrays, strings.
• Variables:
• Store data values.
• Declaration:
int age = 25;

Keywords in Java:
• Reserved words with specific meanings.
• Examples: public, class, static, void, if, else, while, switch, return, etc.

Operators:
1. Arithmetic Operators: +, -, *, /, %.
2. Relational Operators: >, <, >=, <=, ==, !=.
3. Logical Operators: &&, ||, !.
4. Assignment Operators: =, +=, -=, *=, /=.
5. Unary Operators: ++, --.

Control Statements:
1. Conditional Statements:
• if: Executes code if condition is true.
if (x > 10) {
System.out.println("x is greater than 10");
}

• if-else: Executes one block if true, another if false.


if (x > 10) {
System.out.println("x is greater");
} else {
System.out.println("x is smaller");
}
• switch: Executes code based on matching case.
switch (day) {
case 1: System.out.println("Monday"); break;
case 2: System.out.println("Tuesday"); break;
default: System.out.println("Other day");
}

2. Loops:
• for loop: Iterates a fixed number of times.
for (int i = 0; i < 5; i++) {
System.out.println(i);
}

• while loop: Iterates while a condition is true.


int i = 0;
while (i < 5) {
System.out.println(i);
i++;
}

• do-while loop: Executes at least once, then checks condition.


int i = 0;
do {
System.out.println(i);
i++;
} while (i < 5);

Arrays:
• Single-Dimensional Array:
int[] numbers = {1, 2, 3, 4, 5};
System.out.println(numbers[0]); // Output: 1

• Multi-Dimensional Array:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6}
};
System.out.println(matrix[1][2]); // Output: 6
4. Object-Oriented Programming (OOPs)
Principles of OOPs:
1. Encapsulation:
• Wrapping data (variables) and methods in a single unit (class).
• Example:
class Person {
private String name; // Encapsulated variable
public void setName(String name) { this.name = name; }
public String getName() { return name; }
}

2. Inheritance:
• Reusing properties and methods of a parent class in a child class.
• Example:
class Animal { void eat() { System.out.println("Eating"); } }
class Dog extends Animal { void bark()
{ System.out.println("Barking"); } }

3. Polymorphism:
• Performing a single action in different ways.
• Example:
• Overloading (Compile-Time Polymorphism):
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
}

• Overriding (Run-Time Polymorphism):


class Animal { void sound() { System.out.println("Generic
Sound"); } }
class Dog extends Animal { void sound()
{ System.out.println("Bark"); } }

4. Abstraction:
• Hiding implementation details and showing only essential information.
• Example:
• Abstract class:
abstract class Shape {
abstract void draw();
}
class Circle extends Shape {
void draw() { System.out.println("Drawing Circle"); }
}

Classes and Objects:


• Class: Blueprint for creating objects.
• Object: Instance of a class.
class Car {
String model;
void drive() { System.out.println("Driving " + model); }
}
Car car = new Car();
car.model = "Tesla";
car.drive();

Constructors:
• Special methods to initialize objects.
• Default Constructor: No parameters.
class Car { Car() { System.out.println("Car Created"); } }

• Parameterized Constructor: Accepts arguments.


class Car {
String model;
Car(String model) { this.model = model; }
}

Access Modifiers:
• private: Accessible only within the class.
• protected: Accessible within package and subclasses.
• public: Accessible from anywhere.
• default: Accessible within the package.

Static vs. Non-Static:


• Static: Belongs to the class, not instances.
static int count = 0; // Shared by all objects

• Non-Static: Belongs to each object.

this and super keyword:


• this: Refers to the current class instance.
class Car {
String model;
Car(String model) { this.model = model; }
}

• super: Refers to the parent class.


class Dog extends Animal {
Dog() { super.eat(); }
}

Abstract Classes and Interfaces:


• Abstract Class: Cannot be instantiated, may have abstract and non-abstract methods.
abstract class Shape { abstract void draw(); }

• Interface: A contract where all methods are abstract by default.


interface Animal { void sound(); }
class Dog implements Animal { public void sound()
{ System.out.println("Bark"); } }
5. Exception Handling

Exception Handling
What is an Exception?
• An exception is an event that disrupts the normal flow of a program.
• It occurs during runtime and can be handled to prevent the program from crashing.
• Example: Division by zero, accessing a null object.

Types of Exceptions:
1. Checked Exceptions:
• Checked at compile-time.
• Must be handled using try-catch or declared using throws.
• Examples: IOException, SQLException.
• Example:
import java.io.*;
class Test {
void readFile() throws IOException {
FileReader file = new FileReader("file.txt");
}
}

2. Unchecked Exceptions:
• Occur at runtime and are not checked at compile-time.
• Examples: NullPointerException, ArithmeticException.
• Example:
int result = 10 / 0; // Throws ArithmeticException

Try, Catch, Finally:


1. try: Contains code that may throw exceptions.
2. catch: Handles the exception if it occurs.
3. finally: Executes code whether or not an exception is thrown.
Example:
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero: " + e.getMessage());
} finally {
System.out.println("Execution complete.");
}
Throw and Throws:
1. throw: Used to explicitly throw an exception.
Example:
throw new ArithmeticException("Invalid operation");

2. throws: Declares exceptions in the method signature that may be thrown.


Example:
void checkFile() throws IOException {
FileReader file = new FileReader("file.txt");
}

Custom Exceptions:
• User-defined exceptions created by extending the Exception class.
Example:
class InvalidAgeException extends Exception {
InvalidAgeException(String message) {
super(message);
}
}
class Test {
void checkAge(int age) throws InvalidAgeException {
if (age < 18) throw new InvalidAgeException("Age must be 18 or above.");
}
}
6. Java Collections Framework

The Java Collections Framework provides classes and interfaces to


store and manipulate groups of objects efficiently.

List:
• Definition: An ordered collection that allows duplicate elements.
• Implementations:
1. ArrayList:
• Dynamic array; fast for random access.
• Example:
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
System.out.println(list);

2. LinkedList:
• Doubly linked list; faster for insertions and deletions.
• Example:
LinkedList<String> list = new LinkedList<>();
list.add("Car");
list.add("Bike");

3. Vector:
• Synchronized version of ArrayList.
• Example:
Vector<String> vector = new Vector<>();
vector.add("Dog");
vector.add("Cat");

Set:
• Definition: A collection that does not allow duplicate elements.
• Implementations:
1. HashSet:
• No order guarantee; uses hashing.
• Example:
HashSet<String> set = new HashSet<>();
set.add("Java");
set.add("Python");
2. TreeSet:
• Maintains elements in sorted order.
• Example:
TreeSet<Integer> set = new TreeSet<>();
set.add(3);
set.add(1);

Map:
• Definition: A collection that stores key-value pairs.
• Implementations:
1. HashMap:
• Unordered; fast for lookups.
• Example:
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "Apple");
map.put(2, "Banana");

2. TreeMap:
• Maintains keys in sorted order.
• Example:
TreeMap<Integer, String> map = new TreeMap<>();
map.put(2, "Car");
map.put(1, "Bike");

3. LinkedHashMap:
• Maintains insertion order.
• Example:
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("A", 100);
map.put("B", 200);

Queue:
• Definition: Follows FIFO (First-In-First-Out) principle.
• Implementations:
1. PriorityQueue:
• Elements are processed based on priority.
• Example:
PriorityQueue<Integer> queue = new PriorityQueue<>();
queue.add(5);
queue.add(1);
2. LinkedList (Queue):
• Can be used as a queue.
• Example:
Queue<String> queue = new LinkedList<>();
queue.add("Task1");
queue.add("Task2");

Stack:
• Definition: Follows LIFO (Last-In-First-Out) principle.
• Example:
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(2);
System.out.println(stack.pop()); // Output: 2

Iterators:
• Definition: Used to traverse collections.
• Example:
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}

Comparable vs Comparator:
1. Comparable:
• Used to define natural ordering of objects.
• Implemented using compareTo() method.
• Example:
class Student implements Comparable<Student> {
int roll;
Student(int roll) { this.roll = roll; }
public int compareTo(Student s) { return this.roll - s.roll; }
}

2. Comparator:
• Used for custom ordering.
• Implemented using compare() method.
• Example:
class StudentComparator implements Comparator<Student> {
public int compare(Student s1, Student s2) { return s1.roll -
s2.roll; }
}
7. Multithreading and Concurrency

• Multithreading is a technique that allows multiple threads to run concurrently within a


program.
• A thread is the smallest unit of a CPU's execution.
• Multithreading improves the performance of applications by utilizing CPU resources
efficiently, especially on multi-core processors.

Creating Threads:
1. Extending Thread Class:
• The Thread class can be extended, and the run() method can be overridden to
define the task.
• Example:
class MyThread extends Thread {
public void run() {
System.out.println("Thread running");
}
}
public class Main {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start(); // starts the thread
}
}

2. Implementing Runnable Interface:


• Runnable is an interface with a single method run(). It allows more flexibility
than extending Thread because the class can extend another class as well.
• Example:
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread running");
}
}
public class Main {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();
}
}

Thread States:
• A thread can be in one of the following states:
1. New: Thread is created but not yet started.
2. Runnable: Thread is ready to run and is either running or waiting for CPU time.
3. Blocked: Thread is waiting for a resource or lock.
4. Waiting: Thread is waiting indefinitely for another thread to perform a particular
action.
5. Timed Waiting: Thread is waiting for a specific amount of time.
6. Terminated: Thread has finished execution.

Synchronization:
• Synchronization ensures that only one thread can access a resource at a time to prevent data
inconsistency.
• It is achieved using the synchronized keyword.

• Example:
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}

• Synchronized Block:
• Used to synchronize only a specific block of code rather than the whole method.
Example:
public void increment() {
synchronized(this) {
count++;
}
}

Inter-thread Communication:
• Java provides methods like wait(), notify(), and notifyAll() to allow threads to
communicate with each other.
• wait(): Causes the current thread to release the lock and wait until another thread
notifies it.
• notify(): Wakes up one thread that is waiting on the object's monitor.
• notifyAll(): Wakes up all the threads that are waiting on the object's monitor.
Example:
class SharedResource {
synchronized void produce() throws InterruptedException {
while (condition) {
wait(); // Wait until notified
}
}
synchronized void consume() {
notify(); // Notify the waiting thread
}
}

Executors and Thread Pool:


• Executor Framework provides a higher-level replacement for managing threads. It
simplifies the task of managing multiple threads by using Thread Pools.
• Thread Pool: A collection of worker threads that are reused to execute tasks, improving
performance and resource management.
• Example:
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {
System.out.println("Task 1");
});
executor.submit(() -> {
System.out.println("Task 2");
});
executor.shutdown();

• Types of Executors:
1. newFixedThreadPool(n): Creates a pool of fixed-size threads.
2. newCachedThreadPool(): Creates a thread pool that creates new threads as needed
but reuses idle threads.
3. newSingleThreadExecutor(): Creates a single-threaded pool to execute tasks
sequentially.
8. Java Input/Output (I/O)

Byte Streams and Character Streams:


• Byte Streams:
• Deal with raw binary data (like images, audio, etc.).
• They read and write data in the form of bytes (8-bit data).
• Classes: FileInputStream, FileOutputStream.
• Example:
FileInputStream fis = new FileInputStream("file.txt");
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
fis.close();

• Character Streams:
• Deal with character data (text data).
• They read and write data in the form of characters (16-bit data).
• Classes: FileReader, FileWriter.
• Example:
FileReader fr = new FileReader("file.txt");
int data;
while ((data = fr.read()) != -1) {
System.out.print((char) data);
}
fr.close();

Reading and Writing to Files:


1. Reading from a File:
• FileReader: Reads the file character by character.
• Example:
FileReader reader = new FileReader("file.txt");
int data;
while ((data = reader.read()) != -1) {
System.out.print((char) data);
}
reader.close();

2. Writing to a File:
• FileWriter: Writes characters to a file.
• Example:
FileWriter writer = new FileWriter("file.txt");
writer.write("Hello, Java!");
writer.close();
3. BufferedReader and BufferedWriter:
• Used for efficient reading and writing.
• BufferedReader: Reads data in chunks for better performance.
• BufferedWriter: Writes data in chunks.
• Example:
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();

Serialization and Deserialization:


• Serialization:
• The process of converting an object into a byte stream so that it can be saved to a file
or transferred over a network.
• Serializable Interface must be implemented for the class whose objects are to be
serialized.
• Example:
import java.io.*;
class Person implements Serializable {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// Serialization
Person p = new Person("John", 25);
FileOutputStream fos = new FileOutputStream("person.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
oos.close();

• Deserialization:
• The process of converting a byte stream back into a copy of the original object.
• Example:
// Deserialization
FileInputStream fis = new FileInputStream("person.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Person p1 = (Person) ois.readObject();
ois.close();

File Handling APIs:


1. File Class:
• Provides methods for checking file properties (exists, readable, writable, etc.).
• Example:
File file = new File("file.txt");
if (file.exists()) {
System.out.println("File exists");
}

2. FileReader and FileWriter:


• FileReader: Reads files character by character.
• FileWriter: Writes characters to files.
• Example:
FileWriter writer = new FileWriter("output.txt");
writer.write("Hello, World!");
writer.close();

3. BufferedReader and BufferedWriter:


• For efficient reading and writing.
• Example:
BufferedWriter writer = new BufferedWriter(new
FileWriter("output.txt"));
writer.write("Efficient writing");
writer.close();

4. FileInputStream and FileOutputStream:


• FileInputStream: Reads bytes from a file.
• FileOutputStream: Writes bytes to a file.
• Example:
FileInputStream fis = new FileInputStream("file.txt");
int data;
while ((data = fis.read()) != -1) {
System.out.print((char) data);
}
fis.close();
9. Advanced Java Concepts

Generics:
• Generics enable types (classes and methods) to operate on objects of various types while
providing compile-time type safety.
• Example:
class Box<T> {
private T value;
public T getValue() { return value; }
public void setValue(T value) { this.value = value; }
}
// Using Generics
Box<Integer> intBox = new Box<>();
intBox.setValue(10);

• Wildcard:
• ? extends T: Represents an unknown type that is a subtype of T.
• ? super T: Represents an unknown type that is a supertype of T.

Annotations:
• Annotations provide metadata about the program but have no direct effect on its operation.
• Example:
@Override
public String toString() {
return "Example";
}

@Deprecated
public void oldMethod() {
// Method is no longer in use
}

• Common Annotations:
• @Override: Indicates a method overrides a method in the superclass.
• @Deprecated: Marks methods that are outdated and should no longer be used.
• @SuppressWarnings: Tells the compiler to suppress certain warnings.

Lambda Expressions:
• Lambda expressions provide a clear and concise way to represent one method interface
using an expression.
• Syntax: (parameters) -> expression

• Example:
// Using Lambda Expression for Runnable
Runnable r = () -> System.out.println("Running in a thread");
new Thread(r).start();

• Lambda expressions are used extensively in the Streams API and functional interfaces.

Streams API:
• Streams represent sequences of elements that can be processed in parallel or sequentially.
• Streams can be used to perform operations like filtering, mapping, and reducing.
• Types of Streams:
1. Stream: A sequence of elements that can be processed.
2. IntStream, LongStream, DoubleStream: Specialized streams for primitive types.
• Operations in Streams:
1. Intermediate Operations: Transform a stream into another stream (e.g.,
filter(), map()).
2. Terminal Operations: Produce a result or side-effect (e.g., collect(),
forEach()).
• Example:
List<String> names = Arrays.asList("John", "Jane", "Paul");
names.stream()
.filter(name -> name.startsWith("J"))
.forEach(System.out::println);

Intermediate and Terminal Operations:


1. Intermediate Operations:
• Operations that return a new stream and do not modify the original stream.
• Examples: filter(), map(), distinct(), sorted().
2. Terminal Operations:
• Operations that produce a result, such as a value or side-effect.
• Examples: collect(), reduce(), forEach().

• Example using both intermediate and terminal operations:


List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue)
.sum();

Parallel Streams:
• Parallel streams enable processing of elements in a stream in parallel, taking advantage of
multi-core processors.
• They use the ForkJoinPool to divide the workload across multiple threads.

• Example:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream()
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue)
.sum();

• Caution: Parallel streams are not always faster. For small collections or simple operations,
they may even perform worse than sequential streams.

Functional Interfaces:
• A functional interface is an interface that has only one abstract method, and it can have
multiple default or static methods.
• Common functional interfaces:
• Runnable, Callable, Comparator, Consumer, Supplier, Function,
Predicate.
• Example:
@FunctionalInterface
interface MathOperation {
int operation(int a, int b);
}

// Using Lambda Expression to implement MathOperation


MathOperation addition = (a, b) -> a + b;
System.out.println(addition.operation(5, 3)); // Output: 8
10. Java for Web Development

Introduction to Servlets:
• Servlets are Java programs that run on a web server and handle HTTP requests and
responses.
• They are the foundation of Java web applications and are used to generate dynamic content.
• Servlet Lifecycle:
1. init(): Initializes the servlet.
2. service(): Handles client requests.
3. destroy(): Cleans up resources before the servlet is destroyed.
• Example of a basic servlet:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloServlet extends HttpServlet {


protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h1>Hello, World!</h1>");
}
}

JSP (Java Server Pages):


• JSP is a technology used to create dynamic web pages using Java. It allows embedding Java
code inside HTML using special tags (<% %>).

• The Java code is compiled into a servlet, and it runs on the server to produce dynamic
content.
• JSP Syntax:

Declarations: <%! int count = 0; %>

Scriptlets: <% count++; %>

Expressions: <%= count %>

Directives: <%@ page language="java" contentType="text/html"
%>
• Example of a simple JSP file:
<html>
<body>
<h1>Welcome to JSP</h1>
<%
String name = request.getParameter("name");
out.println("Hello, " + name);
%>
</body>
</html>

JDBC (Java Database Connectivity):


• JDBC is a Java API that allows Java applications to connect to databases, send SQL queries,
and process the results.
• Steps in JDBC:
1. Load the database driver:
Class.forName("com.mysql.cj.jdbc.Driver");

2. Establish a connection:
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb",
"username", "password");

3. Create a statement:
Statement stmt = conn.createStatement();

4. Execute a query:
ResultSet rs = stmt.executeQuery("SELECT * FROM users");

5. Process the result:


java
Copy code
while (rs.next()) {
System.out.println(rs.getString("name"));
}

• Closing Resources:
It's important to close Connection, Statement, and ResultSet to free up database
resources.
rs.close();
stmt.close();
conn.close();

Connecting to a Database:
• Steps to connect to a database:
1. Load the database driver.
2. Establish a connection using DriverManager.getConnection().
3. Create a Statement or PreparedStatement to send SQL queries.
4. Execute the query and process the results.
• Example of connecting to MySQL:
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root",
"password");

• Database URL Structure:


1. jdbc:database_type://host:port/database_name
2. Example: jdbc:mysql://localhost:3306/mydb

Executing Queries:
• Executing SQL Queries:
1. Statement.executeQuery(): Used for queries that return a result set, such as
SELECT.
2. Statement.executeUpdate(): Used for queries that do not return a result set, such as
INSERT, UPDATE, or DELETE.
• Example of executing a SELECT query:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
while (rs.next()) {
System.out.println(rs.getString("name"));
}

• Example of executing an INSERT query:


Statement stmt = conn.createStatement();
int rowsAffected = stmt.executeUpdate("INSERT INTO users (name, age)
VALUES ('John', 30)");

• PreparedStatement:
Used for executing SQL queries with parameters. It helps avoid SQL injection and improves
performance for repeated queries.
Example:
String query = "INSERT INTO users (name, age) VALUES (?, ?)";
PreparedStatement ps = conn.prepareStatement(query);
ps.setString(1, "John");
ps.setInt(2, 30);
ps.executeUpdate();
11. Frameworks in Java

Overview of Popular Frameworks:


Java has several popular frameworks that simplify development by providing pre-written code and
tools to handle common tasks. These frameworks help developers focus on business logic rather
than repetitive tasks.
1. Spring Framework: A comprehensive framework that provides tools for building enterprise
applications, including dependency injection, aspect-oriented programming, and transaction
management.
2. Spring Boot: A lightweight framework built on top of Spring, which simplifies the setup
and development of Spring applications by eliminating the need for configuration files.
3. Hibernate: An Object-Relational Mapping (ORM) framework that simplifies database
interactions by mapping Java objects to database tables.
4. Apache Struts: A framework for building web applications based on the Model-View-
Controller (MVC) pattern, typically used for large-scale enterprise apps.

Spring and Spring Boot:


1. Spring Framework:
• Dependency Injection (DI): Spring uses DI to manage the components of an
application. It allows for better testability, maintainability, and decoupling of
components.
• Aspect-Oriented Programming (AOP): Spring provides support for AOP, enabling
separation of cross-cutting concerns like logging and transaction management.
2. Spring Boot:
• Purpose: Spring Boot simplifies Spring application development by reducing
boilerplate configuration and setup. It follows the "convention over configuration"
approach.
• Embedded Servers: Spring Boot comes with embedded web servers like Tomcat,
Jetty, or Undertow, so there is no need to deploy the application to an external server.
• Auto Configuration: Spring Boot automatically configures components based on
the libraries on the classpath, which reduces the need for manual configuration.
• Example of Spring Boot:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Hibernate:
• What is Hibernate?
• Hibernate is an ORM framework that maps Java objects to database tables. It
eliminates the need for developers to write SQL queries to interact with the database,
instead allowing them to use Java methods.
• Advantages of Hibernate:
• Simplifies database interaction.
• Reduces boilerplate code for CRUD operations.
• Supports object-oriented query language (HQL).
• Handles database connection pooling and caching.
• Basic Hibernate Example:
SessionFactory factory = new
Configuration().configure("hibernate.cfg.xml")
.addAnnotatedClass(Employee.cl
ass)
.buildSessionFactory();

Session session = factory.getCurrentSession();


try {
Employee employee = new Employee("John", "Doe",
"[email protected]");
session.beginTransaction();
session.save(employee);
session.getTransaction().commit();
} finally {
factory.close();
}

Apache Struts:
• What is Apache Struts?
• Apache Struts is a framework for creating Java-based web applications, especially
suited for large-scale enterprise-level applications.
• It is based on the Model-View-Controller (MVC) architecture, which separates the
application logic, user interface, and data.
• Struts Features:
• Supports action-based programming, where user actions trigger corresponding logic.
• Provides tag libraries for form handling, data display, and validation.
• Integrates easily with other Java technologies like EJB, Hibernate, and Spring.
• Basic Struts Example:
• In Struts, actions are defined in XML configuration files, and the logic is
implemented in Java classes.
• Example of an action mapping in struts-config.xml:
<action path="/greet"
type="com.example.GreetAction"
name="greetForm"
scope="request"
input="/greet.jsp">
<forward name="success" path="/welcome.jsp"/>
</action>
Basic Example Using Spring Boot:
1. Create a Spring Boot Application:
• Use the @SpringBootApplication annotation to indicate the main class of
your Spring Boot application.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

2. Controller Class:
• Create a REST controller to handle HTTP requests.
@RestController
@RequestMapping("/api")
public class HelloController {

@GetMapping("/hello")
public String sayHello() {
return "Hello, Spring Boot!";
}
}

3. Run the Application:


• Spring Boot will automatically configure everything and run an embedded Tomcat
server.
• You can run the application using the command:
mvn spring-boot:run or by running the DemoApplication class directly.
12. Java 8 and Beyond

Features Introduced in Java 8:


1. Default and Static Methods in Interfaces:
• Default Methods: Java 8 introduced the ability to add default methods in interfaces.
These methods have a body and can provide a default implementation. They allow
you to add new methods to interfaces without breaking existing implementations.
interface MyInterface {
default void printHello() {
System.out.println("Hello from default method");
}
}

• Static Methods: You can also define static methods in interfaces, which are not
inherited by implementing classes.
interface MyInterface {
static void printStatic() {
System.out.println("Static method in interface");
}
}

2. Optional Class:
• Purpose: The Optional class is used to represent optional values that may or may
not be present. It helps to avoid NullPointerException and encourages more
explicit handling of missing values.
• Example:
Optional<String> optional = Optional.of("Hello");
optional.ifPresent(System.out::println); // prints "Hello"

3. Date and Time API:


• Introduction: Java 8 introduced a new Date and Time API (java.time package)
that is more comprehensive and easier to use compared to the old Date and
Calendar classes.
• Key Classes:
• LocalDate: Represents a date without time (e.g., 2024-11-19).
• LocalTime: Represents a time without date (e.g., 12:30:00).
• LocalDateTime: Represents both date and time (e.g., 2024-11-
19T12:30).
• ZonedDateTime: Represents a date and time with a time zone.
• Example:
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();
Highlights from Newer Versions (Java 9, 10, 11, up to 21):
1. Modules (Java 9):
• Introduction: Java 9 introduced the module system to provide better modularization
and encapsulation of code. It allows developers to define modules and explicitly
specify dependencies between them.
• Module Declaration: You declare a module using the module-info.java file.
• Example:
module mymodule {
requires java.base;
exports com.myapp;
}

2. Local-variable Type Inference (var) (Java 10):


• Introduction: Java 10 introduced var, allowing developers to let the compiler infer
the type of a local variable based on the assigned value.
• Example:
var name = "John"; // compiler infers String type
var age = 25; // compiler infers int type

3. Text Blocks (Java 13):


• Introduction: Java 13 introduced text blocks to make multi-line strings more
readable and easier to work with.
• Example:
String json = """
{
"name": "John",
"age": 25
}
""";

4. Pattern Matching (Java 16+):


• Introduction: Java introduced pattern matching to simplify type checks and casting
in conditions like instanceof and switch.
• Example with instanceof:
if (obj instanceof String s) {
System.out.println(s.length());
}

Key Takeaways:
• Java 8 brought powerful changes like default methods in interfaces, the Optional class,
and a new Date-Time API.
• Java 9 introduced modules to improve code organization and maintainability.
• Java 10 introduced the var keyword for local-variable type inference.
• Java 13 added text blocks for easier handling of multi-line strings.
• Java 16 and beyond introduced pattern matching to simplify type checks and casting.
13. Java Best Practices

1. Naming Conventions:
• Classes and Interfaces: Class and interface names should be written in PascalCase
(uppercase first letter of each word).
• Example: StudentDetails, EmployeeService
• Methods and Variables: Method and variable names should be written in camelCase
(lowercase first letter, and uppercase for subsequent words).
• Example: getStudentName(), totalAmount
• Constants: Constants should be in UPPER_SNAKE_CASE (all uppercase, with
underscores separating words).
• Example: MAX_SIZE, PI_VALUE
• Package Names: Package names should be all lowercase with no underscores, often using
the company's domain name in reverse.
• Example: com.example.studentmanagement
• Avoid Abbreviations: Avoid using abbreviations in names unless they are well known (e.g.,
URL or ID).

2. Code Optimization Tips:


• Use Efficient Data Structures: Choose the right data structure for the problem at hand
(e.g., ArrayList for simple lists, HashMap for key-value pairs).

• Minimize Memory Usage: Avoid holding unnecessary references to objects, and prefer
primitive types over wrapper classes when possible to save memory.
• Use StringBuilder for String Concatenation: Instead of concatenating strings in a loop
(which creates multiple objects), use StringBuilder or StringBuffer to efficiently
append strings.
• Example:
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");

• Avoid Repeated Calculations: Cache the result of expensive operations (like loops or
database queries) if the result is reused multiple times.
• Use Streams Efficiently: When using Java Streams, avoid performing unnecessary
intermediate operations or excessive parallelization, as it can add overhead.
• Close Resources Properly: Always close resources like file streams, database connections,
etc., in a finally block or use try-with-resources to ensure they are closed automatically.
3. Writing Testable Code (Unit Testing with JUnit):
• Write Small, Focused Methods: Each method should perform a single task. This makes
testing easier and ensures that methods are reusable.
• Use Dependency Injection: Instead of hardcoding dependencies in classes, inject them via
constructors or setters. This makes it easier to test individual components.
• Use Mocking for External Dependencies: When unit testing, use mocking frameworks like
Mockito to simulate external services, databases, etc.

• Example with Mockito:


@Mock
DatabaseService databaseService;

@InjectMocks
UserService userService;

@Test
void testAddUser() {

when(databaseService.saveUser(any(User.class))).thenReturn(true);
assertTrue(userService.addUser(new User()));
}

• Write Tests for All Logic: Ensure that all logic, especially complex conditions and loops, is
tested. Also, test edge cases.
• Test-Driven Development (TDD): Consider adopting TDD, where you write tests first, then
write code to pass those tests. This ensures code is always written with testability in mind.
• Use JUnit 5 for Unit Testing: JUnit 5 provides a more powerful and flexible testing
framework. Use annotations like @Test, @BeforeEach, @AfterEach,
@ParameterizedTest for efficient testing.

• Example:
@Test
void testAddition() {
int result = calculator.add(2, 3);
assertEquals(5, result);
}

4. Avoiding Common Mistakes:


• Null Pointer Exceptions: Always check for null before dereferencing objects. Use
Optional to handle potential null values more gracefully.

• Hard-Coding Values: Avoid hard-coding values such as file paths, URLs, or configuration
settings. Use constants or configuration files instead.
• Ignoring Exception Handling: Always handle exceptions appropriately. Avoid catching
generic exceptions and provide specific error messages where possible.
• Overusing Static Methods: Overusing static methods can make code harder to test and
maintain. Prefer instance methods when possible, especially in large projects.
• Premature Optimization: Don't optimize code before it's necessary. Focus on writing
clean, readable code first, and optimize only when performance is proven to be a concern.
• Ignoring Code Comments: While you should strive for clean and readable code, don't
neglect documentation where needed. Use comments to explain the reasoning behind
complex logic or design decisions.
• Failing to Follow the DRY Principle: Don’t Repeat Yourself. If you find yourself writing
the same code multiple times, refactor it into reusable methods or classes.
14. Hands-on Projects

1. Build a Calculator:
Objective: Build a simple calculator that performs basic arithmetic operations like addition,
subtraction, multiplication, and division.
Steps:
1. Create a User Interface (UI): Use a Java GUI framework like Swing or JavaFX to
design the calculator UI with buttons for numbers (0-9) and operations (+, -, *, /).
2. Handle User Input: Implement event listeners for buttons to capture user input and display
the result.
3. Perform Calculations: Write methods to handle each arithmetic operation. Store the input
and result, update the display as necessary.
4. Handle Errors: Implement error handling, such as division by zero or invalid input.
Example:
// A simple example of addition operation
public class Calculator {
private double num1, num2, result;

public double add(double a, double b) {


return a + b;
}
}

2. Create a To-Do List Application:


Objective: Build a simple to-do list application where users can add, remove, and mark tasks as
completed.
Steps:
1. Create a Task Class: Create a class Task with properties like taskName,
isCompleted, and methods to add, remove, and update tasks.
2. Design the UI: Use JavaFX or Swing to create a basic UI with text fields for entering tasks,
a list to display tasks, and buttons to add, remove, or mark tasks as completed.
3. Data Persistence: Use a file (e.g., JSON, CSV) or a database to store the tasks so they
persist even after the application is closed.
4. Handle Events: Add event listeners to buttons to update the task list, such as adding a new
task, removing a selected task, or marking a task as completed.
Example:
public class Todo {
private List<String> tasks = new ArrayList<>();

public void addTask(String task) {


tasks.add(task);
}
public void removeTask(String task) {
tasks.remove(task);
}

public void markAsCompleted(String task) {


int index = tasks.indexOf(task);
if (index != -1) {
tasks.set(index, task + " - Completed");
}
}
}

3. Design a Simple Banking System:


Objective: Build a simple banking system where users can create an account, check balance,
deposit money, and withdraw money.
Steps:
1. Create an Account Class: Define an Account class with properties like
accountNumber, balance, and methods to deposit and withdraw money.
2. User Interface: Design a simple text-based or graphical UI where users can input
commands to create an account, view balance, deposit, or withdraw money.
3. Transaction Logic: Implement logic to validate deposit and withdrawal operations,
ensuring the user doesn’t withdraw more than the available balance.
4. Data Persistence: Store account details in a file or database to allow saving and retrieving
account information.
Example:
public class Account {
private String accountNumber;
private double balance;

public Account(String accountNumber) {


this.accountNumber = accountNumber;
this.balance = 0;
}

public void deposit(double amount) {


balance += amount;
}

public boolean withdraw(double amount) {


if (balance >= amount) {
balance -= amount;
return true;
} else {
System.out.println("Insufficient balance");
return false;
}
}

public double getBalance() {


return balance;
}
}
4. Develop a REST API with Spring Boot:
Objective: Build a simple REST API using Spring Boot to perform CRUD (Create, Read, Update,
Delete) operations on a resource like User.

Steps:
1. Set Up Spring Boot Project: Use Spring Initializr to create a new Spring Boot project with
dependencies like Spring Web and Spring Data JPA.
2. Create a User Model: Define a User entity class with properties like id, name, and
email.
3. Create a Repository: Use JpaRepository to handle database operations for the User
entity.
4. Create a Controller: Define a controller with RESTful endpoints to create, retrieve, update,
and delete users.
5. Run the Application: Start the Spring Boot application and test the API using Postman or a
similar tool.
Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;

// Getters and Setters


}

@RestController
@RequestMapping("/users")
public class UserController {

@Autowired
private UserRepository userRepository;

@PostMapping
public User createUser(@RequestBody User user) {
return userRepository.save(user);
}

@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userRepository.findById(id).orElse(null);
}

@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userRepository.save(user);
}

@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userRepository.deleteById(id);
}
}

You might also like