Important Question With Answers UNIT 1 To 5
Important Question With Answers UNIT 1 To 5
UNIT: 1
Q1: Why Choose Java for Software Development? What is the
History of Java and How Has It Evolved Over Time? Explain
the Role and Functionality of JVM, JRE, and Java
Environment?
Ans:
Example:
public class Car {
// Fields
String color;
String model;
int year;
// Methods
void displayInfo() {
System.out.println("Model: " + model + ", Color: " +
color + ", Year: " + year);
}
}
2. Using Constructors
Example:
// Constructor
public Car(String color, String model, int year) {
this.color = color;
this.model = model;
this.year = year;
}
// Methods
void displayInfo() {
System.out.println("Model: " + model + ", Color: " +
color + ", Year: " + year);
}
}
3. Defining Methods
Example:
// Constructor
public Car(String color, String model, int year) {
this.color = color;
this.model = model;
this.year = year;
}
// Method
void startEngine() {
System.out.println("Engine started");
}
void displayInfo() {
System.out.println("Model: " + model + ", Color: " +
color + ", Year: " + year);
}
}
Using Methods:
public class Main {
public static void main(String[] args) {
Car myCar = new Car("Red", "Toyota", 2020);
myCar.startEngine(); // Output: Engine started
myCar.displayInfo(); // Output: Model: Toyota, Color:
Red, Year: 2020
}
}
1. public
o Visibility: Everywhere. The member is accessible
from any other class.
o Example:
public class Car {
public String model;
}
2. private
o Visibility: Within the same class only. The
member is not accessible from outside the class.
o Example:
public class Car {
private String model;
}
3. protected
o Visibility: Within the same package and
subclasses. The member is accessible within its
own package and by subclasses.
o Example:
// Constructor
public Car(String color, String model, int year, String
owner) {
this.color = color;
this.model = model;
this.year = year;
this.owner = owner;
}
// Methods
public void displayInfo() {
System.out.println("Model: " + model + ", Color: " +
color + ", Year: " + year);
}
class Test {
public static void main(String[] args) {
Car myCar = new Car("Red", "Toyota", 2020, "Alice");
myCar.displayInfo(); // Accessible
// myCar.startEngine(); // Not accessible (private)
myCar.service(); // Accessible (protected, same
package)
myCar.changeOwner("Bob"); // Accessible (default,
same package)
}
}
Output:
Model: Toyota, Color: Red, Year: 2020
Car serviced
1. if Statement
Syntax:
if (condition) {
// code to be executed if the condition is true
} else {
// code to be executed if the condition is false
}
Example:
Use Case:
Syntax:
Example:
Use Case:
3. while Loop
Syntax:
while (condition) {
// code to be executed
}
Example:
int count = 0;
while (count < 5) {
System.out.println("Count: " + count);
count++;
}
Use Case:
4. do-while Loop
Syntax:
do {
// code to be executed
} while (condition);
Example:
int count = 0;
do {
System.out.println("Count: " + count);
count++;
} while (count < 5);
Use Case:
5. switch Statement
Syntax:
switch (variable) {
case value1:
// code to be executed if variable == value1
break;
case value2:
// code to be executed if variable == value2
break;
// more cases
default:
// code to be executed if variable doesn't match any case
}
Example:
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Invalid day");
break;
}
Use Case:
Summary
Inheritance
class Superclass {
// fields and methods
}
Example:
// Superclass
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
// Subclass
class Dog extends Animal {
void bark() {
System.out.println("The dog barks.");
}
}
Method Overriding
Example:
// Superclass
class Animal {
void sound() {
System.out.println("This animal makes a sound.");
}
}
// Subclass
class Dog extends Animal {
@Override
void sound() {
System.out.println("The dog barks.");
}
}
Method Overloading
class ClassName {
void methodName(int a) {
// implementation
}
void methodName(double a) {
// implementation
}
Example:
class Calculator {
int add(int a, int b) {
return a + b;
}
Method Overriding
When to Use
Abstract Classes
// Concrete method
void eat() {
System.out.println("This animal eats food.");
}
}
Example:
// Abstract class
abstract class Animal {
abstract void sound();
void eat() {
System.out.println("This animal eats food.");
}
}
Key Points:
Abstraction: Abstract classes allow you to define a
template for other classes without implementing the
entire functionality.
Polymorphism: Abstract classes enable polymorphism
by allowing derived classes to provide specific
implementations of abstract methods.
Interfaces
interface Animal {
void sound(); // Abstract method
}
Example:
// Interface
interface Animal {
void sound();
default void eat() {
System.out.println("This animal eats food.");
}
}
Abstraction:
Abstract classes and interfaces both provide a way to
achieve abstraction in Java. They allow you to define
methods without implementation, which must be
implemented by subclasses or implementing classes.
This enforces a contract for what methods a class must
have without dictating how those methods should be
implemented.
Polymorphism:
Polymorphism is the ability of different classes to
respond to the same method call in different ways. By
using abstract classes and interfaces, you can write code
that works on the abstract type (interface or abstract
class) rather than a specific concrete class. This allows
for flexibility and the ability to handle new classes that
implement the interface or extend the abstract class
without modifying the existing code.
Example of Polymorphism:
interface Animal {
void sound();
}
Creating a Package
com/example/utilities
// File: com/example/utilities/UtilityClass.java
package com.example.utilities;
Using a Package
What is CLASSPATH?
Configuring CLASSPATH
Set CLASSPATH=.;C:\path\to\classes;C:\path\to\library\
lib.jar
Linux/Mac:
CLASSPATH=.:/path/to/classes:/path/to/library/lib.jar
Class-Path: lib/library.jar
UNIT: 2
Q1: What is the Difference Between Exceptions and Errors in
Java, and How Does the JVM React to Each?
Ans: In Java, both exceptions and errors are subclasses of
Throwable, but they serve different purposes and are used in
different contexts. Here's a detailed explanation of the
differences between exceptions and errors, along with how
the JVM reacts to each.
Exceptions in Java
Definition
Checked Exceptions:
These are exceptions that are checked at compile-time.
If a method throws a checked exception, it must either
handle the exception with a try-catch block or declare
the exception using the throws keyword in the method
signature.
o Examples: IOException, SQLException
Unchecked Exceptions:
These are exceptions that are not checked at compile-
time. They are subclasses of RuntimeException. The
compiler does not force the programmer to handle or
declare these exceptions.
o Examples: NullPointerException,
ArrayIndexOutOfBoundsException,
ArithmeticException
Errors in Java
Definition
Errors are serious problems that a reasonable
application should not try to catch. They are typically
problems that are outside the control of the program and
indicate issues with the runtime environment itself.
Types of Errors
Summary of Differences
Understanding the differences between exceptions and errors, as well
as how the JVM handles them, is crucial for robust Java programming.
While exceptions are recoverable and should be managed within the
application, errors typically indicate serious issues that the application
cannot control or recover from.
Q2: What are Checked and Unchecked Exceptions in Java, and
How Should They Be Handled? How Do the try, catch,
finally, throw, and throws Keywords Work Together in Java
Exception Handling? Write a program related to it.
Checked Exceptions
Unchecked Exceptions
Example Program
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
Explanation
Exception Occurrence:
o When an exception occurs, the normal flow of the
program is disrupted. The Java Virtual Machine
(JVM) looks for a block of code that can handle
the exception.
Exception Propagation:
o If the exception is not caught in the current
method, it propagates up the call stack. This
means that the JVM searches for a suitable catch
block in the calling method. This continues up the
call stack until a suitable handler is found or the
program terminates.
Exception Handling:
o When a matching catch block is found, control
transfers to that block. The exception is
considered handled, and the program execution
continues from the end of the catch block.
Finally Block Execution:
o Regardless of whether an exception is caught or
not, the finally block (if present) is executed. This
block is typically used for cleanup tasks, such as
closing files or releasing resources.
Program Termination:
o If no suitable catch block is found in the entire call
stack, the JVM will terminate the program and
print the stack trace to the standard error output.
methodB Execution:
methodB attempts to perform a division by zero, which
throws an ArithmeticException.
The catch block in methodB catches the exception and
prints a message.
The exception is then rethrown using throw new
ArithmeticException("Rethrown ArithmeticException
from methodB");.
Exception Propagation:
The rethrown ArithmeticException propagates back to
methodA.
The finally block in methodB is executed before the
exception propagates.
methodA Execution:
methodA does not handle the rethrown
ArithmeticException, so it continues to propagate up to
the caller (main method).
The finally block in methodA is executed before the
exception continues to propagate.
main Method Execution:
The main method catches the ArithmeticException and prints
a message.
The finally block in main is executed last.
Important points
Example Program
import java.util.Scanner;
Explanation
Main Method:
validateNumber Method:
Exception Handling:
Byte streams are used for handling raw binary data, including
text files. Here’s how to copy a file using byte streams:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
} catch (IOException e) {
System.out.println("An error occurred: " +
e.getMessage());
}
}
}
Explanation:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
} catch (IOException e) {
System.out.println("An error occurred: " +
e.getMessage());
}
}
}
Explanation:
Important Points
import java.util.LinkedList;
import java.util.Queue;
// Start threads
producer.start();
consumer.start();
}
// Producer class
static class Producer implements Runnable {
@Override
public void run() {
int value = 0;
while (true) {
try {
produce(value);
value++;
Thread.sleep(1000); // Simulate time taken to
produce
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Producer interrupted.");
}
}
}
// Consumer class
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
try {
consume();
Thread.sleep(1500); // Simulate time taken to
consume
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Consumer interrupted.");
}
}
}
Explanation:
Shared Buffer:
A Queue is used as the shared buffer. It has a fixed capacity
(BUFFER_CAPACITY).
Producer Class:
The Producer class implements Runnable and continuously
produces data.
The produce() method is synchronized to ensure mutual
exclusion.
It checks if the buffer is full. If so, it waits (wait()) until the
consumer consumes some data and notifies (notify()) when it
has added new data to the buffer.
Consumer Class:
The Consumer class implements Runnable and continuously
consumes data.
The consume() method is synchronized to ensure mutual
exclusion.
It checks if the buffer is empty. If so, it waits (wait()) until
the producer adds some data and notifies (notify()) when it
has consumed data from the buffer.
Synchronization:
o synchronized blocks ensure that only one thread
can execute the critical section of code that
modifies the buffer at a time.
o wait() makes the current thread wait until it is
notified.
o notify() wakes up one of the threads that are
waiting on the monitor.
Thread Management:
o producer.start() and consumer.start() initiate the
producer and consumer threads.
This program demonstrates basic inter-thread communication
and synchronization using Java's built-in methods and
ensures that the producer and consumer work together
effectively. Adjust the sleep durations as needed to simulate
different production and consumption rates.
//Thread life cycle is important; please cover the topic with
notes.
UNIT: 3
Q1: How Do Functional Interfaces and Lambda Expressions
Improve Code Readability and Maintainability in Java? What
Are Method References, and How Do They Simplify Lambda
Expressions? Provide an Example.
Functional Interfaces
Lambda Expressions
Without Lambda:
With Lambda:
Method References
Example in Context
Q2: Explain the Stream API using diagram and its benefits
over traditional collection operations. Write a Java
program that filters a list of integers, squares the filtered
values, and prints the result using Stream API.
Ans:
Stream API in Java
The Stream API, introduced in Java 8, provides a powerful
and efficient way to process sequences of elements
(collections) in a functional style. It allows you to perform
operations such as filter, map, and reduce on collections in a
more readable and concise manner.
Benefits of Stream API over Traditional Collection
Operations:
Declarative Code: Stream API allows you to write more
readable and maintainable code by specifying what you want
to achieve rather than how to achieve it.
Lazy Evaluation: Intermediate operations are lazy, meaning
they are not executed until a terminal operation is invoked.
This can lead to performance improvements.
Parallel Processing: Streams can be easily parallelized to
leverage multi-core processors, improving performance for
large data sets.
Reduced Boilerplate: Stream operations often require fewer
lines of code compared to traditional iterative approaches.
Functional Style: Promotes functional programming
principles such as immutability and statelessness.
Stream API Diagram
Here is a diagram illustrating the basic workflow of the
Stream API:
Source: A collection, array, or I/O channel.
Stream: A sequence of elements supporting sequential and
parallel aggregate operations.
Intermediate Operations: Transformations such as filter, map,
sorted, which are lazy and return a new stream.
Terminal Operation: Triggers the processing of the pipeline
and returns a result or side effect such as collect, forEach,
reduce.
Example Java Program Using Stream API
Let's write a Java program that filters a list of integers,
squares the filtered values, and prints the results using the
Stream API.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
Explanation:
Source: The source is the list of integers numbers.
Stream: numbers.stream() creates a stream from the list.
Intermediate Operations:
filter(num -> num % 2 == 0): Filters the stream to include
only even numbers.
map(num -> num * num): Maps each element of the filtered
stream to its square.
Terminal Operation:
collect(Collectors.toList()): Collects the squared values into a
list.
Print: squaredNumbers.forEach(System.out::println); prints
each element of the resulting list.
This program demonstrates how to leverage the Stream API
to write concise and expressive code for common operations
on collections.
Q3:
Write a Java program that performs the following tasks:
import java.util.Base64;
/**
* Encodes the given string into Base64 format.
*
* @param input The string to be encoded.
* @return The Base64 encoded string.
*/
public static String encodeBase64(String input) {
return
Base64.getEncoder().encodeToString(input.getBytes());
}
/**
* Decodes the given Base64 encoded string back to its
original form.
*
* @param input The Base64 encoded string to be
decoded.
* @return The decoded original string.
*/
public static String decodeBase64(String input) {
byte[] decodedBytes =
Base64.getDecoder().decode(input);
return new String(decodedBytes);
}
}
Explanation
Main Method:
A sample input string originalString is defined.
The encodeBase64 method is called to encode the
originalString into Base64 format, and the result is printed.
The decodeBase64 method is called to decode the Base64
encoded string back to its original form, and the result is
printed.
encodeBase64 Method:
decodeBase64 Method:
Takes a Base64 encoded string input.
Decodes the Base64 string into a byte array using
Base64.getDecoder().decode(String).
o Converts the byte array back to a string using new
String(byte[]).
o Returns the decoded original string.
To run the program, copy the code into a Java file (e.g.,
Base64Example.java) and execute it. The output will
demonstrate the Base64 encoding and decoding processes:
import java.util.Scanner;
/**
* Returns the number of days in a given month and year.
*
* @param month The month (1-12).
* @param year The year.
* @return The number of days in the month.
*/
public static int getDaysInMonth(int month, int year) {
return switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> 31;
case 4, 6, 9, 11 -> 30;
case 2 -> {
if (isLeapYear(year)) {
yield 29;
} else {
yield 28;
}
}
default -> throw new
IllegalArgumentException("Invalid month: " + month);
};
}
/**
* Determines if a given year is a leap year.
*
* @param year The year.
* @return True if the year is a leap year, false otherwise.
*/
public static boolean isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year %
400 == 0);
}
}
Explanation
getDaysInMonth Method:
isLeapYear Method:
To run the program, copy the code into a Java file (e.g.,
DaysInMonthCalculator.java) and execute it. The program
will prompt you to enter a month and year, and then it will
output the number of days in that month and year. For
example:
import java.util.ArrayList;
import java.util.List;
Explanation
Output
When you run the above code, the output will be:
Apple
Banana
Cherry
Example:
Benefits:
Records
Example:
Benefits:
Limitations:
Sealed Classes
Example:
Benefits:
Limitations:
Switch Expressions
Example:
int day = 3;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> throw new IllegalArgumentException("Invalid
day: " + day);
};
Benefits:
Limitations:
Example Program:
Explanation
Text Blocks:
Program Output:
To run the program, copy the code into a Java file (e.g.,
TextBlocksExample.java) and execute it. The output will
display the formatted multi-line strings as defined in the text
blocks.
UNIT: 4
Q1: What is the Java Collections Framework, and What Are Its
Core Interfaces? List and describe the core interfaces of the
Java Collections Framework. Implement a simple program
demonstrating the use of Collection, List, Set, and Map
interfaces.
import java.util.*;
Collection Interface:
Demonstrated using an ArrayList.
Added elements to the collection and printed it.
List Interface:
Demonstrated using an ArrayList.
Copied elements from the collection to the list, added an
additional element, and printed it.
Set Interface:
Demonstrated using a HashSet.
Copied elements from the list to the set, added an additional
element, and printed it.
Attempted to add a duplicate element to show that sets do not
allow duplicates.
Map Interface:
Demonstrated using a HashMap.
Added key-value pairs to the map and printed it.
Iteration:
Iterated over the elements of the collection, list, set, and map
using enhanced for-loops.
For the map, iterated over the entry set to access keys and
values.
To run the program, copy the code into a Java file (e.g.,
CollectionsDemo.java) and execute it. The output will
demonstrate the usage of various collection interfaces and
their common operations.
Q2: How Does the Iterator Interface Work, and How Do You
Use It? Write a Java program that uses the Iterator
interface to traverse and print the elements of an
ArrayList.
Explanation
Creating an ArrayList:
An ArrayList named fruits is created and populated with
elements.
Getting an Iterator:
The iterator() method of the ArrayList class is called to obtain
an Iterator for the list.
Traversing the ArrayList:
A while loop is used to traverse the list. The hasNext()
method checks if there are more elements to iterate over.
The next() method retrieves the next element in the list.
Each element is printed to the console.
Running the Program
To run the program, copy the code into a Java file (e.g.,
IteratorExample.java) and execute it. The output will display
the elements of the ArrayList as they are traversed using the
Iterator interface.
Output
HashMap:
o Ordering: Does not maintain any order of the
keys. The elements are stored based on the hash of
the keys.
o Performance: Offers constant-time performance
for basic operations like get and put, assuming the
hash function disperses elements properly.
o Null Values: Allows one null key and multiple
null values.
LinkedHashMap:
o Ordering: Maintains a doubly-linked list running
through all of its entries. This ensures insertion-
order iteration, meaning the order in which keys
were inserted.
o Performance: Slightly slower than HashMap due
to the overhead of maintaining the linked list, but
still offers constant-time performance for basic
operations.
o Null Values: Allows one null key and multiple
null values.
TreeMap:
o Ordering: Implements the NavigableMap
interface and uses a Red-Black tree. It sorts the
keys according to their natural ordering or by a
specified comparator.
o Performance: Provides guaranteed log(n) time
cost for the containsKey, get, put, and remove
operations.
o Null Values: Does not allow null keys but allows
multiple null values.
Example Program
// LinkedHashMap
Map<String, Integer> linkedHashMap = new
LinkedHashMap<>();
linkedHashMap.put("Banana", 3);
linkedHashMap.put("Apple", 1);
linkedHashMap.put("Cherry", 2);
System.out.println("LinkedHashMap:");
printMap(linkedHashMap);
// TreeMap
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Banana", 3);
treeMap.put("Apple", 1);
treeMap.put("Cherry", 2);
System.out.println("TreeMap:");
printMap(treeMap);
}
Explanation
HashMap:
The elements are inserted without order.
Output order may vary each time the program is run.
LinkedHashMap:
Maintains insertion order.
Elements are printed in the order they were added.
TreeMap:
Maintains natural ordering of the keys (alphabetical order in
this case).
Elements are printed in sorted order by key.
To run the program, copy the code into a Java file (e.g.,
MapExample.java) and execute it. The output will
demonstrate the different ordering behavior of HashMap,
LinkedHashMap, and TreeMap.
Sample Output
HashMap:
Apple = 1
Banana = 3
Cherry = 2
LinkedHashMap:
Banana = 3
Apple = 1
Cherry = 2
TreeMap:
Apple = 1
Banana = 3
Cherry = 2
Q4: How Can You Sort a List Using Comparable and Comparator
Interfaces? Write a Java program that sorts a list of custom
objects using both Comparable and Comparator interfaces.
Example Program
Let's create a class Person with fields name and age. We will
then sort a list of Person objects using both Comparable and
Comparator interfaces.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
this.name = name;
this.age = age;
return name;
}
public int getAge() {
return age;
@Override
return this.name.compareTo(other.name);
@Override
Collections.sort(people);
System.out.println(person);
@Override
return Integer.compare(p1.getAge(),
p2.getAge());
};
Collections.sort(people, ageComparator);
System.out.println(person);
System.out.println(person);
}
}
Explanation
Person Class:
Implements the Comparable<Person> interface.
Overrides the compareTo method to provide natural ordering
by name.
Sorting using Comparable:
The Collections.sort(people) method sorts the list using the
natural ordering defined by the compareTo method.
The list is sorted by name in ascending order.
Sorting using Comparator:
A custom Comparator<Person> is defined to sort by age.
The Collections.sort(people, ageComparator) method sorts
the list using the custom comparator.
The list is sorted by age in ascending order.
Sorting using Comparator with Lambda:
A lambda expression is used to simplify the Comparator
implementation for sorting by age.
The list is again sorted by age in ascending order.
To run the program, copy the code into a Java file (e.g.,
SortingExample.java) and execute it. The output will
demonstrate how the list of Person objects is sorted using
both Comparable and Comparator interfaces.
Sample Output
Sorted by name using Comparable:
Person{name='Alice', age=30}
Person{name='Bob', age=25}
Person{name='Charlie', age=35}
Synchronization:
Null Values:
Performance:
Example Program
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
System.out.println("HashMap:");
printMap(hashMap);
// Hashtable example
Map<String, String> hashtable = new Hashtable<>();
hashtable.put("one", "1");
hashtable.put("two", "2");
hashtable.put("three", "3");
// Uncommenting the following lines will cause
NullPointerException
// hashtable.put(null, "nullValue"); // Does not allow null
key
// hashtable.put("four", null); // Does not allow null
value
System.out.println("Hashtable:");
printMap(hashtable);
// Synchronization difference
// HashMap is not thread-safe
Runnable hashMapTask = () -> {
for (int i = 0; i < 1000; i++) {
hashMap.put("key" + i, "value" + i);
}
};
// Hashtable is thread-safe
Runnable hashtableTask = () -> {
for (int i = 0; i < 1000; i++) {
hashtable.put("key" + i, "value" + i);
}
};
hashMapThread1.start();
hashMapThread2.start();
hashtableThread1.start();
hashtableThread2.start();
try {
hashMapThread1.join();
hashMapThread2.join();
hashtableThread1.join();
hashtableThread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Explanation
Null Handling:
Synchronization:
To run the program, copy the code into a Java file (e.g.,
MapExample.java) and execute it. The output will
demonstrate the differences between HashMap and Hashtable
in terms of null handling and synchronization.
Sample Output
HashMap:
null = nullValue
four = null
one = 1
three = 3
two = 2
Hashtable:
one = 1
three = 3
two = 2
Step-by-Step Implementation
Example Program
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
System.out.println("Original list:");
System.out.println(numbers);
Explanation
To run the program, copy the code into a Java file (e.g.,
CustomComparatorExample.java) and execute it. The output
will demonstrate the sorting of integers in descending order
using a custom comparator.
Sample Output
Original list:
[5, 1, 10, 3, 7]
Unit 5
Q1: What is Dependency Injection (DI) in Spring, and How
Does It Promote Loose Coupling? Write a Spring
application that demonstrates Dependency Injection.
Create a simple service and a controller where the service
is injected into the controller. Show how changing the
service implementation does not require modifying the
controller.
package com.example.di;
import org.springframework.stereotype.Service;
@Service
public class GreetingServiceImpl implements
GreetingService {
@Override
public String greet() {
return "Hello, World!";
}
}
package com.example.di;
import org.springframework.stereotype.Service;
@Service
public class GreetingServiceSpanishImpl implements
GreetingService {
@Override
public String greet() {
return "¡Hola, Mundo!";
}
}
package com.example.di;
import
org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class GreetingController {
private final GreetingService greetingService;
@Autowired
public GreetingController(GreetingService
greetingService) {
this.greetingService = greetingService;
}
package com.example.di;
import
org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplicat
ion;
import org.springframework.context.annotation.Primary;
@SpringBootApplication
public class SpringDiExampleApplication implements
CommandLineRunner {
@Autowired
public SpringDiExampleApplication(GreetingController
greetingController) {
this.greetingController = greetingController;
}
SpringApplication.run(SpringDiExampleApplication.class,
args);
}
@Override
public void run(String... args) throws Exception {
greetingController.sayGreeting();
}
}
package com.example.di;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
@Primary
@Service
public class GreetingServiceImpl implements
GreetingService {
@Override
public String greet() {
return "Hello, World!";
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-di-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Sample Output
Hello, World!
Switching Implementations
¡Hola, Mundo!
Project Structure
package com.example.beanscopes.services;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@Service
@Scope("singleton")
public class SingletonScopedService extends
UniqueIdentifierGenerator {
}
PrototypeScopedService.java
package com.example.beanscopes.services;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@Service
@Scope("prototype")
public class PrototypeScopedService extends
UniqueIdentifierGenerator {
}
RequestScopedService.java
package com.example.beanscopes.services;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import
org.springframework.web.context.annotation.RequestScope;
@Service
@RequestScope
public class RequestScopedService extends
UniqueIdentifierGenerator {
}
SessionScopedService.java
Package com.example.beanscopes.services;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import
org.springframework.web.context.annotation.SessionScope;
@Service
@SessionScope
public class SessionScopedService extends
UniqueIdentifierGenerator {
}
ApplicationScopedService.java
package com.example.beanscopes.services;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import
org.springframework.web.context.annotation.ApplicationSco
pe;
@Service
@ApplicationScope
public class ApplicationScopedService extends
UniqueIdentifierGenerator {
}
UniqueIdentifierGenerator.java
package com.example.beanscopes.services;
import java.util.UUID;
public UniqueIdentifierGenerator() {
this.id = UUID.randomUUID().toString();
}
ScopeController.java
package com.example.beanscopes.controllers;
import com.example.beanscopes.services.*;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.web.bind.annotation.GetMapping;
import
org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/scopes")
public class ScopeController {
@Autowired
private SingletonScopedService singletonScopedService;
@Autowired
private PrototypeScopedService prototypeScopedService;
@Autowired
private RequestScopedService requestScopedService;
@Autowired
private SessionScopedService sessionScopedService;
@Autowired
private ApplicationScopedService
applicationScopedService;
@GetMapping("/singleton")
public String getSingletonScope() {
return "Singleton Scope Bean ID: " +
singletonScopedService.getId();
}
@GetMapping("/prototype")
public String getPrototypeScope() {
return "Prototype Scope Bean ID: " +
prototypeScopedService.getId();
}
@GetMapping("/request")
public String getRequestScope() {
return "Request Scope Bean ID: " +
requestScopedService.getId();
}
@GetMapping("/session")
public String getSessionScope() {
return "Session Scope Bean ID: " +
sessionScopedService.getId();
}
@GetMapping("/application")
public String getApplicationScope() {
return "Application Scope Bean ID: " +
applicationScopedService.getId();
}
}
BeanScopesApplication.java
package com.example.beanscopes;
import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplicat
ion;
@SpringBootApplication
public class BeanScopesApplication {
public static void main(String[] args) {
SpringApplication.run(BeanScopesApplication.class,
args);
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-bean-scopes</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Running the Application
Sample Output
package com.example.demo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
package com.example.demo.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Around("@annotation(com.example.demo.annotation.L
ogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint
joinPoint) throws Throwable {
long start = System.currentTimeMillis();
package com.example.demo.service;
import com.example.demo.annotation.LogExecutionTime;
import org.springframework.stereotype.Service;
@Service
public class SampleService {
@LogExecutionTime
public String serve() throws InterruptedException {
Thread.sleep(2000); // Simulate a delay
return "Service is done!";
}
}
Example Controller
package com.example.demo.controller;
import com.example.demo.service.SampleService;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.web.bind.annotation.GetMapping;
import
org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
@Autowired
private SampleService sampleService;
@GetMapping("/serve")
public String serve() throws InterruptedException {
return sampleService.serve();
}
}
Q4: How Can You Build and Test RESTful Web Services
with Spring Boot? Create a Spring Boot application
with a REST controller that supports CRUD
operations. Include endpoints for GET, POST, PUT,
and DELETE requests. Write a simple test class to
verify the functionality of these endpoints.
Ans: Building and testing RESTful web services with
Spring Boot is a common task that involves creating a
REST controller to handle CRUD (Create, Read,
Update, Delete) operations and writing tests to verify
the functionality. Here’s how you can do it step-by-
step:
Step 1: Set Up the Spring Boot Application
package com.example.demo.model;
public Item() {}
this.id = id;
this.name = name;
this.description = description;
package com.example.demo.service;
import com.example.demo.model.Item;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Service
public class ItemService {
private List<Item> items = new ArrayList<>();
private Long nextId = 1L;
public List<Item> getAllItems() {
return items;
}
public Optional<Item> getItemById(Long id) {
return items.stream().filter(item ->
item.getId().equals(id)).findFirst();
}
public Item createItem(Item item) {
item.setId(nextId++);
items.add(item);
return item;
}
public Item updateItem(Long id, Item itemDetails) {
Optional<Item> optionalItem = getItemById(id);
if (optionalItem.isPresent()) {
Item item = optionalItem.get();
item.setName(itemDetails.getName());
item.setDescription(itemDetails.getDescription());
return item;
}
return null;
}
public void deleteItem(Long id) {
items.removeIf(item -> item.getId().equals(id));
}
}
Step 4: Create a REST Controller
Implement a REST controller to handle CRUD
operations.
package com.example.demo.controller;
import com.example.demo.model.Item;
import com.example.demo.service.ItemService;
import
org.springframework.beans.factory.annotation.Autowi
red;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/items")
public class ItemController {
@Autowired
private ItemService itemService;
@GetMapping
public List<Item> getAllItems() {
return itemService.getAllItems();
}
@GetMapping("/{id}")
public ResponseEntity<Item>
getItemById(@PathVariable Long id) {
Optional<Item> item =
itemService.getItemById(id);
if (item.isPresent()) {
return ResponseEntity.ok(item.get());
} else {
return ResponseEntity.notFound().build();
}
}
@PostMapping
public Item createItem(@RequestBody Item item) {
return itemService.createItem(item);
}
@PutMapping("/{id}")
public ResponseEntity<Item>
updateItem(@PathVariable Long id, @RequestBody
Item itemDetails) {
Item updatedItem = itemService.updateItem(id,
itemDetails);
if (updatedItem != null) {
return ResponseEntity.ok(updatedItem);
} else {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void>
deleteItem(@PathVariable Long id) {
itemService.deleteItem(id);
return ResponseEntity.noContent().build();
}
}
Step 5: Write Test Cases
Write a simple test class to verify the functionality of
the endpoints.
package com.example.demo;
import com.example.demo.model.Item;
import com.example.demo.service.ItemService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import
org.springframework.beans.factory.annotation.Autowi
red;
import
org.springframework.boot.test.autoconfigure.web.servl
et.AutoConfigureMockMvc;
import
org.springframework.boot.test.context.SpringBootTest
;
import org.springframework.http.MediaType;
import
org.springframework.test.web.servlet.MockMvc;
import java.util.List;
import static
org.springframework.test.web.servlet.request.MockMv
cRequestBuilders.*;
import static
org.springframework.test.web.servlet.result.MockMvc
ResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
public class ItemControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ItemService itemService;
@Autowired
private ObjectMapper objectMapper;
@BeforeEach
public void setup() {
itemService.getAllItems().clear();
itemService.createItem(new Item(null, "Test
Item", "This is a test item."));
}
@Test
public void shouldReturnAllItems() throws
Exception {
mockMvc.perform(get("/api/items"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].name").value("Te
st Item"));
}
@Test
public void shouldReturnItemById() throws
Exception {
List<Item> items = itemService.getAllItems();
Long itemId = items.get(0).getId();
mockMvc.perform(get("/api/items/{id}", itemId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Test
Item"));
}
@Test
public void shouldCreateNewItem() throws
Exception {
Item newItem = new Item(null, "New Item",
"This is a new item.");
mockMvc.perform(post("/api/items")
.contentType(MediaType.APPLICATION_J
SON)
.content(objectMapper.writeValueAsString(
newItem)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("New
Item"));
}
@Test
public void shouldUpdateItem() throws Exception {
List<Item> items = itemService.getAllItems();
Long itemId = items.get(0).getId();
Item updatedItem = new Item(null, "Updated
Item", "This is an updated item.");
mockMvc.perform(put("/api/items/{id}", itemId)
.contentType(MediaType.APPLICATION_J
SON)
.content(objectMapper.writeValueAsString(
updatedItem)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Upda
ted Item"));
}
@Test
public void shouldDeleteItem() throws Exception {
List<Item> items = itemService.getAllItems();
Long itemId = items.get(0).getId();
mockMvc.perform(delete("/api/items/{id}",
itemId))
.andExpect(status().isNoContent());
assert(itemService.getItemById(itemId).isEmpty());
}
}
package com.example.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@Service
public class MyService {
private static final Logger logger =
LoggerFactory.getLogger(MyService.class);
package com.example.demo;
import
org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootAppli
cation;
@SpringBootApplication
public class DemoApplication implements
CommandLineRunner {
@Autowired
private MyService myService;
@Override
public void run(String... args) throws Exception {
myService.performTask();
}
}
Explanation
application.properties Configuration:
logging.level.root=INFO: Sets the default logging level for
the entire application to INFO.
logging.level.com.example=DEBUG: Sets the logging
level to DEBUG for all classes in the com.example
package.
logging.level.com.example.demo.MyService=DEBUG:
Specifically sets the logging level to DEBUG for the
MyService class.
logging.pattern.console: (Optional) Customizes the log
format.
Service Class Logging:
The MyService class uses the SLF4J Logger to log
messages at different levels (DEBUG, INFO, WARN,
ERROR).
Main Application Class:
The DemoApplication class runs the performTask method
of MyService on application startup, demonstrating
logging in action.
By following these steps, you can configure and use
logging in a Spring Boot application for debugging and
monitoring purposes.
package com.example.demo;
import org.springframework.boot.SpringApplication;
import
org.springframework.boot.autoconfigure.SpringBootApplicat
ion;
@SpringBootApplication
public class DemoApplication {
import
org.springframework.web.bind.annotation.GetMapping;
import
org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
Configure Application Properties
Create application.properties under src/main/resources:
server.port=8080
Hello, World!