Skip to main content

Java

Sending Emails in Spring Boot 3: A Complete Guide

Email isn't just for newsletters; it's the backbone of modern application workflows. From sending critical account verification links to delivering daily reports, a reliable email system is non-negotiable. Luckily, Spring Boot makes sending emails clean, configurable, and production-ready with its powerful JavaMailSender interface. In this comprehensive guide, we'll walk you through everything you need to know to become an email pro with Spring Boot 3. We'll cover sending plain text and rich HTML emails, handling attachments, and supercharging your system with asynchronous processing for blazing-fast performance. Let's get started. 1. Setting the Stage: Project Setup First things first, we need to tell our Spring Boot project that we intend to use its mail-sending capabilities. We do this by adding a single dependency to our pom.xml file.

Tail vs Non-Tail Recursion in Java: Definitions, Examples, and When It Matters

Quick summary Tail recursion is when a function’s recursive call is the last operation before returning, enabling tail-call elimination in languages/runtimes that support it; non-tail recursion performs additional work after the recursive call returns. In Java, tail-call optimization is not guaranteed by the JVM, so tail recursion does not reduce stack usage unless transformed to iterative code; still, converting non-tail recursion to tail style can make iterative conversion straightforward and avoid stack overflow in production. What is recursion? Recursion is a divide-and-conquer technique where a function calls itself with smaller inputs until a base case is reached, with the JVM allocating a stack frame for each invocation; deep recursion risks StackOverflowError if not controlled. Each call must eventually reduce the problem and hit a base case to terminate safely and predictably.

Java DelayQueue — A Specialized BlockingQueue for Delayed Elements

In concurrent programming, often you need to schedule work or tasks to happen after a delay: e.g. timeouts, scheduled retries, delayed tasks, rate limiting, delayed processing, etc. Java’s java.util.concurrent package provides a handy queue for such use cases — DelayQueue — which accepts elements that become available only after a specified delay. In this post, we will explore: What is a DelayQueue The Delayed interface How DelayQueue works internally Key methods and behaviors A simple producer/consumer example Real-world use cases & caveats Summary 1. What is DelayQueue DelayQueue<E extends Delayed> is an unbounded blocking queue whose elements must implement the Delayed interface. An element can be retrieved (via take() or poll(...)) only when its delay has expired. Until then, it stays “dormant” inside the queue. Some important characteristics: The head of the queue is the delayed element whose expiration (delay) is earliest (i.e. whose delay will expire first). If no element has expired yet, poll() returns null, and take() blocks until an element becomes available. The queue is unbounded — operations like put() or offer() never block (unless out of memory). The queue uses internal locking (ReentrantLock) for thread safety. Iterators over the queue are weakly consistent and do not guarantee ordered traversal. In short: DelayQueue is like a priority queue (ordered by expiration time) combined with blocking/waiting semantics.

Java BitSet Explained (with Practical Examples)

When developing applications, there are situations where we need to represent and manipulate large collections of binary values – typically true or false. Storing these values in a conventional data structure like a boolean[] or a HashSet<Integer> can be inefficient in terms of memory and speed. Java provides the BitSet class in the java.util package to address this problem. BitSet represents a sequence of bits that can grow dynamically and provides built-in methods for bit-level manipulation. In this article, we will cover: Introduction to BitSet Internal representation and advantages Common operations Basic usage example Real-world example: Attendance tracking Bitwise operations (AND, OR, XOR, ANDNOT) Performance comparison with boolean[] and HashSet Conclusion

Java Interview Preparation Guide

A categorized Java interview prep guide covering core Java, collections, concurrency, Streams/Optional, and Spring basics, with annotated code, comparison tables, and notes on why each topic trips candidates up.

Overview of New Features in Java 19

Java 19 has just been released — September 20, 2022 — as a short-term support release on the six-month cadence the Java platform moved to starting with Java 9. It is not an LTS release, but that does not make it uninteresting: Java 19 ships 7 JEPs, several of them highly anticipated by the Java community. Virtual Threads, in particular, represent one of the most significant changes to the Java concurrency model in years. The headline features span concurrency, pattern matching, native interop, and platform reach. Three features arrive as preview (complete but seeking feedback), one as an incubator module (early-stage API), and the rest are fully stable additions. Because several require flags to enable, we will also cover exactly how to turn them on — both on the command line and in Maven. This article walks through each major Java 19 feature with code examples and explains the preview and incubator status so you know what you can try today and what to expect in future releases.

Apache Commons Collection – MultiValuedMap

Apache Commons Collections MultiValuedMap compared against Guava Multimap and a vanilla nested Map of Lists, with a realistic form-validation-errors use case, annotated code, sample output, and FAQs.