Click ⭐ if you like the project. Pull Request is highly appreciated. Follow me @AltafJava for technical updates.
| No. | Question |
|---|---|
| 1 | How to read value from custom properties file in spring? |
| 2 | What is MissingRequestHeaderException? |
| No. | Question |
|---|---|
| 1 | Can you explain the internal architecture of Kafka? |
| 2 | How do you manage a Kafka broker failure? |
| 3 | Apache Kafka Question 1 |
| No. | Question |
|---|---|
| 1 | What is "Death by a thousand cuts" problem in software development? |
-
public interface functionalInterface { void read(int a); }
public class FunctionalInterfaceImpl { public static void main(String[] args) { functionalInterface f = (a) -> System.out.println("Value is: " + a); f.read(10); } }
-
In Java 8,
mapandflatMapare both methods in the Stream interface used for transforming elements. However, they serve different purposes and operate in distinct ways.-
map: The
mapmethod transforms each element of a stream into another object using the provided function. It applies the function to each element of the stream independently and returns a new stream containing the transformed elements. The function passed to themap()operation returns a single value for each input, resulting in a one-to-one mapping. Essentially,map()is used solely for transformation, producing a stream of values.List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); List<Integer> mapResult = list.stream().map(x -> x * 2).collect(Collectors.toList()); System.out.println(mapResult); // prints [2, 4, 6, 8, 10]
-
flatMap: The
flatMapmethod transforms each element of a stream into a stream of objects and then combines all those streams into a single stream. It is particularly useful when we want to flatten a stream of collections or arrays into a single stream of elements. The function we pass to theflatMap()operation can return an arbitrary number of values for each input, facilitating a one-to-many mapping. This method performs both transformation and flattening, producing a stream of stream values, and is used for both transformation and mapping.List<List<Integer>> list = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5, 6)); List<Integer> flatMapResult = list.stream().flatMap(Collection::stream).collect(Collectors.toList()); System.out.println(flatMapResult); // prints [1, 2, 3, 4, 5, 6]
-
-
List<Student> student = Arrays.asList( new Student(1, "Alice", 85), new Student(2, "Bob", 92), new Student(3, "Charlie", 78), new Student(4, "David", 95) );
int totalMarks = student.stream().mapToInt(Student::getMarks).sum();
-
List<Student> student = Arrays.asList( new Student(1, "Alice", 85), new Student(2, "Bob", 92), new Student(3, "Charlie", 78), new Student(4, "David", 95) );
List<Student> sortedStudents = student.stream() .sorted(Comparator.comparing(Student::getMarks).reversed()) .collect(Collectors.toList());
List<Student> sortedStudents = students.stream() .sorted((emp1, emp2) -> emp2.getMarks().compareTo(emp1.getMarks())) .collect(Collectors.toList());
-
Employee emp1 = new Employee(1, "Alice", 85) Employee emp2 = new Employee(1, "Alice", 85) boolean b1 = emp1 == emp2 boolean b2 = emp1.equals(emp2)
Answer:
b1will befalsebecause==checks for reference equality, andemp1andemp2are two distinct objects.b2will befalsebecause the defaultequals()method in Object also checks for reference equality. Unless equals() is overridden in the Employee class to compare the attributes, it behaves the same as==. -
static int except() { try { int a = 10; return 1; } catch(Exception e) { return 2; } finally { return 3; } }
Answer: The
finallyblock will always execute, regardless of whether an exception is thrown or not. In this case, thefinallyblock returns3, which overrides the return value of1in thetryblock. So, the output will be3.- In this case, the try block executes and returns 1.
- Before the method actually returns 1, the finally block is executed.
- The finally block contains a return statement that returns 3, which overrides the previous return value.
-
int[] arr = { 2, 9, 4, 7, 1, 6 }; int min = Arrays.stream(arr).min().getAsInt(); System.out.println("Minimum value: " + min);
Output:
Minimum value: 1 -
- What is the term used to describe the ability of an object to take many forms?
-
a) Inheritance b) Encapsulation c) Polymorphism d) Abstraction
Answer: c) Polymorphism
- In Java, which type of polymorphism is achieved through method overriding?
-
a) Compile-time polymorphism b) Run-time polymorphism c) Static polymorphism d) Dynamic polymorphism
Answer: d) Dynamic polymorphism
- Which principle of object-oriented programming (OOP) is closely related to polymorphism?
-
a) Inheritance b) Encapsulation c) Abstraction d) Composition
Answer: a) Inheritance
- Which of the following is NOT a thread-safe collection in Java?
-
a) ArrayList b) ConcurrentHashMap c) CopyOnWriteArrayList d) LinkedBlockingQueue
Answer: a) ArrayList
-
List<Employee> employees = Arrays.asList( new Employee(1, "Alice", 95000, 25), new Employee(2, "Bob", 85000, 30), new Employee(3, "Charlie", 90000, 35), new Employee(4, "David", 92000, 40) );
Optional<String> name = employees.stream() .filter(emp -> emp.getSalary() > 90000) .min(Comparator.comparing(Employee::getSalary)) .map(Employee::getName); System.out.println(name.orElse("No employee found"));
Output:
David -
In Java, there are several ways to create objects:
-
Using the
newkeyword:- The most common way to create an object in Java is by using the
newkeyword followed by a constructor call. - For example:
Employee emp = new Employee();
- The most common way to create an object in Java is by using the
-
Using `Class.forName() method:
- We can create an object using the
Class.forName()method by providing the fully qualified class name. - For example:
Employee emp = (Employee) Class.forName("com.example.Employee").newInstance();
- We can create an object using the
-
Using `clone() method:
- We can create a copy of an existing object using the
clone()method. - For example:
Employee emp = (Employee) existingEmp.clone();
- We can create a copy of an existing object using the
-
Using `Deserialization:
- We can create an object by deserializing it from a file or stream using Java serialization.
- For example:
ObjectInputStream in = new ObjectInputStream(new FileInputStream("employee.ser")); Employee emp = (Employee) in.readObject();
-
Using `Object creation using newInstance() method:
- We can create an object using the
newInstance()method of theClassclass. - For example:
Employee emp = Employee.class.newInstance();
- We can create an object using the
-
-
An immutable class in Java is a class whose objects cannot be modified once they are created. The state of an immutable object remains constant throughout its lifetime, and any attempt to modify its state results in the creation of a new object with the modified state. Immutable classes are thread-safe, as they are inherently free. Example:
public final class ImmutableClass { private final int id; private final String name; public ImmutableClass(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public String getName() { return name; } }
In the above example, the
ImmutableClassis declared asfinalto prevent subclassing. The class has two private final fieldsidandname, which are initialized through the constructor. The class provides getter methods to access the fields but does not provide any setter methods to modify the state of the object. By making the fieldsprivateandfinal, the class ensures that the state of the object cannot be changed once it is created. Any attempt to modify the object's state will result in the creation of a new object with the modified state.What will happen if we have a
Listor any mutable field in an immutable class?If an immutable class contains a
Listor any mutable variable, the immutability of the class is compromised because the List can be modified even if the class itself is immutable. To maintain immutability, the List should be defensively copied in the constructor or getter method to prevent external modification. For example:public final class ImmutableClass { private final int id; private final String name; private final List<String> items; public ImmutableClass(int id, String name, List<String> items) { this.id = id; this.name = name; this.items = new ArrayList<>(items); } public int getId() { return id; } public String getName() { return name; } public List<String> getItems() { return new ArrayList<>(items); } }
In the above example, the
itemsList is defensively copied in the constructor to ensure that the original List is not modified externally. ThegetItems()method also returns a copy of the List to prevent direct access to the internal state of the object. -
A marker interface in Java is an interface that does not contain any methods or fields but is used to mark or tag classes that implement it. Marker interfaces are used to provide metadata or marker information about classes at runtime. To create a custom marker interface in Java, follow these steps:
-
Define the marker interface:
Create an interface without any methods or fields. This interface will serve as the marker interface.
public interface MyMarkerInterface { // Marker interface }
-
Implement the marker interface:
Implement the marker interface in the classes that need to be marked or tagged.
public class MyClass implements MyMarkerInterface { // Class implementation }
-
Check if a class implements the marker interface:
Use the
instanceofoperator to check if a class implements the marker interface.MyClass obj = new MyClass(); if (obj instanceof MyMarkerInterface) { System.out.println("Class implements the marker interface"); }
By following these steps, we can create a custom marker interface in Java and use it to mark or tag classes that implement the interface.
-
-
class X { void foo(int a) { System.out.println("ONE"); } void foo(double d) { System.out.println("TWO"); } } class Y extends X { @Override void foo(double d) { System.out.println("THREE"); } } public class MainClass { public static void main(String[] args) { new Y().foo(100); } }
Answer: The output of the code will be
ONE. The methodfoo(int a)in classXis not overridden in classY, so the methodfoo(int a)from classXwill be called whennew Y().foo(100)is executed. The methodfoo(double d)in classXis overloaded, not overridden, in classY. Overloading is determined at compile time based on the reference type, while overriding is determined at runtime based on the object type. Since the reference type isY, the overloaded methodfoo(double d)in classXis not considered during method resolution. Therefore, the output will beONE.
-
To read values from a custom properties file in Spring, we can use the
@PropertySourceannotation to specify the location of the properties file and the@Valueannotation to inject the property values into Spring beans.Example:
-
Create a custom properties file (
custom.properties):app.name=SpringApp app.version=1.0
-
Load the custom properties file in Spring configuration class:
@Configuration @PropertySource("classpath:custom.properties") public class AppConfig { @Value("${app.name}") private String appName; @Value("${app.version}") private String appVersion; @Bean public AppInfo appInfo() { return new AppInfo(appName, appVersion); } }
-
-
MissingRequestHeaderExceptionis an exception in Spring that is thrown when a required header is missing from an HTTP request. This exception occurs when a controller method expects a specific header to be present in the request but the header is not provided.Example:
@GetMapping("/user") public ResponseEntity<User> getUserDetails(@RequestHeader("Authorization") String token) { // Controller logic }
In the above example, the
getUserDetailsmethod expects anAuthorizationheader to be present in the request. If theAuthorizationheader is missing, aMissingRequestHeaderExceptionwill be thrown.To handle this exception, we can use
@ExceptionHandlerin a controller advice or handle it within the controller method itself.@ExceptionHandler(MissingRequestHeaderException.class) public ResponseEntity<String> handleMissingRequestHeaderException(MissingRequestHeaderException ex) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Required header is missing: " + ex.getHeaderName()); }
-
The
@Transientannotation in JPA is used to indicate that a field or property should not be persisted to the database. When an entity class is mapped to a database table, all its fields are persisted by default. However, there may be scenarios where certain fields should not be stored in the database, such as derived or transient fields that are calculated at runtime.Example:
import javax.persistence.Transient; @Entity public class Employee { @Id private Long id; private String name; @Transient private int age; // Getters and setters }
In the above example, the
agefield is marked with the@Transientannotation, indicating that it should not be persisted to the database. Theagefield is considered transient and will not be included in the database schema when theEmployeeentity is mapped to a database table. The@Transientannotation can be applied to fields, properties, or methods in an entity class to exclude them from database persistence.Examples:
-
Calculated Fields: Sometimes, we might have fields whose values are calculated based on other persisted fields. These calculated fields do not need to be stored in the database because their values can be derived at runtime.
@Entity public class Order { @Id private Long id; private BigDecimal price; private BigDecimal taxRate; @Transient private BigDecimal totalPrice; // Calculated as price + (price * taxRate) public BigDecimal getTotalPrice() { return price.add(price.multiply(taxRate)); } }
-
Logging or Debugging Information: Fields used for logging or debugging purposes, which are useful during development or troubleshooting but do not need to be part of the persistent state.
@Entity public class User { @Id private Long id; private String username; @Transient private String debugMessage; // Used only for debugging, not persisted }
-
Security or Sensitive Information: Sometimes, you might want to temporarily hold sensitive information like passwords or tokens in an entity for processing or validation, but you do not want these details to be stored in the database.
@Entity public class Account { @Id private Long id; private String accountName; @Transient private String temporaryAuthToken; // Sensitive information not to be persisted }
-
-
The N+1 problem is a common performance issue that occurs when using an ORM framework like Hibernate to fetch data from a relational database. It arises when an entity is associated with a collection of child entities (one-to-many or many-to-many relationship), and the ORM framework generates N+1 SQL queries to fetch the associated child entities.
Example:
Consider the following entities
AuthorandBookwith a one-to-many relationship:@Entity public class Author { @Id private Long id; private String name; @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) private List<Book> books; } @Entity public class Book { @Id private Long id; private String title; @ManyToOne private Author author; }
If we fetch a list of authors along with their books using Hibernate, the N+1 problem occurs when Hibernate executes N+1 SQL queries to fetch the associated books for each author. For example, if there are 10 authors, Hibernate will execute 1 query to fetch the authors and then 10 additional queries to fetch the books for each author, resulting in a total of 11 queries (N+1).
Solution:
To avoid the N+1 problem in Hibernate, we can use fetch strategies like
FetchType.EAGER,JOIN FETCHor@BatchSizeto fetch the associated entities eagerly or in batches. By specifying the fetch strategy in the query or mapping annotations, we can optimize the data retrieval process and reduce the number of SQL queries executed by Hibernate.Example:
-
Using FetchType.EAGER:
@Entity public class Author { @Id private Long id; private String name; @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) private List<Book> books; }
-
Using JOIN FETCH:
List<Author> authors = entityManager.createQuery("SELECT a FROM Author a JOIN FETCH a.books", Author.class).getResultList();
-
Using @BatchSize:
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL) @BatchSize(size = 10) private List<Book> books;
By using appropriate fetch strategies and tuning the mappings, we can mitigate the N+1 problem in Hibernate and improve the performance of data retrieval operations.
-
-
Both
CrudRepositoryandJpaRepositoryinterfaces in Spring Data provide methods for deleting entities by their IDs. However, there are differences in the behavior and performance of thedeleteAllByIds()method inCrudRepositoryand thedeleteAllByIdsInBatch()method inJpaRepository.-
CrudRepository's deleteAllByIds():
- The
deleteAllByIds()method inCrudRepositorydeletes entities one by one in a loop, resulting in multiple individual delete queries being executed for each ID. - This method is suitable for deleting a small number of entities or when the number of entities to be deleted is not known in advance.
- It is less efficient for bulk deletion operations as it generates multiple delete queries, leading to increased database round trips and performance overhead.
- If the provided id is not present in the database, it will throw
EmptyResultDataAccessException.
public interface UserRepository extends CrudRepository<User, Long> { void deleteAllByIds(List<Long> ids); }
- The
-
JpaRepository's deleteAllByIdsInBatch():
- The
deleteAllByIdsInBatch()method inJpaRepositoryperforms batch deletion of entities using a single delete query with anINclause containing the list of IDs to be deleted. - This method is optimized for bulk deletion operations and is more efficient than
deleteAllByIds()for deleting a large number of entities. - It reduces the number of database round trips and improves performance by executing a single batch delete query for all the specified IDs.
- If the provided id not present in the database, it will not throw any exception.
public interface UserRepository extends JpaRepository<User, Long> { @Modifying @Query("DELETE FROM User u WHERE u.id IN :ids") void deleteAllByIdsInBatch(@Param("ids") List<Long> ids); }
- The
-
Usage:
- Use
deleteAllByIds()inCrudRepositoryfor deleting a small number of entities or when the number of entities to be deleted is not large. - Use
deleteAllByIdsInBatch()inJpaRepositoryfor bulk deletion of entities when deleting a large number of entities efficiently.
- Use
By choosing the appropriate method based on the number of entities to be deleted and the performance requirements, we can optimize the deletion process and improve the efficiency of bulk deletion operations in Spring Data repositories.
-
-
-
Repository Interface:
- The
Repositoryinterface is the base interface for all Spring Data repositories. - It is a marker interface and does not provide any methods.
- It is used to enable the Spring Data infrastructure to detect repository interfaces and create their implementations.
- The
-
CrudRepository Interface:
- The
CrudRepositoryinterface extends theRepositoryinterface and provides generic CRUD (Create, Read, Update, Delete) operations for entity classes. - It includes methods like:
save(S entity): Saves a given entity.saveAll(Iterable<S> entities): Saves all given entities.findById(ID id): Retrieves an entity by its ID.existsById(ID id): Checks if an entity exists by its ID.findAll(): Returns all entities.findAllById(Iterable<ID> ids): Returns all entities with the given IDs.count(): Returns the count of entities.deleteById(ID id): Deletes an entity by its ID.delete(T entity): Deletes a given entity.deleteById(Iterable<? extends ID> ids): Deletes all entities with the given IDs.deleteAll(Iterable<? extends S> entities): Deletes all given entities.deleteAll(): Deletes all entities.
- The
-
PagingAndSortingRepository Interface:
- The
PagingAndSortingRepositoryinterface extends theCrudRepositoryinterface and provides additional methods for pagination and sorting of query results. - It includes methods like:
findAll(Sort sort): Returns all entities sorted by the given options.findAll(Pageable pageable): Returns aPageof entities meeting the paging restriction provided in thePageableobject.
- The
-
JpaRepository Interface:
- The
JpaRepositoryinterface extends thePagingAndSortingRepositoryinterface and provides JPA-specific operations. - It includes all the methods of
CrudRepositoryandPagingAndSortingRepositoryand adds JPA-specific methods such as:saveAndFlush(S entity): Saves an entity and flushes changes instantly.deleteAllInBatch(Iterable<T> entities): Deletes all entities in a batch.deleteAllByIdInBatch(Iterable<T> ids): Deletes all entities with the given IDs in a batch.deleteAllInBatch(): Deletes all entities in a batch.getOne(ID id): Retrieves a reference to the entity with the given ID.findAll(): Returns all entities.findAll(Sort sort): Returns all entities sorted by the given options.findAllById(Iterable<ID> ids): Returns all entities with the given IDs.
- The
Scenarios for Choosing Each Interface:
- Use
Repositoryif we only need to mark an interface as a repository without any specific methods. - Use
CrudRepositoryfor basic CRUD operations without the need for pagination or sorting. - Use
PagingAndSortingRepositorywhen we need to retrieve entities with pagination and sorting capabilities. - Use
JpaRepositorywhen we require advanced JPA-specific features in addition to CRUD operations, pagination, and sorting.
-
-
Input:
{ 2,9,4,7,1,6 }public class ReverseArray { public static void main(String[] args) { int[] arr = { 2, 9, 4, 7, 1, 6 }; System.out.println("Before: " + Arrays.toString(arr)); for (int i = 0; i < arr.length / 2; i++) { int temp = arr[i]; arr[i] = arr[arr.length - 1 - i]; arr[arr.length - 1 - i] = temp; } System.out.println("After: " + Arrays.toString(arr)); } }
Output:
Before: [2, 9, 4, 7, 1, 6] After: [6, 1, 7, 4, 9, 2] -
String str = "programming"; Map<Character, Integer> charFrequency = new HashMap<>(); for (char c : str.toCharArray()) { charFrequency.put(c, charFrequency.getOrDefault(c, 0) + 1); } System.out.println(charFrequency);
Using Java 8 Stream API:
String str = "programming"; Map<Character, Long> charFrequency = str.chars() .mapToObj(c -> (char) c) .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); System.out.println(charFrequency);
Output:
{p=1, r=2, o=1, g=2, a=1, m=2, i=1, n=1} -
public static String lengthOflongestNonRepeatingSubstring(String str) { int max = 0; Map<Character, Integer> map = new LinkedHashMap<>(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); if (map.containsKey(ch)) { i = map.get(ch); map.clear(); } else { map.put(ch, i); } max = Math.max(max, map.size()); } return max; }
String str = "abcabcbb"; System.out.println(lengthOflongestNonRepeatingSubstring(str));
Output:
3 -
public static String longestNonRepeatingSubstring(String str) { int maxLength = 0; int start = 0; String longestSubstring = ""; Map<Character, Integer> map = new HashMap<>(); for (int i = 0; i < str.length(); i++) { char ch = str.charAt(i); if (map.containsKey(ch)) { start = Math.max(start, map.get(ch) + 1); } map.put(ch, i); if (i - start + 1 > maxLength) { maxLength = i - start + 1; longestSubstring = str.substring(start, i + 1); } } return longestSubstring; }
String str = "abcabcbb"; System.out.println(longestNonRepeatingSubstring(str));
Output:
abc -
To find the 3rd largest number in a list of integers with O(n) running time complexity in Java, we can use a single pass algorithm. The idea is to traverse the list once and keep track of the top three largest unique numbers using three variables. At the end of the traversal, the third-largest number will be stored in the third variable.
public static void main(String[] args) { int[] arr = { 8, 7, 2, 1, 0, 9, 6 }; int kthLargest = findThirdLargest(arr); System.out.println("3rd largest element is: " + kthLargest); } public static int findThirdLargest(int[] nums) { int first = Integer.MIN_VALUE, second = Integer.MIN_VALUE, third = Integer.MIN_VALUE; for (int num : nums) { if (num > first) { third = second; second = first; first = num; } else if (num > second && num < first) { third = second; second = num; } else if (num > third && num < second) { third = num; } } return third; }
Output:
3rd largest element is: 7If we want to find the kth largest element in an array, we can use the QuickSelect algorithm, which is an efficient selection algorithm based on the partitioning technique of the quicksort algorithm.
public static void main(String[] args) { int[] arr = { 8, 7, 2, 1, 0, 9, 6 }; int k = 3; // To find the 3rd largest number int kthLargest = quickSelect(arr, 0, arr.length - 1, arr.length - k); System.out.println(k + "th largest element is: " + kthLargest); } private static int quickSelect(int[] arr, int low, int high, int k) { if (low <= high) { int partitionIndex = partition(arr, low, high); if (partitionIndex == k) { return arr[partitionIndex]; } else if (partitionIndex < k) { return quickSelect(arr, partitionIndex + 1, high, k); } else { return quickSelect(arr, low, partitionIndex - 1, k); } } return Integer.MIN_VALUE; // This should never hit if k is within the bounds of the array } private static int partition(int[] arr, int low, int high) { int pivot = arr[low]; int i = low, j = high; do { while (i <= high && arr[i] <= pivot) { i++; } while (arr[j] > pivot) { j--; } if (i < j) { swap(arr, i, j); } } while (i < j); swap(arr, low, j); return j; } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }
Output:
3th largest element is: 7 -
To find all subarrays in an array of integers whose sum is equal to a given target sum (e.g., 5), we can use a sliding window approach. The idea is to maintain a window that expands and contracts based on the sum of elements within the window. We can use two pointers (start and end) to represent the window and move them accordingly to find subarrays with the desired sum.
public static void findSubarraysWithSum(int[] arr, int targetSum) { int start = 0, end = 0, sum = 0; while (end < arr.length) { sum += arr[end]; while (sum > targetSum) { sum -= arr[start]; start++; } if (sum == targetSum) { System.out.println("Subarray with sum 5 found: " + Arrays.toString(Arrays.copyOfRange(arr, start, end + 1))); } end++; } } public static void main(String[] args) { int[] arr = {1, 2, 3, 2, 1, 4, 1}; int targetSum = 5; findSubarraysWithSum(arr, targetSum); }
Output:
Subarray with sum 5 found: [2, 3] Subarray with sum 5 found: [3, 2] Subarray with sum 5 found: [1, 4] Subarray with sum 5 found: [4, 1] -
int [] arr1 = {23,2,87,63,26}; int [] arr2 = {45,87,62,2};Answer:
public static void findCommonElements(int[] arr1, int[] arr2) { Set<Integer> set = new HashSet<>(); for (int num : arr1) { set.add(num); } System.out.print("Common elements: "); for (int num : arr2) { if (set.contains(num)) { System.out.print(num + " "); } } }
int[] arr1 = {23, 2, 87, 63, 26}; int[] arr2 = {45, 87, 62, 2}; findCommonElements(arr1, arr2);
Output:
Common elements: 87 2 -
int[] arr1 = {1, 3, 4, 5}; int[] arr2 = {3, 4, 1, 5}; // Expected output: true int[] arr1 = {1, 9, 4, 5}; int[] arr2 = {3, 4, 1, 5}; // Expected output: falseAnswer:
public static boolean areEqualArrays(int[] arr1, int[] arr2) { if (arr1.length != arr2.length) { return false; } Map<Integer, Integer> map = new HashMap<>(); for (int num : arr1) { map.put(num, map.getOrDefault(num, 0) + 1); } for (int num : arr2) { if (!map.containsKey(num) || map.get(num) == 0) { return false; } map.put(num, map.get(num) - 1); } return true; }
int[] arr1 = {1, 3, 4, 5}; int[] arr2 = {3, 4, 1, 5}; System.out.println(areEqualArrays(arr1, arr2)); // true
int[] arr1 = {1, 9, 4, 5}; int[] arr2 = {3, 4, 1, 5}; System.out.println(areEqualArrays(arr1, arr2)); // false
Output:
true false -
- Which data structure organizes elements in a sorted manner and supports efficient search, insertion, and deletion operations?
- a) Array b) Stack c) Queue d) Binary Search Tree
Answer: d) Binary Search Tree
- Which data structure uses a dynamic array to store elements and allows for random access to elements?
- a) Stack b) Queue c) ArrayList d) LinkedList
Answer: c) ArrayList
- What is the time complexity of searching for an element in an ArrayList?
- a) O(1) b) O(log n) c) O(n) d) O(n^2)
Answer: c) O(n)
- Which of the following data structures stores elements in a sorted order?
- a) HashSet b) LinkedList c) Stack d) TreeMap
Answer: d) TreeMap
- Which data structure provides constant time complexity for inserting, deleting, and searching elements?
- a) LinkedList b) Stack c) Queue d) HashMap
Answer: d) HashMap
-
String s = "focusNEARgarden"; // Output should be: "fecasNAERgurdon"
Answer:
public static String reverseVowels(String s) { char[] chars = s.toCharArray(); String vowels = "aeiouAEIOU"; int left = 0, right = chars.length - 1; while (left < right) { while (left < right && !vowels.contains(chars[left] + "")) { left++; } while (left < right && !vowels.contains(chars[right] + "")) { right--; } if (left < right) { char temp = chars[left]; chars[left] = chars[right]; chars[right] = temp; left++; right--; } } return new String(chars); }
String s = "focusneargarden"; System.out.println(reverseVowels(s));
Output:
fecasNAERgurdon -
Question: You are given a 0-indexed array nums consisting of positive integers. You can choose two indices
iandj, such thati != j, and the sum of digits of the numbernums[i]is equal to that ofnums[j]. Return the maximum value ofnums[i] + nums[j]that you can obtain over all possible indicesiandjthat satisfy the conditions.Input: nums = [18,43,36,13,7] Output: 54 Explanation: Pairing: 18 and 36 -> 1+8 + 3+6 = 9 + 9 = 18 43 and 7 -> 4+3 + 7 = 7 + 7 = 14 18 and 43 -> 1+8 + 4+3 = 9 + 7 = 16 36 and 13 -> 3+6 + 1+3 = 9 + 4 = 13 18 and 7 -> 1+8 + 7 = 9 + 7 = 16 Maximum sum: 54 (from pairing 18 and 36 -> 1+8 + 3+6 = 9 + 9 = 18)Answer:
public static int maxSumPairs(int[] nums) { int[] digitSums = new int[100]; for (int num : nums) { int sum = 0; while (num > 0) { sum += num % 10; num /= 10; } digitSums[sum]++; } int maxSum = 0, remaining = 0; for (int i = 0; i < 100; i++) { maxSum += i * (digitSums[i] / 2); remaining += digitSums[i] % 2; } return maxSum + remaining / 2; }
int[] nums = {18, 43, 36, 13, 7}; System.out.println(maxSumPairs(nums));
Output:
54Source: LeetCode
-
int a = 10, b = 20; a = a + b; b = a - b; a = a - b; System.out.println("a: " + a + ", b: " + b);
Output:
a: 20, b: 10
-
Employee Table id name city Address Table id city
Answer:
UPDATE employee e JOIN address a ON e.id = a.id SET e.city = a.city;
-
Question: Given an Employees table with columns first_name, last_name, and salary, write an SQL query to find all employees who have a salary greater than any employee with the first name 'Nawab'.
SELECT * FROM Employees WHERE salary > (SELECT MAX(salary) FROM Employees WHERE first_name = 'Nawab');
-
id | name | category ---|---------|--------- 1 | steak | meat 2 | cake | sweets 3 | steak | meat 4 | chicken | meat 5 | cake | sweets 6 | cake | sweetsAnswer:
SELECT name, category, COUNT(*) FROM shop GROUP BY name, category HAVING COUNT(*) > 1;
Output:
name | category | count -----|----------|------ steak| meat | 2 cake | sweets | 3 -
Employee Table id | name | city_id ---|------|-------- 1 | John | 1 2 | Alex | 2 3 | Bob | 1 City Table id | city ---|----- 1 | Delhi 2 | MumbaiAnswer:
SELECT e.name FROM employee e JOIN city c ON e.city_id = c.id WHERE c.city = 'Delhi';
Output:
John Bob -
Employee Table id | name | salary | dept_id ---|------|--------|-------- 1 | John | 5000 | 1 2 | Alex | 6000 | 2 3 | Bob | 7000 | 1 4 | Mike | 8000 | 2 Department Table id | name ---|----- 1 | HR 2 | ITAnswer:
SELECT e.name, e.salary, d.name AS department FROM employee e JOIN department d ON e.dept_id = d.id WHERE e.salary > (SELECT AVG(salary) FROM employee WHERE dept_id = e.dept_id);
Output:
Bob | 7000 | HR Mike| 8000 | IT
-
Apache Kafka is a distributed streaming platform that is designed to handle large-scale data processing (with high throughput, fault tolerance, and scalability) and real-time event streaming. The internal architecture of Kafka consists of several key components that work together to provide high throughput, fault tolerance, and scalability. Here is an overview of the internal architecture of Kafka:
-
Broker: A Kafka cluster consists of one or more brokers, which are individual servers that store and manage topics and partitions. Each broker is responsible for handling client requests, storing data, and replicating data across the cluster.
- Leader and Follower: For each partition, one broker is elected as the leader, and one or more brokers are followers. The leader handles all read and write requests, while followers replicate the data to ensure fault tolerance.
-
Topic: A topic is a logical channel to which data is sent and from which data is read. Topics are categories or feed names to which messages are published. Topics are divided into partitions to allow for parallel processing and distribution of messages across multiple brokers.
-
Partition: Each topic is split into multiple partitions. Partitions allow Kafka to scale horizontally and provide parallelism. Each partition is an ordered, immutable sequence of records that are continually appended.
-
Producer: Producers are client applications that send records to a Kafka topic. Producers can choose which partition to send records to within a topic (usually using a key for partitioning).
- Acknowledgment: Producers can choose to receive acknowledgments from brokers after successfully writing messages to Kafka. Acknowledgments can be synchronous or asynchronous, depending on the desired level of reliability.
-
Consumer: Consumers are client applications that subscribe to topics and consume messages from Kafka partitions. Consumers read messages from partitions in the order they were produced. Consumers can be part of a consumer group, where each record is delivered to one consumer in the group, ensuring load balancing and fault tolerance.
- Consumer Group: A consumer group is a group of consumers that work together to consume messages from one or more topics. Each consumer in a group is assigned a subset of partitions to read from, enabling parallel processing and load balancing.
- Offset Management: Consumers track their progress by storing the offset of the last message they have read, allowing them to resume reading from the correct position after a restart.
- Consumer Rebalancing: Kafka automatically rebalances partitions among consumers in a consumer group when new consumers join or existing consumers leave the group.
- Consumer Offset Commitment: Consumers can commit offsets to Kafka to indicate that they have successfully processed messages. This allows consumers to resume reading from the last committed offset in case of failure.
-
ZooKeeper: ZooKeeper is used by Kafka for cluster coordination, metadata management, and leader election. ZooKeeper maintains information about brokers, topics, partitions, and consumer groups, ensuring consistency and synchronization across the Kafka cluster.
-
Replication: Kafka uses replication to ensure fault tolerance and data durability. Each partition is replicated across multiple brokers, with one broker serving as the leader and the others as followers. Replication allows Kafka to recover from broker failures and maintain data availability.
- In-Sync Replicas (ISR): Kafka maintains a set of in-sync replicas (ISRs) for each partition, which are replicas that are up-to-date with the leader. ISRs are used to ensure data consistency and fault tolerance.
-
Log Segments: Kafka stores messages in log segments, which are sequential files on disk. Each partition consists of multiple log segments, and older log segments are periodically compacted and deleted to manage disk space efficiently.
-
Offset: An offset is a unique identifier assigned to each message within a partition. Consumers track their progress by storing the offset of the last message they have read, allowing them to resume reading from the correct position after a restart.
-
Controller: One of the brokers in a Kafka cluster is designated as the controller. The controller is responsible for administrative tasks like partition assignment, leader election, and reassigning partitions in case of broker failures. The controller ensures the overall health and stability of the Kafka cluster. If the controller fails, another broker is elected as the new controller.
+-------------------------+ | ZooKeeper | +-----------+-------------+ | | v +-------------------+--------------------+ | Kafka Cluster (Brokers) | | | | +---------+ +---------+ +---------+ | | | Broker 1| | Broker 2| | Broker 3| | | +----+----+ +----+----+ +----+----+ | | | | | | +------+-------------+-------------+------+ | | | +-------v------+ +----v-------+ +---v-------+ | Topic A | | Topic B | | Topic C | +--------------+ +------------+ +-----------+ | Part. 0 | Part. 1 | Part. 2 | Part. 0 | ... | +---------+ +-------+ +-------+ +-------+-----+ -
-
Managing a Kafka broker failure involves taking appropriate steps to ensure the availability and reliability of the Kafka cluster. When a broker fails, it can impact the overall performance and data replication of the cluster. Here are some strategies to manage a Kafka broker failure:
-
Monitoring and Alerting: Implement monitoring tools to detect broker failures and set up alerts to notify administrators when a broker goes down. Monitoring tools can track metrics like CPU usage, memory consumption, disk space, and network traffic to identify potential issues.
Example: Prometheus, Grafana, Nagios, Datadog.
-
Replication Factor: Configure the replication factor for topics to ensure data redundancy across multiple brokers. By setting a replication factor of at least 2 or 3, Kafka can maintain multiple copies of data across brokers, allowing for data recovery in case of a broker failure.
-
Broker Reassignment: If a broker fails, Kafka can automatically reassign the partitions hosted on the failed broker to other healthy brokers in the cluster. This process is known as partition reassignment and helps maintain data availability and fault tolerance.
-
Broker Replacement: In the event of a permanent broker failure, replace the failed broker with a new broker to restore the cluster's capacity and performance. The replacement broker should have the same configuration and storage capacity as the failed broker to maintain consistency.
-
Data Recovery: If data loss occurs due to a broker failure, Kafka can recover data from the replicated partitions on other brokers. By leveraging the replication factor and data retention policies, Kafka can restore lost data and maintain data integrity.
-
Cluster Scaling: To prevent performance degradation during a broker failure, scale the Kafka cluster horizontally by adding more brokers. A larger cluster with additional brokers can distribute the workload and improve fault tolerance, reducing the impact of individual broker failures.
-
Backup and Disaster Recovery: Implement backup and disaster recovery strategies to protect data in case of catastrophic failures. Regularly back up Kafka data and configurations, and establish disaster recovery procedures to restore the cluster in the event of a major outage.
-
-
Question: A Kafka topic has 100 messages distributed equally across 10 partitions. If there are only 4 consumers subscribed to this topic, explain how the messages will be consumed by the consumers. How will Kafka manage the distribution of partitions among the consumers?
Answer:
Partition Assignment: Kafka will distribute the partitions among the 4 consumers as evenly as possible. Since there are 10 partitions, the most even distribution will have 2 consumers consuming from 3 partitions each, and the other 2 consumers consuming from 2 partitions each.
Message Consumption: Each consumer will independently consume messages from the partitions assigned to it. Given the messages are evenly distributed, each partition has 10 messages, leading to a scenario where 2 consumers will process 30 messages each (from 3 partitions), and the other 2 consumers will process 20 messages each (from 2 partitions).
Parallel Processing: All 4 consumers will process their assigned messages in parallel, increasing the throughput and efficiency of message processing compared to having a single consumer.
Consumer Group Coordination: Kafka ensures that within a consumer group, each partition is only consumed by one consumer, preventing duplicate processing of messages. If a consumer fails or is added to the group, Kafka will rebalance the partitions among the available consumers to ensure continued parallel processing.
-
"Death by a thousand cuts" is a metaphor used in software development to describe the accumulation of small, seemingly insignificant issues or problems that, when combined, can lead to significant negative consequences or failure of a project. These small issues, if left unaddressed, can gradually erode the quality, performance, or maintainability of the software, resulting in a situation where the software becomes increasingly difficult to maintain, enhance, or scale. The term highlights the importance of addressing minor issues promptly and maintaining a focus on quality throughout the development process to prevent the accumulation of problems that can lead to project failure. It emphasizes the need for attention to detail, proactive issue resolution, and continuous improvement to avoid the "death by a thousand cuts" scenario.
Example: Ignoring code quality, not following coding standards, not addressing technical debt, lack of code reviews, not fixing bugs promptly, etc. can contribute to the "death by a thousand cuts" problem.