AJ Notes
AJ Notes
Introduction to Generics :
What are Generics?
Generics are a way to create classes, interfaces, and methods with type
parameters. Think of them as a way to handle data of any type without
needing to specify the exact type when you create your code.
Generic Types: These are types that work with any data type, like
List<T> where T is a placeholder for the type you specify later.
Parameterized Types: When you specify the type for a generic,
like List<String>, you're creating a parameterized type. Here,
String is the parameter, and List<String> is a list that only holds
strings.
Example: If you have a class Box<T>, it can store any type. Using
Box<Integer> means that T is replaced by Integer.
Introduction to WildCards
In Java Generics, wildcards are used to represent unknown types. They
allow you to write more flexible code that can work with different types,
especially when working with generics. Wildcards are represented by the
question mark ? and are mainly used in method arguments to define what
kind of types the method will accept.
Example :
import java.util.ArrayList;
intList.add(9);
strList.add("String");
dblList.add(9.0);
//Works
print(intList);
print(dblList);
print(strList);
}
System.out.println(list);
intList.add(9);
dblList.add(9.0);
nList.add(9);
oList.add("snasj");
print(nList);
print(oList);
//Gets error (because Double is not a super class of Number class)
// print(dblList);
System.out.println(list);
Basic operations are those that perform common tasks such as adding,
removing, and checking elements. Most of these operations are defined in
the Collection interface, which is the root interface of the Collection
Framework.
Adding elements:
Removing elements:
Size of Collection:
2. Bulk Operations
addAll(Collection<? extends E> c): Adds all elements from the specified
collection.
1. List :
Characteristics:
Ordered: Maintains the order of elements as they were inserted.
Allows Duplicates: Elements can appear multiple times in a list.
Indexed Access: Elements can be accessed using an index, like an array.
Common Implementations:
ArrayList: Backed by a dynamic array; efficient for random access but
slower for insertions and deletions in the middle.
LinkedList: Backed by a doubly linked list; efficient for insertions and
deletions but slower for random access.
Vector (legacy): Synchronized version of ArrayList, mainly used in
legacy code.
Use Cases:
Ideal when you need to maintain the order of elements.
Suitable when you need to access elements by index frequently.
Commonly used for caching, ordered data processing, and to-do lists
where duplicates are allowed.
Example:
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Apple"); // Duplicates are allowed
System.out.println(list); // Output: [Apple, Banana, Apple]
2. Set :
A Set is an unordered collection that does not allow duplicate elements.
It’s useful when you need to maintain a unique collection of items.
Characteristics:
Unordered (except for specific implementations).
No Duplicates Allowed: Ensures that each element is unique.
Common Implementations:
HashSet: Backed by a hash table; does not maintain order.
LinkedHashSet: Backed by a hash table and a linked list; maintains
insertion order.
TreeSet: Backed by a red-black tree; maintains elements in sorted order.
Use Cases:
Suitable for storing unique elements, such as IDs, usernames, or product
SKUs.
Useful for removing duplicates from a collection.
Can be used for set operations (like union, intersection, and difference).
Example:
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // Duplicate is ignored
System.out.println(set); // Output: [Apple, Banana]
3. Queue :
Characteristics:
Follows FIFO ordering.
New elements are added at the end, and removal happens from the front.
Queue is an interface; common implementations include LinkedList and
PriorityQueue.
Common Methods:
offer(): Adds an element to the queue; returns false if the queue is full (in
bounded queues).
poll(): Removes and returns the head of the queue; returns null if the
queue is empty.
peek(): Retrieves, but does not remove, the head of the queue; returns null
if the queue is empty.
4. Map :
Characteristics:
No Duplicate Keys: Each key can map to only one value.
Unordered (unless using specific implementations).
Common Implementations:
HashMap: Backed by a hash table; does not guarantee any order.
LinkedHashMap: Maintains insertion order of keys.
TreeMap: Backed by a red-black tree; maintains keys in sorted order.
ConcurrentHashMap: A thread-safe map for concurrent operations.
Use Cases:
Ideal for scenarios where you need to associate unique keys with values.
Used frequently for lookup tables, caches, and dictionaries where you
want to retrieve values based on unique keys.
Example:
java
Copy code
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Apple", 3); // Key "Apple" is updated
System.out.println(map); // Output: {Apple=3, Banana=2}
Both TreeMap and HashMap are part of the Java Collection Framework
and are used to store key-value pairs. But they work differently.
TreeMap :
How It Works:
A TreeMap organizes all the keys in sorted order (ascending by
default).
Key Rules:
No null keys allowed (because sorting a null value doesn’t make
sense).
Null values are allowed (you can store a null as a value, like key:
John, value: null).
Speed:
Slightly slower because it spends time sorting the keys.
Every operation (like adding, removing, or finding a key) takes O(log
n) time.
Extra Features:
You can easily find the smallest or largest key (firstKey(), lastKey()).
You can get keys in a specific range (e.g., all keys between A and M).
When to Use:
When you need the keys to always stay sorted.
Useful for tasks like leaderboards where you need data in a ranked
order.
example :
import java.util.TreeMap;
HashMap :
How It Works:
A HashMap uses a hashing technique to store data, which makes it
super fast for looking up or adding keys.
There’s no specific order for keys.
Key Rules:
Allows one null key (e.g., key: null, value: Something).
Allows multiple null values (e.g., key1: X, value: null, key2: Y, value:
null).
Speed:
Very fast! Adding, removing, or finding keys usually takes O(1) time
(constant time).
Can get slower if too many keys “clash” (hash collisions), but this is
rare.
When to Use:
When you just need quick access to key-value pairs.
Example :
import java.util.HashMap;
Lambda Expressions :
Syntax Example :
(parameters) -> expression
// or
(parameters) -> { statements; }
2. Lambda Parameters
JSP Architecture :
1. Translation/Compilation Phase :
When a JSP page is requested for the first time, the JSP container
(like Apache Tomcat) converts the JSP file into a Java Servlet (which
is a Java program). This process is called "translation."
The JSP code is turned into Java code that handles the logic and
dynamic content (like displaying different information based on user
input).
Then, this Java code is turned into a bytecode file (.class file) that the
computer can understand and run.
2. Initialization Phase :
After the JSP page has been converted into a servlet, the JSP
container loads this servlet into memory.
The container calls a special method called init() to set things up for
the servlet. This step happens only once when the JSP page is first
requested.
In the init() method, things like database connections or shared
resources are prepared.
4. Destroy Phase :
When the servlet is no longer needed (like when the server is shutting
down or the JSP page is being replaced), the container calls the
destroy() method.
In this step, the servlet releases resources it was using, like closing
database connections or cleaning up memory.
After that, the servlet is removed from memory.
JSP Building blocks :
building blocks are the essential components that allow for the
development of dynamic web pages. These include elements like
directives, scripting elements, actions, and expressions, each serving
different purposes within JSP files.
1. Directives :
1] Page Directive
2] Include Directive
3] Taglib Directive
1. Page Directive :
The page directive defines attributes that apply to the entire JSP page.
Syntax: <%@ page attribute="value" %>
Important attributes:
3] buffer: Defines the size of the buffer. Common values include none
(no buffering) or a specific size (e.g., 8kb).
Example: <%@ page buffer="16kb" %>
6] isErrorPage: Indicates whether the current JSP page can act as an error
handler for other JSP pages.
Example: <%@ page isErrorPage="true" %>
2. Include Directive :
Important attribute:
file: Specifies the path to the file to be included.the included file's content
is added to the JSP page at translation time.
Example: <%@ include file="header.jsp" %>
3. Taglib Directive :
The taglib directive allows for the use of custom tags defined in tag
libraries, such as the JSP Standard Tag Library (JSTL). This enables
modular and reusable code by allowing complex functionalities to be
handled by custom tags.
Syntax: <%@ taglib prefix="prefix" uri="uri" %>
Important attributes:
prefix: Specifies a short name that will be used in the JSP to refer to the
custom tags from the library.
Example: <%@ taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core" %>
uri: Defines the URI for locating the tag library descriptor (TLD) file,
which contains the tag definitions and attributes.
Example: <%@ taglib prefix="fmt"
uri="http://java.sun.com/jsp/jstl/fmt" %>
2. Scripting Elements
Scripting elements allow you to embed Java code directly in a JSP file.
There are three types of scripting elements:
1] Declaration
2] Scriptlet
3] Expression
Scriptlets: Allow Java code to be inserted into the service method of the
JSP page. Scriptlets are used to execute Java code that interacts with the
JSP content.
Syntax: <% code %>
Example: <% counter++; %>
3. Action tag
JSP action tags are XML-like tags that enable dynamic functionality
within a JSP page. These tags are processed by the server and used to
perform tasks such as including content from other resources, managing
JavaBeans, and forwarding requests. They are essential for creating
modular and reusable JSP code.
Here are the some JSP action tags :
1. <jsp:include> :
Attributes:
page: Specifies the path to the resource to be included.
Example: <jsp:include page="header.jsp" />
2. <jsp:forward> :
Attributes:
page: Specifies the path to the target resource for the forward action.
Example: <jsp:forward page="login.jsp" />
Use Case: Frequently used in login pages, form submissions, and error
handling scenarios where, based on conditions, the request needs to be
forwarded to a different JSP or servlet.
3. <jsp:param> :
Attributes:
name: Specifies the name of the parameter.
Example: <jsp:param name="username" value="JohnDoe" />
value: Specifies the value of the parameter.
Example: <jsp:param name="userType" value="admin" />
4. <jsp:useBean>
Attributes:
id: Specifies a unique identifier for the bean, used to reference it within
the JSP page.
Example: <jsp:useBean id="user" class="com.example.User" />
class: The fully qualified name of the JavaBean class.
Example: <jsp:useBean id="user" class="com.example.User" />
scope: Specifies the bean’s scope (page, request, session, or application),
determining its lifetime and visibility.
Example: <jsp:useBean id="user" class="com.example.User"
scope="session" />
Use Case: Commonly used to store user or session data, such as form
input, throughout multiple JSP pages, enabling data sharing across
different parts of an application.
1. request Object :
The request object represents the data sent by the client to the server.
It helps you access things like form inputs, query parameters in the URL,
headers, and cookies.
Examples of use:
getParameter("name"): Get values from form fields.
getAttribute("key"): Access temporary data stored during a single request.
getSession(): Get the user’s session if they have one.
Scope: It’s only available during the current request (e.g., while loading a
page).
Ex. String username = request.getParameter("username");
2. response Object :
The response object represents the reply sent from the server back to the
client.
You can use it to set response details, like content type, add cookies, or
redirect to another page.
Examples of use:
setContentType("text/html"): Set the type of content being sent (e.g.,
HTML, JSON).
addCookie(new Cookie("name", "value")): Add a cookie for the user.
sendRedirect("newPage.jsp"): Redirects the client to another page.
Scope: Exists only while building the response for the client.
Cookie userCookie = new Cookie("username", "JohnDoe");
response.addCookie(userCookie);
3. session Object :
The session object stores user-specific data across multiple requests (like
pages) for a single user.
Use it to keep track of things like login status or preferences.
Examples of use:
getAttribute("key"): Get data from the session.
setAttribute("key", value): Store data for this user session.
invalidate(): End the session (e.g., when the user logs out).
Scope: Lasts as long as the user is active on the site or until they log out.
session.setAttribute("user", username);
String currentUser = (String) session.getAttribute("user")
4. application Object :
The application object stores data that is shared across the entire
application.
It’s useful for settings or data that should be accessible to all users.
Examples of use:
getAttribute("key"): Access global data for the application.
setAttribute("key", value): Save data that everyone can use.
Scope: Lasts as long as the application is running.
<%
visitCount = (Integer) application.getAttribute("visitCount");
if (visitCount == null) {
visitCount = 1;
}
else {
visitCount++;
}
application.setAttribute("visitCount", visitCount);
%>
<p>Total visits to this site: <%= visitCount %></p>
5. out Object :
The out object is used to send content directly to the client.
It’s like a writer that lets you print text or HTML to the page.
Examples of use:
print("Hello, World!"): Print text to the page.
println("Welcome!"): Print text with a newline.
Scope: Exists only while generating the response for the client.
out.print("<h1>Welcome to My Site!</h1>");
6. config Object :
The config object holds configuration information about the servlet (the
server-side program that powers JSP).
It’s useful for accessing parameters that were set when the servlet was
initialized.
Examples of use:
getServletName(): Get the name of the servlet.
getInitParameter("key"): Get a setting that was defined in the web.xml
file.
Scope: Available as long as the application is running; settings cannot be
changed after initialization.
<%
String appName = config.getInitParameter("applicationName");
%>
<p>Application Name: <%= appName %></p>
7. page Object :
The page object is a reference to the current JSP page itself.
Think of it as a shortcut to access methods on the page itself.
Scope: Limited to the current page and isn’t usually needed directly.
<%
// Using `page` is equivalent to using `this` in a JSP
String currentPageName = page.getClass().getName();
%>
<p>This JSP page's class name is: <%= currentPageName %></p>
8. pageContext Object :
The pageContext object provides access to all the different scopes (like
request, session, application) and other JSP objects.
It’s like a central tool for managing attributes and interacting with request,
response, and session data.
Examples of use:
setAttribute("key", value): Set an attribute for the current page.
getRequest(): Get the request object.
Scope: Limited to the current page.
pageContext.setAttribute("pageMessage", "This is a page-scoped
message.");
9. exception Object
The exception object is only available on error pages.
It represents any errors that occurred while processing a request.
Examples of use:
getMessage(): Get the error message.
printStackTrace(): Print the error details.
Scope: Only available on pages that are set up to handle errors (using
isErrorPage="true").
<%@ page isErrorPage="true" %>
<%
if (exception != null)
{ out.println("<p>Error: " + exception.getMessage() + "</p>");}
%>
Session Tracking types and methods :
When a user visits a website, the server doesn't automatically remember
who they are or what they did on previous pages because HTTP (the
protocol used for web pages) is stateless. This means that every time you
load a page, it's like starting fresh. Session tracking helps the server
"remember" things like who the user is and what actions they took, so
they don't have to start from scratch every time.
1. URL Rewriting :
How it works: The server adds session information directly into the
URL when you click a link. This means the browser automatically
sends this session information when you visit the next page.
When to use it: It's useful if the user's browser has cookies turned off,
because cookies won’t work in that case.
Example: When you click a link like this:
<a href="<%= response.encodeURL("nextPage.jsp") %>">Go to next
page</a>
The encodeURL method adds session information to the link's URL
so the server can still know who you are.
example :
FormatDateTag.java :
package com.customtags;
import java.util.Date;
@Override
public void doTag() throws JspException, IOException {
if (date != null) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-
MM-dd HH:mm:ss");
<taglib>
<uri>customtags</uri>
<tag>
<name>formatDate</name>
<tag-class>com.customtags.FormatDateTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>date</name>
<required>true</required>
<type>java.util.Date</type>
</attribute>
</tag>
</taglib>
index.jsp :
<!DOCTYPE html>
<html>
<head>
<title>Custom JSP Tag Example</title>
</head>
<body>
<h1>Formatted Date Example</h1>
<p>Current Date and Time: <ct:formatDate date="<%= new
Date() %>" /></p>
</body>
</html>
MODULE 3
Aspects: These are the parts of your app that handle tasks like logging or
security.
Instrumentation: Tools to modify and manage your code while it is
running.
4. Messaging :
This part helps your app send and receive messages, like notifications or
updates, using tools like RabbitMQ or Kafka.
5. Core Container :
This is the foundation of the Spring Framework. It manages objects
(called beans) and how they interact:
Beans: These are the building blocks of your app, and Spring manages
their lifecycle and settings.
Core: Provides basic features like managing the relationships between
objects (dependency injection).
Context: Works with the Core to manage your app as a whole and
provides tools to use beans more easily.
SpEL: A simple way to include dynamic logic in your app’s configuration,
like calculations or conditions.
6. Test :
This part helps you test your app to ensure it works correctly:
What is a POJO?
POJO stands for Plain Old Java Object.
It’s a basic Java class that contains variables (fields) and methods to
access or modify them (getters and setters).
POJOs are used to define objects in a simple and readable way.
Example: Employee.java
Example: MainClass.java
package Jtp.PojoDemo;
// Set values
obj.setName("Alisha");
obj.setId("A001");
obj.setSal(200000);
Output:
Name: Alisha
Id: A001
Salary: 200000.0
The IoC (Inversion of Control) container is the core part of the Spring
Framework.
It is responsible for:
Creating objects (like your classes or components).
Configuring them (setting values or dependencies).
Managing their lifecycle (from creation to destruction).
It uses Dependency Injection (DI) to manage objects.
1. BeanFactory Container
2. ApplicationContext Container
1. BeanFactory Container :
Basic container that provides simple Dependency Injection (DI).
Uses the BeanFactory interface to handle beans.
Commonly used when resources are limited (e.g., on mobile devices
or small applications).
Example:
HelloWorld.java
package com.example;
MainApp.java :
package com.example;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
<beans xmlns="http://www.springframework.org/schema/beans">
<bean id="helloWorld" class="com.example.HelloWorld">
<property name="message" value="Hello World!" />
</bean>
</beans>
Output:
Your Message: Hello World!
2. ApplicationContext Container :
More advanced container than BeanFactory.
It includes all BeanFactory features and provides extra functionality.
It is recommended over BeanFactory for most applications.
HelloWorld.java :
same as above....
MainApp.java :
package com.example;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.FileSystemXmlApplicationContext;
Beans.xml :
same as above…
1. Constructor-Based DI :
Example :
Movie.java :
public class Movie {
private String movieName; // Dependency
Beans.xml :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-
beans.xsd">
</beans>
How It Works:
movieName is the dependency needed by Movie.
When Spring creates an object of Movie, it will inject the dependency
into the constructor.
2. Setter-Based DI :
Example :
Movie.java :
public class Movie {
private String movieName; // Dependency
Beans.xml :
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-
beans.xsd">
</beans>
How It Works:
Spring creates an object of Movie and then uses the setMovieFinder()
method to inject the dependency (movieName).
Problem Scenario :
We have two services, ServiceA and ServiceB, that depend on each other.
ServiceA.java:
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private ServiceB serviceB;
ServiceB.java:
import org.springframework.stereotype.Service;
@Service
public class ServiceB {
private ServiceA serviceA;
In this example:
ServiceA.java:
java
Copy code
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private ServiceB serviceB;
Spring allows you to define a parent bean with configuration values and
then create child beans that inherit those values. The child bean can
either use the inherited configuration as-is or override it. This concept is
similar to inheritance in programming but works with Spring beans, not
Java classes.
When we talk about bean inheritance, it means that one bean can
inherit properties and configurations from another bean. You define this
relationship using the parent attribute in Spring's XML-based
configuration.
Key Concepts:
Parent Bean: A template bean that contains common configurations or
properties.
Child Bean: A bean that inherits configurations from the parent bean and
can override or add more properties.
You define a parent bean (like helloWorld) and set its properties.
Example:
Here, the helloWorld bean has two properties: message1 and message2.
The child bean (like helloIndia) is defined by using the parent attribute to
inherit properties from the parent (helloWorld). The child can override
the inherited properties and add new ones.
Example:
HelloWorld.java :
HelloIndia.java :
Autowiring Modes:
Module 4
class Example {
public void m1() { /* Do something */ }
public void m2() { /* Do something */ }
public void m3() { /* Do something */ }
public void m4() { /* Do something */ }
public void m5() { /* Do something */ }
public void n1() { /* Do something */ }
public void n2() { /* Do something */ }
public void p1() { /* Do something */ }
public void p2() { /* Do something */ }
public void p3() { /* Do something */ }
}
Scenario:
You want to log a message before and after every method that starts
with "m".
Without AOP: You’ll write the same logging code in 5 methods (m1, m2,
etc.). This is repetitive and boring.
With AOP: You write the logging code in one place, and it’s automatically
applied to all methods that start with "m". Less work, less mess!
1. Aspect:
This is where you write the extra feature code (e.g., logging, security
checks).
Example: Logging every time a method is called.
2. Join Point:
A specific place in your code where an aspect (extra feature) can be
applied.
Example: A method being called or an exception being thrown.
3. Advice:
The actual extra code you want to run. There are different types:
Before Advice: Runs before a method starts.
After Advice: Runs after a method finishes.
Around Advice: Runs before and after a method.
4. Pointcut:
A rule that decides where to apply the advice (extra code).
Example: "Apply logging only to methods that start with 'm'."
Example :
1. Before Advice :
What It Does: Runs before the actual method (or join point) starts.
Example:
@Before("execution(* com.example.MyClass.myMethod(..))")
public void logBefore() {
System.out.println("Before the method is executed.");
}
Output :
Before the method is executed.
<Then the actual method runs>
Example:
@AfterReturning("execution(* com.example.MyClass.myMethod(..))")
public void logAfterReturning() {
System.out.println("Method completed successfully.");
}
Output :
<Method runs>
Method completed successfully.
Example :
@AfterThrowing("execution(* com.example.MyClass.myMethod(..))")
public void logAfterException() {
System.out.println("An exception occurred in the method.");
}
Output :
An exception occurred in the method.
4. After Advice :
What It Does: Runs after actual method (joint point).
Example:
@After("execution(* com.example.MyClass.myMethod(..))")
public void logAfterFinally() {
System.out.println("This runs after the method, no matter what.");
}
Output :
<Method runs or throws an error>
This runs after the method, no matter what.
5. Around Advice :
What It Does: Wraps around the method (or join point). It can run
custom code before and after the method, control whether the method
is called, or even modify its result.
Example:
@Around("execution(* com.example.MyClass.myMethod(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws
Throwable {
System.out.println("Before the method runs.");
Object result = joinPoint.proceed(); // Calls the actual method
System.out.println("After the method runs.");
return result;
}
Output :
Before the method runs.
<Method runs>
After the method runs.
Module 5
Syntax:
Class.forName("DriverClassName");
Example for Oracle Database:
Syntax:
Connection con = DriverManager.getConnection(String url, String
username, String password);
Example:
Syntax:
Statement stmt = con.createStatement();
Example:
java
Copy code
ResultSet rs = stmt.executeQuery("SQL_QUERY");
The query results are stored in a ResultSet object, which lets you access
the data row by row.
Syntax :
con.close();
JDBC Architecture:
JDBC (Java Database Connectivity) helps Java applications communicate
with databases. There are two main types of architectures used for
database access: Two-Tier Architecture and Three-Tier Architecture.
1. Two-Tier Architecture:
Direct Connection: In this setup, a Java application communicates
directly with a database.
How it works:
The application sends requests (queries) to the database and
receives the results directly.
It can be connected to the database on the same computer or a
remote computer over a network (intranet or internet).
Client-Server Model: This is a classic client-server model:
The client is the user's machine (where the application runs).
The server is the machine that hosts the database.
The application (client) talks directly to the database (server) via
JDBC drivers.
Network Connection: The database can be on a local machine or
accessed over the internet/intranet.
2. Three-Tier Architecture: