--- title: Java Development Cheatsheet tags: - java - tips author: name: Zihlu Wang email: real@zihluwang.me --- ## 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: ```java 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`: ```java a.stripTrailingZeros().equals(b.stripTrailingZeros()); // true ``` ### Comparing with zero Avoid `==` or `.equals(BigDecimal.ZERO)` to check for zero — prefer `compareTo`: ```java 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: ```java @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: ```java 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:** | Approach | When to use | |--------------------------|---------------------------------------------------| | `@EntityGraph` | Declarative, good for entity-specific fetch plans | | `JOIN FETCH` in `@Query` | Fine-grained control per query | | `@BatchSize` | Reduces N+1 to N/k+1 by batching | ```java // Option 1: EntityGraph @EntityGraph(attributePaths = {"roles", "permissions"}) Optional findById(long id); // Option 2: JOIN FETCH @Query("SELECT u FROM User u JOIN FETCH u.roles WHERE u.id = :id") Optional 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. ```java // 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: ```java @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. ```java @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: ```yaml 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`: ```java public interface UserRepository extends JpaRepository, JpaSpecificationExecutor { } // Usage Specification spec = (root, query, cb) -> { List 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 page = userRepository.findAll(spec, pageable); ```