Java Development Cheatsheet

Comparison for BigDecimal

In Java, comparing BigDecimal values requires care because equals and compareTo behave differently.

equals vs compareTo

BigDecimal#equals checks both value and scale, while BigDecimal#compareTo only checks value (ignoring scale). This means:

var a = new BigDecimal("100");     // scale = 0
var b = new BigDecimal("100.00");  // scale = 2

a.equals(b);    // false — different scale
a.compareTo(b); // 0     — same mathematical value

var c = new BigDecimal("200");

a.compareTo(c); // -1 (negative) — a is less than c
c.compareTo(a); //  1 (positive) — c is greater than a

Why this matters

The scale mismatch often appears when values come from different sources — e.g., parsing user input, reading from a database (DECIMAL(10,2) columns), or receiving JSON payloads. You might think two values are equal when equals says they aren't.

Rule of thumb

  • Use compareTo for numeric equality checks: a.compareTo(b) == 0

  • Use equals only when you mean "identical representation" (same value and same scale)

  • Use stripTrailingZeros() if you need to normalise scale before equals:

    a.stripTrailingZeros().equals(b.stripTrailingZeros()); // true

Comparing with zero

Avoid == or .equals(BigDecimal.ZERO) to check for zero — prefer compareTo:

if (value.compareTo(BigDecimal.ZERO) == 0) { ... }

How to Retrieve Data from a BlockingQueue

  • take() — retrieves and removes the head of the queue, waiting if necessary until an element becomes available.
  • poll() — retrieves and removes the head of the queue, or returns null if the queue is empty.
  • poll(long timeout, TimeUnit unit) — retrieves and removes the head of the queue, waiting up to the specified wait time if necessary for an element to become available. Returns null if the timeout expires.
  • peek() — retrieves but does not remove the head of the queue. Returns null if the queue is empty.

Spring Cloud Alibaba FAQs

How to prevent Nacos from creating a nacos folder in the user's home directory?

Add the following two configuration properties to specify the Nacos storage path:

  • JM.LOG.PATH
  • JM.SNAPSHOT.PATH

How to deal with Sentinel's scattered log files?

Add the configuration property csp.sentinel.log.dir to change Sentinel's log directory.

How to add Configuration Properties in JetBrains IntelliJ IDEA?

In JetBrains IntelliJ IDEA, click Edit Configurations… in the run configuration dropdown at the top right.

Click the Modify options button on the page, then add the properties you need to reset in the Override configuration properties table that appears below.

Spring Data JPA FAQs

How to fix the "Serializing PageImpl instances as-is not supported" warning?

Spring Data JPA warns about unstable JSON serialization of PageImpl. To resolve this, enable VIA_DTO serialization mode on your application's main class:

@EnableSpringDataWebSupport(pageSerializationMode =
    EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO)

Why does the first page return no results?

JPA pagination is zero-indexed. Page 0 is the first page. If your frontend sends page=1, you need to pass page - 1 to Spring Data:

Pageable pageable = PageRequest.of(requestPage - 1, pageSize);

How to avoid the N+1 query problem?

The N+1 problem occurs when JPA executes one query for the parent entity, then N additional queries for each child association.

Detection — look for repetitive SQL queries in the logs, or configure spring.jpa.properties.hibernate.generate_statistics=true to spot it.

Fixes:

ApproachWhen to use
@EntityGraphDeclarative, good for entity-specific fetch plans
JOIN FETCH in @QueryFine-grained control per query
@BatchSizeReduces N+1 to N/k+1 by batching
// Option 1: EntityGraph
@EntityGraph(attributePaths = {"roles", "permissions"})
Optional<User> findById(long id);

// Option 2: JOIN FETCH
@Query("SELECT u FROM User u JOIN FETCH u.roles WHERE u.id = :id")
Optional<User> findByIdWithRoles(@Param("id") long id);

findById vs getReferenceById — which one to use?

  • findById — hits the database immediately, returns the entity or Optional.empty(). Use this when you need the data.
  • getReferenceById — returns a lazy proxy without hitting the database. Throws EntityNotFoundException only when you access a non-existent proxy's properties. Use this when you only need the ID to set a foreign key relationship.
// Good: only need the user reference to set a FK
Post post = new Post();
post.setAuthor(userRepository.getReferenceById(userId));

How to fix LazyInitializationException?

This happens when you access a lazily-loaded association outside the persistence context (e.g., in a controller or serializer after the transaction has closed).

Solutions:

  1. Use JOIN FETCH or @EntityGraph to eagerly load needed associations.

  2. Use DTO projections — return only the fields you need instead of whole entities:

    @Query("SELECT new com.example.UserDto(u.id, u.name) FROM User u WHERE u.id = :id")
    UserDto findUserDtoById(@Param("id") long id);
  3. @Transactional(readOnly = true) on the service method — keep the session open for the entire method scope.

When should I use @Transactional(readOnly = true)?

Use @Transactional(readOnly = true) on read-only service methods for three benefits:

  • Hibernate skips dirty checking (no snapshots, less memory).
  • The JDBC driver may route to read replicas.
  • It documents the intent clearly.
@Service
public class UserService {

    @Transactional(readOnly = true)
    public UserDto getUser(long id) { ... }

    @Transactional
    public UserDto createUser(CreateUserRequest request) { ... }
}

save() vs saveAll() — which is faster for batch inserts?

saveAll() uses a single transaction and can benefit from JDBC batching. Configure the batch size:

spring:
  jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 20
        order_inserts: true
        order_updates: true

For large bulk inserts (thousands of rows), consider JdbcTemplate batch operations instead — Hibernate's entity management overhead is significant at that scale.

How to use dynamic queries with Specification?

For complex search forms with optional filters, use JpaSpecificationExecutor:

public interface UserRepository extends JpaRepository<User, Long>,
        JpaSpecificationExecutor<User> {
}

// Usage
Specification<User> spec = (root, query, cb) -> {
    List<Predicate> predicates = new ArrayList<>();
    if (name != null) {
        predicates.add(cb.like(root.get("name"), "%" + name + "%"));
    }
    if (status != null) {
        predicates.add(cb.equal(root.get("status"), status));
    }
    return cb.and(predicates.toArray(new Predicate[0]));
};

Page<User> page = userRepository.findAll(spec, pageable);
javatips