- HashTable
- HashMap
- IdentityMap
- EnumMap
- ConcurrentHashMap
- LinkedHashMap
- TreeMap
- WeakHashMap
- Collections.SynchronizedMap
internally
how things work internally ;)
Monday, July 4, 2022
Map implementations
Wednesday, June 29, 2022
Core Java Concepts
Cloning In Java
- Shallow copy vs Deep copy
- Techniques to achive
- Object clone method
- Copy contstructor
- Third party tools - Apache common langs, Google gson, Jackson
Immutable Object
Note that final only forbids us from changing the reference the variable holds, it doesn't protect us from changing the internal state of the object it refers to by using its public API:
- declare the class as final so it cannot be extended
- all class members should be private so they cannot be accessed outside of class
- shouldn't contain any setter methods to change the value of class members
- the getter method should return the copy of class members
- class members are only initialized using constructor
Java Generics
Java Serialization
- Classes that are eligible for serialization need to implement a special marker interface, Serializable.
- static fields belong to a class and are not serialized
- we can use the keyword transient to ignore class fields during serialization
- Inheritance : When a class implements the java.io.Serializable interface, all its sub-classes are serializable as well
- Composition : when an object has a reference to another object, these objects must implement the Serializable interface separately, or else a NotSerializableException will be thrown:
- Serial Version UID :
- The JVM associates a version (long) number with each serializable class
- We use it to verify that the saved and loaded objects have the same attributes, and thus are compatible on serialization.
- Any changes result in a different number, and can cause an InvalidClassException
- If a serializable class doesn't declare a serialVersionUID, the JVM will generate one automatically at run-time. However, it's highly recommended that each class declares its serialVersionUID, as the generated one is compiler dependent and thus may result in unexpected InvalidClassExceptions.
- If you're actually using serialization, it only matters if you plan on storing and retrieving objects using serialization directly. The serialVersionUID represents your class version, and you should increment it if the current version of your class is not backwards compatible with its previous version.
- it is good practice to provide the serialVersionUID value and update it after changes to the class so that we can have control over the serialization/deserialization processReferences :
Integer Cache
- Integer Cache was introduced in Java 5 in order to improve memory management.
- Integer Cache works only on auto boxing which means Conversion from a primitive type to an object reference
- By default keeps cache of range between -128 to 127. But this can be increased with
-XX: AutoBoxCacheMax=size parameter - Integer cache gives you the facility to cache other objects also for Example like Byte, Short, Long, Character etc.
Comparing Doubles
- it isn't as easy as comparing other primitive types
- As a matter of fact, it's problematic in many other languages, not only Java.
- Inaccuracy with comparisons using the == operator is caused by the way double values are stored in a computer's memory.
- we can't have an exact representation of most double values in our computers. They must be rounded to be saved
- The recommended algorithm to compare double values in plain Java is a threshold comparison method. In this case, we need to check whether the difference between both numbers is within the specified tolerance, commonly called epsilon:
double epsilon = 0.000001d;
assertThat(Math.abs(d1 - d2) < epsilon).isTrue(); - The smaller the epsilon's value, the greater the comparison accuracy. However, if we specify the tolerance value too small, we'll get the same false result as in the simple == comparison. In general, epsilon's value with 5 and 6 decimals is usually a good place to start.
- Third party libraries to compare doubles : Apache Commons Math, Guava, Junit
How to lose object in Map?
- Equals and hashCode methods implemented by keys are mutable
- Solution : to make keys immutable. If not possible, make sure keys are not changed
BitSet
- we can use BitSets to represent a vector of bits
- similar to boolean[] but takes less memory
- new boolean[1024] take 1 MB
- new BitSet(1024) takes 1024 bit, 168 bytes which is 130 KB
Sunday, June 19, 2022
Spring Concepts
Bean Scopes
- Singleton
- Prototype
- Request
- Session
- Application
- WebSocket
Injecting dependencies
- Constructor based
- Setter based
- Field based
- This approach might look simpler and cleaner, but we don't recommend using it because it has a few drawbacks such as:
- This method uses reflection to inject the dependencies, which is costlier than constructor-based or setter-based injection.
- It's really easy to keep adding multiple dependencies using this approach. If we were using constructor injection, having multiple arguments would make us think that the class does more than one thing, which can violate the Single Responsibility Principle.
Injecting Prototype into Singleton
- Every request to get prototype object from singleton bean will return same instance of prototype
- In order to return different prototype bean there are different ways
- Injecting ApplicationContext
- Method Injection with @Lookup annotation
- javax.inject API
Using bean outside of Spring context
- Implement
ApplicationContextAware
- Inject into static field
- Then call context.getBean method
private static ApplicationContext ctx;
private static final String USER_SERVICE = "userServiceBean";
@Overridepublic void setApplicationContext(ApplicationContext appContext)throws BeansException {
ctx = appContext;
}public static ApplicationContext getApplicationContext() {
return ctx;
}
public static UserService getUserService(){
return ctx.getBean(USER_SERVICE);
}
BeanFactory vs ApplicationContext
- BeanFactory loads beans on demand (Lazy loading)
- ApplicationContext loads all beans at startup (Easger loading)
- BeanFactory only when memory consumption is critical
- ApplicationContext provides
- Annotation based dependency injection
- Event publication
- Messaging (i18n)
- Easy integration with Spring AOP feature
@ExceptionHandler and Global Handler
@Autowire
- Allows Spring to resolve and inject collaborating beans into our bean
- by declaring all the bean dependencies in a Spring configuration file, Spring container can autowire relationships between collaborating beans. This is called Spring bean autowiring
- Resolving bean conflicts using @Qualifier annotation
- @Qualifier helps to avoid ambiguity
- @SpringBootApplication - is equivalent to using @Configuration, @EnableAutoConfiguration, and @ComponentScan. When we run Spring Boot application, it will automatically scan the components in the current package and its sub-packages. Thus it will register them in Spring's Application Context, and allow us to inject beans using @Autowired.
- We can use autowiring on properties, setters, and constructors
- @Autowired(required = false) - makes bean optional. Otherwise throws NoSuchBeanDefinitionException
Design Patterns in Spring
- Singleton - The singleton pattern is a mechanism that ensures only one instance of an object exists per application. This pattern can be useful when managing shared resources or providing cross-cutting services, such as logging. By default, Spring creates all beans as singletons.
- Factory Method pattern - The factory method pattern entails a factory class with an abstract method for creating the desired object. For example : BeanFactory, ApplicationContextFactory are factory patterns
- Proxy - Proxies are a handy tool in our digital world, and we use them very often outside of software (such as network proxies). In code, the proxy pattern is a technique that allows one object — the proxy — to control access to another object — the subject or service. For example : @Transactioin annotation is creating proxy object
- Template - In many frameworks, a significant portion of the code is boilerplate code. For example, when executing a query on a database, the same series of steps must be completed: Establish a connection, Execute query, Perform cleanup, Close the connection - These steps are an ideal scenario for the template method pattern.
The template method pattern is a technique that defines the steps required for some action, implementing the boilerplate steps, and leaving the customizable steps as abstract.
For example : JDBC template, JMS, JPA templates
Spring Events
- The event class should extend ApplicationEvent if we're using versions before Spring Framework 4.2. As of the 4.2 version, the event classes no longer need to extend the ApplicationEvent class.
- The publisher should inject an ApplicationEventPublisher object.
- The listener should implement the ApplicationListener interface.
- We can write our Custom events
- Spring allows us to create and publish custom events that by default are synchronous. This has a few advantages, such as the listener being able to participate in the publisher’s transaction context.
- In some cases, publishing events synchronously isn't really what we're looking for — we may need async handling of our events.We can turn that on in the configuration by creating an ApplicationEventMulticaster bean with an executor. The event, the publisher and the listener implementations remain the same as before, but now the listener will asynchronously deal with the event in a separate thread.
- Existing framework events - ContextRefreshedEvent, ContextStartedEvent, RequestHandledEvent etc
@Async
- annotating a method of a bean with @Async will make it execute in a separate thread. In other words, the caller will not wait for the completion of the called method.
- enabling asynchronous processing with Java configuration.by adding the @EnableAsync to a configuration class
- Additional options :
- annotation – By default, @EnableAsync detects Spring's @Async annotation and the EJB 3.1 javax.ejb.Asynchronous. We can use this option to detect other, user-defined annotation types as well.
- mode indicates the type of advice that should be used — JDK proxy based or AspectJ weaving.
- proxyTargetClass indicates the type of proxy that should be used — CGLIB or JDK. This attribute has effect only if the mode is set to AdviceMode.PROXY.
- order sets the order in which AsyncAnnotationBeanPostProcessor should be applied. By default, it runs last so that it can take into account all existing proxies.
- @Async has two limitations
- It must be applied to public methods only
- Self-invocation — calling the async method from within the same class — won't work.
The reasons are simple: The method needs to be public so that it can be proxied. And self-invocation doesn't work because it bypasses the proxy and calls the underlying method directly. - Methods With Void Return Type
- Methods With Return Type - by wrapping the actual return in the Future
- By default, Spring uses a SimpleAsyncTaskExecutor to actually run these methods asynchronously. But we can override the defaults at two levels: the application level or the individual method level.
- Override the Executor at the Method Level
- Override the Executor at the Application Level
- Exception Handling -When a method return type is a Future, exception handling is easy. Future.get() method will throw the exception. But if the return type is void, exceptions will not be propagated to the calling thread. So, we need to add extra configurations to handle exceptions.
- create a custom async exception handler by implementing AsyncUncaughtExceptionHandler interface
- handleUncaughtException() method is invoked when there are any uncaught asynchronous exceptions
- override the getAsyncUncaughtExceptionHandler() method to return our custom asynchronous exception handler
Hiberante
Map entity to multiple tables
- Annotate table with @SecondayTable(name ="author_details") annotation.
- Provide table name in @Column(table ="author_details") annotation
- Benefit to split entity and its details into separate tables. Like author and author details
Reference
Difference between First level and Second Level cache
Key | First level cache | Second level cache | |
---|---|---|---|
Basic | First level cache is a session level cache and it is always associated with session level object | Second level cache is session factory level cache and it is available across all sessions | |
Enabled | It is enabled by default. | It is not enabled by default. | |
Availability | It is available for a session | It is available across all session. | |
Configuration | No Extra configuration required | We have to decide which |
Different Entity states in JPA and Hibernate
N+1 Problem
- there is car and wheel table --> SELECT * FROM Cars;
- in order to fetch wheel car we will hit db --> SELECT * FROM Wheel WHERE CarId = ?
- Solution to this JOIN tables (or Entity Graph)
Hibernate Fetch types
- FetchMode JOIN : Eager loading which loads all the collections and relations at the same time.
- FetchMode SELECT(default) : Lazy loading which loads the collections and relations only when required.
- FetchMode SELECT with Batch Size : Fetch upto “N”collections or entities(“Not number of records”)
- FetchMode SUBSELECT : Group the collection of an entity into a Sub-Select query.
Load() vs Get()
load() | get() |
---|---|
Only use load() method if you are sure that the object exists. | If you are not sure that the object exist, then use one of get() methods. |
load() method will throw an exception if the unique id is not found in the database. | get() method will return null if the unique id is not found in the database. |
load() just returns a proxy by default and database won't be hit until the proxy is first invoked. | get() will hit the database immediately. |
Dirty Checking
- Hibernate has a feature of checking all managed entity properties. Whenever an entity is loaded through hibernate, it makes an additional copy of that whole entity object along with the all entity's property values
- So even if only one property of the persistent object is changed, Hibernate will still check all managed entities. It detects which objects have been modified and then calls update statements on all updated objects.
- Hibernate monitors all persistent objects. At the end of a unit of work, it knows which objects have been modified. Then it calls update statement on all updated objects. This process of monitoring and updating only objects that have been changed is called automatic dirty checking in hibernate.
- Within the Persistence Context, Hibernate has a copy of all persistent objects that were loaded from the database. It compares these persistent objects with these objects to detect the objects that have been modified or are dirty. This is the default implementation.
Query Cache and Second Level Cache
- If a query under execution has previously cached results, then no SQL statement is sent to the database. Instead the query results are retrieved from the query cache, and then the cached entity identifiers are used to access the second level cache.
- If the second level cache contains data for a given Id, it re-hydrates the entity and returns it. If the second level cache does not contain the results for that particular Id, then an SQL query is issued to load the entity from the database.
Hibernate Inheritance Mapping
- MappedSuperclass – the parent classes, can't be entities
- Single Table – The entities from different classes with a common ancestor are placed in a single table.
- Joined Table – Each class has its table, and querying a subclass entity requires joining the tables.
- Table per Class – All the properties of a class are in its table, so no join is required.
Monday, June 13, 2022
Spring Transaction Management
- Transaction Propagation : Propagation defines our business logic's transaction boundary. Spring manages to start and pause a transaction according to our propagation setting. (in other words : Defines how transactions relate to each other)
- REQUIRED : Code will always run in a transaction. Creates a new transaction or reuses one if available.
- REQUIRED_NEW : Code will always run in a new transaction. Suspends the current transaction if one exists.
- SUPPORTS
- MANDATORY
- NEVER
- NOT_SUPPORTED
- NESTED
- Transaction Isolation : solation is one of the common ACID properties: Atomicity, Consistency, Isolation, and Durability. Isolation describes how changes applied by concurrent transactions are visible to each other. (in other words : Defines the data contract between transactions)
Isolation Levels - DEFAULT
- READ_UNCOMMITTED : Allows dirty reads
- READ_COMMITTED : Does not allow dirty reads
- REPEATABLE_READ : If a row is read twice in the same transaction, the result will always be the same
- SERIALIZABLE : Performs all transactions in a sequence
Each isolation level prevents zero or more concurrency side effects on a transaction:Dirty read: read the uncommitted change of a concurrent transaction Nonrepeatable read: get different value on re-read of a row if a concurrent transaction updates the same row and commits Phantom read: get different rows after re-execution of a range query if another transaction adds or removes some rows in the range and commits
References
Baeldung : link
Stackoverflow : link
Transactions with Spring and JPA : link