<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Liriel</title>
    <description>The latest articles on DEV Community by Liriel (@lirielc).</description>
    <link>https://dev.to/lirielc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4003118%2Fbdffb4ad-a004-421c-a5d1-6c3077136d6f.jpg</url>
      <title>DEV Community: Liriel</title>
      <link>https://dev.to/lirielc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lirielc"/>
    <language>en</language>
    <item>
      <title>Java 27: What Now? 7 Changes Every Developer Should Know</title>
      <dc:creator>Liriel</dc:creator>
      <pubDate>Fri, 18 Sep 2026 17:07:50 +0000</pubDate>
      <link>https://dev.to/lirielc/java-27-what-now-7-changes-every-developer-should-know-3m33</link>
      <guid>https://dev.to/lirielc/java-27-what-now-7-changes-every-developer-should-know-3m33</guid>
      <description>&lt;p&gt;Java 27 is here, but it is not the kind of release that asks you to relearn the language or rewrite your application. Most of its important changes happen behind the scenes: Java can use memory more efficiently, choose a different strategy for cleaning unused objects, protect network connections against future attacks, and produce safer diagnostic recordings.&lt;/p&gt;

&lt;p&gt;If terms such as &lt;em&gt;JVM&lt;/em&gt;, &lt;em&gt;garbage collector&lt;/em&gt;, or &lt;em&gt;JEP&lt;/em&gt; are unfamiliar, do not worry. We will translate each one into practical consequences.&lt;/p&gt;

&lt;p&gt;Released on September 15, 2026, Java 27 contains nine JEPs. It is a &lt;strong&gt;non-LTS release&lt;/strong&gt;; Java 25 remains the latest Long-Term Support release. In simple terms, Java 27 is a useful release to test and learn from, while companies that prioritize years of vendor support may prefer to remain on Java 25.&lt;/p&gt;

&lt;p&gt;Here are the seven changes that deserve your attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, what exactly was updated?
&lt;/h2&gt;

&lt;p&gt;“Java” can refer to three related things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Java language&lt;/strong&gt; is the syntax you write: classes, records, &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;switch&lt;/code&gt;, and so on.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;JDK&lt;/strong&gt; is the development kit containing the compiler, command-line tools, libraries, and the runtime.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;JVM&lt;/strong&gt; is the virtual machine that executes compiled Java code and manages resources such as memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Java 27 changes all three, but its biggest improvements are in the JDK and JVM. A &lt;strong&gt;JEP&lt;/strong&gt;, or &lt;em&gt;JDK Enhancement Proposal&lt;/em&gt;, is the public design document for a significant JDK change.&lt;/p&gt;

&lt;p&gt;Feature status is equally important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Final&lt;/strong&gt; means the feature is supported as a normal part of the platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preview&lt;/strong&gt; means developers can test the feature, but it may still change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incubator&lt;/strong&gt; means an experimental API is available for feedback and is even less settled.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. G1 is now the default GC in every environment
&lt;/h2&gt;

&lt;p&gt;Java creates objects in memory while processing work. When they are no longer needed, a &lt;strong&gt;garbage collector (GC)&lt;/strong&gt; finds their memory and makes it available again—automatic housekeeping for the application.&lt;/p&gt;

&lt;p&gt;Java has several collectors because workloads have different priorities. Serial GC can suit very small applications. &lt;strong&gt;G1&lt;/strong&gt;, short for Garbage-First, divides memory into regions and cleans promising regions first, balancing throughput with predictable pauses.&lt;/p&gt;

&lt;p&gt;G1 was already the normal choice on server-class machines. Java 27 removes the remaining environment-dependent selection: if you do not explicitly choose a collector, HotSpot uses &lt;strong&gt;G1 everywhere&lt;/strong&gt;, including small machines and containers where Serial GC could previously be selected.&lt;/p&gt;

&lt;p&gt;For a beginner, the practical message is simple: &lt;strong&gt;your code will continue to work, but its performance profile may change&lt;/strong&gt;. A service might use CPU differently, pause for different amounts of time, or keep a different amount of memory available.&lt;/p&gt;

&lt;p&gt;Before upgrading, record the collector used by the current deployment and compare it with Java 27 under a representative load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-XX&lt;/span&gt;:+PrintCommandLineFlags &lt;span class="nt"&gt;-version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The safest approach is to compare Java 27 with your current JDK under realistic traffic rather than assuming that a newer default is automatically better for every workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Smaller object headers become the default
&lt;/h2&gt;

&lt;p&gt;An object contains more than your declared fields. The JVM attaches a &lt;strong&gt;header&lt;/strong&gt; with internal runtime information. Imagine a package: your data is the product, while the header is the shipping label.&lt;/p&gt;

&lt;p&gt;Compact Object Headers move from an optional capability to the default HotSpot object layout. On 64-bit architectures, that label can shrink from &lt;strong&gt;96 bits to 64 bits&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The saving on one object is tiny. Across millions, it can mean a smaller heap, better use of the CPU cache, and less memory for the GC to scan. Applications creating many small objects benefit most.&lt;/p&gt;

&lt;p&gt;Your source code does not need to change. Still, agents, profilers, JNI code, or libraries that assume an object layout should be tested with the Java 27 build you plan to deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. TLS 1.3 gets hybrid post-quantum key exchange
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TLS&lt;/strong&gt; is the security protocol behind HTTPS. A client and server first perform a handshake to agree on encryption keys. Today's techniques are safe against current computers, but future quantum computers could threaten some of them.&lt;/p&gt;

&lt;p&gt;Java 27 adds hybrid TLS 1.3 groups that combine conventional elliptic-curve cryptography with the post-quantum ML-KEM algorithm.&lt;/p&gt;

&lt;p&gt;The traditional algorithm protects traffic today; ML-KEM adds protection against future quantum attacks. This counters &lt;em&gt;harvest now, decrypt later&lt;/em&gt;: recording encrypted traffic now to attack it years later.&lt;/p&gt;

&lt;p&gt;Applications using Java's standard &lt;code&gt;javax.net.ssl&lt;/code&gt; APIs can benefit automatically when the other side also supports the new negotiation. Most developers do not need to call a new method. Platform teams should still test load balancers, proxies, external security providers, and any tool that inspects TLS handshakes.&lt;/p&gt;

&lt;p&gt;Java 27 also enables TLS 1.3 certificate compression with &lt;code&gt;zlib&lt;/code&gt; by default, reducing the size of certificate chains exchanged during a handshake.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. JFR redacts sensitive data before it leaves the process
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Java Flight Recorder (JFR)&lt;/strong&gt; is a flight recorder for a Java application. It collects low-overhead information about CPU, memory, threads, and garbage collection to explain slow or unstable behavior.&lt;/p&gt;

&lt;p&gt;The problem is that diagnostic data can accidentally contain secrets. Java 27 addresses this by redacting sensitive command-line arguments, environment-variable values, and system-property values &lt;strong&gt;inside the running process&lt;/strong&gt;, before the recording is written or streamed.&lt;/p&gt;

&lt;p&gt;That is a meaningful improvement for commands such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-Ddb&lt;/span&gt;.password&lt;span class="o"&gt;=&lt;/span&gt;secret &lt;span class="nt"&gt;-Dapi&lt;/span&gt;.key&lt;span class="o"&gt;=&lt;/span&gt;token &lt;span class="nt"&gt;-jar&lt;/span&gt; app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redaction is enabled by default and can be extended with application-specific filters. This reduces the chance that a password or API key ends up in a recording shared with another team. It is still better not to pass secrets on the command line at all. JFR redaction is a safety net, not a replacement for a secret manager.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The most exciting APIs are still not final
&lt;/h2&gt;

&lt;p&gt;Java 27 continues several long-running experiments. Here is what they mean without the jargon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structured Concurrency&lt;/strong&gt; groups related tasks. If loading a profile and recent orders in parallel fails, the group can cancel and report them as one operation instead of leaving work behind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primitive types in patterns&lt;/strong&gt; makes values such as &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;long&lt;/code&gt;, and &lt;code&gt;double&lt;/code&gt; work more naturally with pattern matching and &lt;code&gt;switch&lt;/code&gt;. The long-term goal is fewer awkward differences between primitive values and objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy Constants&lt;/strong&gt; delay expensive initialization until a value is actually requested. A large lookup table, for example, does not need to slow application startup if no request ever uses it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PEM encodings&lt;/strong&gt; give Java a standard way to read and write the familiar &lt;code&gt;-----BEGIN CERTIFICATE-----&lt;/code&gt; format used for cryptographic keys and certificates.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Vector API&lt;/strong&gt; describes one operation over several numbers at once. The JIT can translate it into CPU instructions useful for images, scientific computing, and machine learning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These features are worth exploring, but their status matters. Preview code requires explicit flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javac &lt;span class="nt"&gt;--enable-preview&lt;/span&gt; &lt;span class="nt"&gt;--release&lt;/span&gt; 27 Main.java
java &lt;span class="nt"&gt;--enable-preview&lt;/span&gt; Main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flags prevent accidental dependence on unfinished features. Preview and incubating APIs can change or disappear, so use them in controlled projects unless your maintenance policy accepts that cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Production diagnostics get more useful
&lt;/h2&gt;

&lt;p&gt;Production debugging requires inspecting the JVM that is actually running, not merely the expected configuration.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jcmd&lt;/code&gt; gains a command that prints the active security properties of a running JVM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jcmd &amp;lt;pid&amp;gt; VM.security_properties
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;&amp;lt;pid&amp;gt;&lt;/code&gt; is the operating-system process ID of the Java application. &lt;code&gt;VM.info&lt;/code&gt; and fatal-error logs also report the number of open &lt;strong&gt;file descriptors&lt;/strong&gt;. A file descriptor represents an open file, socket, or similar resource; leaking too many can cause the dreaded &lt;code&gt;Too many open files&lt;/code&gt; failure.&lt;/p&gt;

&lt;p&gt;One compatibility detail can break monitoring pipelines: numeric fields in JSON thread dumps, including thread IDs and the PID, are now JSON numbers rather than strings. The output declares &lt;code&gt;"formatVersion": 2&lt;/code&gt;. If you parse these dumps, test the parser before rollout.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Migration includes removals and behavior changes
&lt;/h2&gt;

&lt;p&gt;Every platform eventually removes obsolete behavior. Beginners can treat this section as a checklist for build and platform teams; most ordinary application code will not use these features directly.&lt;/p&gt;

&lt;p&gt;Java 27 removes several pieces of accumulated legacy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The experimental JVMCI and bundled Graal JIT are gone. This does &lt;strong&gt;not&lt;/strong&gt; mean the wider GraalVM project has disappeared.&lt;/li&gt;
&lt;li&gt;Several obsolete JVM verification and class-GC flags are removed.&lt;/li&gt;
&lt;li&gt;Linux's &lt;code&gt;VFORK&lt;/code&gt; process-launch mechanism is removed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ThreadPoolExecutor.finalize()&lt;/code&gt; is removed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HttpServer&lt;/code&gt; changes from string-prefix matching to path-prefix matching. A context at &lt;code&gt;/foo&lt;/code&gt; matches &lt;code&gt;/foo/bar&lt;/code&gt;, but no longer &lt;code&gt;/foobar&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ServiceLoader&lt;/code&gt; now consistently wraps linkage failures in &lt;code&gt;ServiceConfigurationError&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build plugins, agents, platforms, and older libraries are more likely to depend on these details. Successful compilation alone does not prove an upgrade is safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical upgrade checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Confirm your support policy.&lt;/strong&gt; Java 27 is not LTS; decide whether you are evaluating, experimenting, or deploying.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inventory JVM flags.&lt;/strong&gt; Search container images, deployment manifests, CI jobs, and startup scripts for removed or obsolete options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark with production-like traffic.&lt;/strong&gt; Pay special attention to the G1 switch, heap behavior, startup, tail latency, and memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test infrastructure boundaries.&lt;/strong&gt; Exercise TLS proxies, custom providers, monitoring agents, native integrations, and thread-dump parsers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate final features from previews.&lt;/strong&gt; Do not accidentally make &lt;code&gt;--enable-preview&lt;/code&gt; a hidden production dependency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run compatibility tools and the full test suite.&lt;/strong&gt; Unit tests alone rarely expose runtime, packaging, and observability issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a rollback path.&lt;/strong&gt; Record the JDK build, flags, images, and baseline metrics used by the previous deployment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  So, should you upgrade?
&lt;/h2&gt;

&lt;p&gt;For most teams, Java 27 is best viewed as an &lt;strong&gt;evaluation release with unusually practical runtime improvements&lt;/strong&gt;. G1 everywhere and Compact Object Headers can improve deployment behavior without source changes. Post-quantum TLS and JFR redaction make safe behavior the default. The preview APIs show where Java is heading, but they are not yet stable contracts.&lt;/p&gt;

&lt;p&gt;If you are on Java 25 LTS, there is no need to move simply because 27 exists. Install it in CI, run your services under realistic load, and use what you learn to prepare for the next releases. If you already track every six-month release, Java 27 is a compelling upgrade—provided you test the defaults you did not explicitly choose.&lt;/p&gt;

&lt;p&gt;The real story of Java 27 is not flashy syntax. It is a JVM that uses memory more efficiently, exposes safer diagnostics, and prepares network security for a very different future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oracle.com/java/technologies/javase/27all-relnotes.html" rel="noopener noreferrer"&gt;Consolidated JDK 27 Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/27/docs/api/index.html" rel="noopener noreferrer"&gt;Java 27 API Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://openjdk.org/jeps/0" rel="noopener noreferrer"&gt;OpenJDK JEP index&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>java27</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building GitHub Companion taught me a few things about Android architecture...</title>
      <dc:creator>Liriel</dc:creator>
      <pubDate>Thu, 02 Jul 2026 17:04:51 +0000</pubDate>
      <link>https://dev.to/lirielc/building-github-companion-taught-me-some-things-about-android-architecture-1m5f</link>
      <guid>https://dev.to/lirielc/building-github-companion-taught-me-some-things-about-android-architecture-1m5f</guid>
      <description>&lt;p&gt;One of the biggest challenges when learning Android development is moving beyond isolated code examples and building an application that resembles a production environment. Once an application starts interacting with external APIs, local databases, background synchronization, and asynchronous operations, concepts such as MVVM, repositories, dependency injection, and state management become essential rather than optional.&lt;/p&gt;

&lt;p&gt;To explore these concepts in practice, I built GitHub Companion, a native Android application that consumes the GitHub REST API while combining modern Kotlin components with Java interoperability commonly found in real-world Android projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Java Still Matters in Android Development
&lt;/h2&gt;

&lt;p&gt;Kotlin is currently the preferred language for Android, but Java remains a foundational pillar of the ecosystem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Coexistence and Legacy Codebases&lt;/strong&gt;: A vast number of production Android applications contain legacy systems written entirely in Java. Engineering teams rely on developers who can seamlessly navigate, refactor, and extend Java modules alongside newer Kotlin additions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Interoperability&lt;/strong&gt;: Kotlin and Java compile to the same JVM bytecode and are 100% interoperable. In modern projects, it is common to write UI layers in Kotlin (e.g., Jetpack Compose) while maintaining stable backend interfaces, models, and network libraries in Java.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Solid OOP Foundations&lt;/strong&gt;: Understanding Java's strict object-oriented design, garbage collection, and class hierarchies makes it significantly easier to grasp advanced Android frameworks and design patterns.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Architecture: Demystifying MVVM and Coroutines
&lt;/h2&gt;

&lt;p&gt;The application is built on the &lt;strong&gt;Model-View-ViewModel (MVVM)&lt;/strong&gt; pattern, which enforces a strict separation of concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Model&lt;/strong&gt;: Encapsulates the domain logic, database entities, and API clients.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;View&lt;/strong&gt;: Handles user interaction and rendering (in our case, declarative Jetpack Compose).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ViewModel&lt;/strong&gt;: Holds UI state and coordinates data operations. It communicates with the domain repositories and exposes states (Loading, Success, Error) to the View.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To handle asynchronous networking without blocking the UI thread, we utilize &lt;strong&gt;Kotlin Coroutines&lt;/strong&gt;. Coroutines provide a non-blocking execution model. By launching network requests in a Coroutine scope, we suspend task execution while waiting for the network, and resume automatically when the data arrives, keeping the main thread free to draw the UI.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Under the Hood: Deep Technical Insights
&lt;/h2&gt;

&lt;p&gt;To build reliable applications, we must understand how our frameworks operate underneath the abstraction layers. Here is how our app functions "under the hood."&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Why Room Exists If SQLite Already Exists
&lt;/h3&gt;

&lt;p&gt;SQLite is the engine under Android's local database, but using raw SQLite requires significant boilerplate. Developers must manually write SQL queries as strings, translate &lt;code&gt;Cursor&lt;/code&gt; objects into Java/Kotlin objects, and handle database updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Room&lt;/strong&gt; is an abstraction layer over SQLite that solves these issues:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Compile-Time Verification&lt;/strong&gt;: Room parses and validates your SQL queries during compilation. If you mistype a table name in a &lt;code&gt;@Query&lt;/code&gt; annotation, the build fails immediately. With raw SQLite, this syntax error would only crash your app at runtime on the user's device.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;No Boilerplate Mapping&lt;/strong&gt;: Room maps database rows directly to Java/Kotlin Data Objects (Entities) using annotation processors, eliminating cursor traversal loops.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reactive Streams&lt;/strong&gt;: Room seamlessly integrates with &lt;code&gt;Flow&lt;/code&gt; and &lt;code&gt;LiveData&lt;/code&gt;. When a row in your SQLite table changes, Room automatically publishes the updated query results to any active subscribers, keeping the UI in sync.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  B. What Actually Happens When Retrofit Executes a Request
&lt;/h3&gt;

&lt;p&gt;When you define a networking interface in Retrofit, it is just an interface with annotations—there is no implementation class. How does it execute?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Dynamic Proxy&lt;/strong&gt;: When you initialize Retrofit and call &lt;code&gt;retrofit.create(GitHubApiService.class)&lt;/code&gt;, Java's reflection mechanism uses &lt;code&gt;Proxy.newProxyInstance()&lt;/code&gt; to construct a dynamic proxy class at runtime.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Annotation Processing&lt;/strong&gt;: When a method (like &lt;code&gt;getRepository()&lt;/code&gt;) is called, Retrofit intercepts the call, parses the annotations (such as &lt;code&gt;@GET&lt;/code&gt; and &lt;code&gt;@Path&lt;/code&gt;) using reflection, and builds an HTTP request configuration.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;OkHttp Core&lt;/strong&gt;: Retrofit passes this request configuration to OkHttp, which manages the low-level connection pool, headers, and HTTP interceptors.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Serialization&lt;/strong&gt;: Once the raw bytes return from the server, Retrofit uses &lt;code&gt;GsonConverterFactory&lt;/code&gt; to deserialize the JSON stream into a Kotlin/Java DTO (Data Transfer Object).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Thread Switching&lt;/strong&gt;: If using Java &lt;code&gt;Call.enqueue()&lt;/code&gt;, Retrofit schedules the HTTP work on a background executor pool and posts the result back to the Android Main Thread. If using Kotlin &lt;code&gt;suspend&lt;/code&gt;, it suspends the Coroutine and resumes on the dispatcher scope.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  C. Coroutines Are Not Threads
&lt;/h3&gt;

&lt;p&gt;A common misconception is that a Coroutine is simply a thread wrapper. It is not.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Threads&lt;/strong&gt; are managed by the Operating System. Context switching between threads is expensive because the OS must save registers and CPU states, costing memory and time. You cannot run millions of threads concurrently.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Coroutines&lt;/strong&gt; are managed by the runtime environment and are cooperative. They use &lt;em&gt;suspension points&lt;/em&gt; where they yield the underlying thread to other coroutines without blocking it. &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Lightweight&lt;/strong&gt;: A coroutine is just a small object allocated on the heap. You can launch 100,000 coroutines on a single thread without memory pressure.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dispatchers&lt;/strong&gt;: Coroutines execute on dispatchers (like &lt;code&gt;Dispatchers.IO&lt;/code&gt; for network/disk operations or &lt;code&gt;Dispatchers.Main&lt;/code&gt; for UI changes). The dispatcher acts as a scheduler, mapping coroutine tasks to a thread pool underneath.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  D. Understanding Dependency Injection Through Hilt
&lt;/h3&gt;

&lt;p&gt;Without Dependency Injection (DI), classes instantiate their own dependencies. For example, a &lt;code&gt;MainActivity&lt;/code&gt; would instantiate a &lt;code&gt;Repository&lt;/code&gt;, which instantiates a &lt;code&gt;RoomDatabase&lt;/code&gt; and a &lt;code&gt;Retrofit&lt;/code&gt; client. This creates tight coupling, makes testing impossible, and violates the Single Responsibility Principle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hilt&lt;/strong&gt; (built on Dagger) is a compile-time DI library:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Service Decoupling&lt;/strong&gt;: Instead of writing &lt;code&gt;new GitHubRepositoryImpl(...)&lt;/code&gt;, we annotate the class constructor with &lt;code&gt;@Inject&lt;/code&gt; and Hilt automatically provides the dependency.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Codegen Graph&lt;/strong&gt;: During compilation, Hilt parses our annotations and generates the dependency graph. It validates that every class has access to the instances it needs. If a dependency is missing, the app fails to compile.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Scope Management&lt;/strong&gt;: Hilt couples dependencies to Android lifecycles (e.g., &lt;code&gt;@Singleton&lt;/code&gt; lives for the app's duration, while &lt;code&gt;@ActivityScoped&lt;/code&gt; exists only as long as the Activity).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  E. Why Repository Exists
&lt;/h3&gt;

&lt;p&gt;The Repository pattern serves a vital architectural purpose: it isolates the domain layer from data origin details.&lt;br&gt;
Without a Repository, the ViewModel would need to coordinate Room database transactions and Retrofit network calls directly. If we decided to migrate our caching engine from Room to Realm, we would have to rewrite the ViewModel.&lt;/p&gt;

&lt;p&gt;The Repository provides a &lt;strong&gt;Single Source of Truth (SSOT)&lt;/strong&gt;. The ViewModel simply requests a repository record, and the Repository decides whether to fetch it from SQLite or trigger a web request. During tests, we mock the Repository interface using mock libraries (like Mockito) to return local test data, verifying our UI states without hitting real APIs.&lt;/p&gt;
&lt;h3&gt;
  
  
  F. The WorkManager + Hilt Crash That Took Hours to Debug
&lt;/h3&gt;

&lt;p&gt;When setting up background syncing, we encountered a runtime crash: &lt;code&gt;NoSuchMethodException: SyncFavoritesWorker.&amp;lt;init&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Cause&lt;/strong&gt;: By default, Android's &lt;code&gt;androidx.startup&lt;/code&gt; library automatically initializes WorkManager. During startup, WorkManager uses reflection to look for a default two-argument constructor &lt;code&gt;(Context, WorkerParameters)&lt;/code&gt;. Because our worker uses &lt;code&gt;@HiltWorker&lt;/code&gt; to inject dependencies, it lacks this constructor, causing reflection to fail.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Resolution&lt;/strong&gt;: We had to disable the automatic WorkManager initializer in the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; via:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta-data&lt;/span&gt;
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"androidx.work.WorkManagerInitializer"&lt;/span&gt;
    &lt;span class="na"&gt;android:value=&lt;/span&gt;&lt;span class="s"&gt;"androidx.startup"&lt;/span&gt;
    &lt;span class="na"&gt;tools:node=&lt;/span&gt;&lt;span class="s"&gt;"remove"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Then, we implemented &lt;code&gt;Configuration.Provider&lt;/code&gt; in our &lt;code&gt;Application&lt;/code&gt; class, manually injecting the custom &lt;code&gt;HiltWorkerFactory&lt;/code&gt; to handle the instantiation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  G. Cache Invalidation Is Harder Than It Looks
&lt;/h3&gt;

&lt;p&gt;Offline synchronization sounds simple: save data locally and show it. But what happens if the data on the server changes?&lt;br&gt;
If the app never checks for updates, the user sees stale information forever. If the app updates too often, it defeats the purpose of caching and drains the battery.&lt;/p&gt;

&lt;p&gt;To solve this, we implemented a &lt;strong&gt;Time-Based Invalidation Policy&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Every database record includes a &lt;code&gt;lastSync&lt;/code&gt; timestamp.&lt;/li&gt;
&lt;li&gt;  When a user searches for a repository, the repository queries Room and checks if &lt;code&gt;System.currentTimeMillis() - lastSync &amp;lt; 30 minutes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  If valid, it returns the cached data. If expired, it attempts a network fetch. If the network call fails (e.g., no internet), it falls back gracefully to the expired cache.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  H. Why GitHub API Rate Limits Matter
&lt;/h3&gt;

&lt;p&gt;The GitHub REST API enforces a strict rate limit of &lt;strong&gt;60 requests per hour&lt;/strong&gt; for unauthenticated requests. &lt;/p&gt;

&lt;p&gt;If our app did not cache data locally, every tab switch (Commits -&amp;gt; Branches -&amp;gt; Issues) or list reload would count against the user's rate limit. The user would quickly receive a &lt;code&gt;403 Forbidden&lt;/code&gt; error. By caching details in Room for 30 minutes and grouping repository data, we minimize API calls, saving our network budget.&lt;/p&gt;
&lt;h3&gt;
  
  
  I. Why ANRs Happen
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;Application Not Responding (ANR)&lt;/strong&gt; dialog is shown when the Main Thread (UI Thread) is blocked.&lt;br&gt;
In Android, the Main Thread has a message loop managed by a &lt;code&gt;Looper&lt;/code&gt;. It processes layout draws, touch events, and system notifications. If any event takes longer than &lt;strong&gt;5 seconds&lt;/strong&gt; to execute, the OS assumes the app is frozen and shows the ANR dialog.&lt;/p&gt;

&lt;p&gt;Running a database query or an API request synchronously blocks the Thread until the socket completes or disk I/O completes. In our application, we prevent this by executing database queries asynchronously using Room's Flow bindings and performing Retrofit calls inside Kotlin Coroutines or Java's background executor thread pools.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. Java-Kotlin Interoperability: The Date Formatter
&lt;/h2&gt;

&lt;p&gt;To show how Java classes integrate with Kotlin, we implemented &lt;strong&gt;&lt;a href="https://github.com/LirielC/GitHubCompanion/blob/main/app/src/main/java/com/example/hubcompanion/util/DateFormatterUtil.java" rel="noopener noreferrer"&gt;&lt;code&gt;DateFormatterUtil.java&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt; in Java to parse ISO-8601 strings into user-friendly relative dates (e.g., "3 minutes ago").&lt;/p&gt;

&lt;p&gt;In our Kotlin presentation layer, we consume this Java helper directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;relativeDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DateFormatterUtil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formatGithubDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Architectural Code Walkthrough
&lt;/h2&gt;

&lt;p&gt;Below are the streamlined core components of the application. The full, concrete implementations can be viewed directly in the &lt;a href="https://github.com/LirielC/GitHubCompanion" rel="noopener noreferrer"&gt;project repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Consuming REST APIs (Retrofit Interface)
&lt;/h3&gt;

&lt;p&gt;Retrofit abstracts network endpoints. In a mixed codebase, we can define our endpoints in Java using &lt;code&gt;Call&amp;lt;T&amp;gt;&lt;/code&gt; or in Kotlin using &lt;code&gt;suspend&lt;/code&gt; functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kotlin (using Coroutines)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;GitHubApiService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repos/{owner}/{repo}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"owner"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;RepositoryDto&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Java Equivalent (using &lt;code&gt;Call&amp;lt;T&amp;gt;&lt;/code&gt;)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;GitHubApiService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repos/{owner}/{repo}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Call&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RepositoryDto&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"owner"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"repo"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  B. The Repository Pattern (Cache Management)
&lt;/h3&gt;

&lt;p&gt;The Repository acts as a mediator between data sources, providing a single source of truth.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Kotlin Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="err"&gt;`&lt;/span&gt;  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GitHubRepositoryImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GitHubApiService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;repositoryDao&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RepositoryDao&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GitHubReposit&lt;/span&gt;&lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;ory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;forceRefresh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Repository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;localRepo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repositoryDao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFavoriteById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$owner/$name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isCacheValid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localRepo&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;localRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastSync&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isCacheValid&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;forceRefresh&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;localRepo&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;dto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;apiService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;dto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;also&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;repositoryDao&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insertFavorite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RepositoryEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromDomain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;localRepo&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toDomain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  C. State Management (ViewModel)
&lt;/h3&gt;

&lt;p&gt;The ViewModel hosts the application state, pushing states lifecycle-safely to the View.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Java LiveData ViewModel&lt;/strong&gt;:&lt;br&gt;
&lt;code&gt;&lt;/code&gt;`java&lt;br&gt;
public class RepositorySearchViewModel extends ViewModel {&lt;br&gt;
    private final GitHubRepositoryImpl repository;&lt;br&gt;
    private final MutableLiveData&amp;gt; searchResult = new MutableLiveData&amp;lt;&amp;gt;();&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public LiveData&amp;lt;Resource&amp;lt;Repository&amp;gt;&amp;gt; getSearchResult() { return searchResult; }

public void searchRepository(String owner, String repo) {
    searchResult.setValue(Resource.loading());
    new Thread(() -&amp;gt; {
        try {
            Repository result = repository.getRepository(owner, repo, true);
            searchResult.postValue(Resource.success(result));
        } catch (Exception e) {
            searchResult.postValue(Resource.error(e.getMessage()));
        }
    }).start();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Key Concepts Comparison: Kotlin vs. Java
&lt;/h2&gt;

&lt;p&gt;Developers working in mixed codebases must understand the structural equivalents across both languages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Kotlin Pattern&lt;/th&gt;
&lt;th&gt;Java Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Async Operations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coroutines (&lt;code&gt;suspend&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Executors, &lt;code&gt;Thread&lt;/code&gt;, or Retrofit &lt;code&gt;Call.enqueue()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;State Observation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;StateFlow&lt;/code&gt; or &lt;code&gt;SharedFlow&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LiveData&lt;/code&gt; or RxJava &lt;code&gt;Observable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Binding&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Jetpack Compose State&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LiveData.observe()&lt;/code&gt; or View Binding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data Classes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;data class Repository(...)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standard Java Class with private fields, getters, and constructor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  7. Application Branding &amp;amp; Interface Preview
&lt;/h2&gt;

&lt;p&gt;To give the application a premium identity, we designed a custom logo combining a robotic companion concept with the GitHub symbol:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnzdwmffl59big6mdn2jv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnzdwmffl59big6mdn2jv.png" alt="GitHub Companion Logo" width="324" height="726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is a preview of the search and detailed views of the app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsu2cbqm1gu5p5yhirxhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsu2cbqm1gu5p5yhirxhx.png" alt="GitHub Companion Mockup" width="324" height="724"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Clean Code &amp;amp; Mobile Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;DRY (Don't Repeat Yourself)&lt;/strong&gt;: Network responses (DTOs) are mapped to domain models in a centralized mapping layer, ensuring parsing logic is never repeated.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;SOLID Principles&lt;/strong&gt;: We respect the Single Responsibility Principle. For example, database DAOs are solely responsible for SQL queries, while the Repository handles cache management logic.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Version Control (Git)&lt;/strong&gt;: Adopted a feature-branch workflow (e.g., &lt;code&gt;feature/retrofit-api&lt;/code&gt;) to keep the main development branch clean, employing semantic commit logs.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Conclusion &amp;amp; Learnings
&lt;/h2&gt;

&lt;p&gt;Building &lt;strong&gt;GitHub Companion&lt;/strong&gt; highlighted the value of structured architecture. By leveraging the &lt;strong&gt;Repository Pattern&lt;/strong&gt; and &lt;strong&gt;MVVM&lt;/strong&gt;, writing clean, encapsulated &lt;strong&gt;Java models&lt;/strong&gt;, and integrating &lt;strong&gt;Kotlin Coroutines&lt;/strong&gt; and &lt;strong&gt;Retrofit REST APIs&lt;/strong&gt;, we built a codebase that is highly testable, scalable, and easy to maintain in a mixed-language development environment.&lt;/p&gt;

&lt;p&gt;Working directly on these layers shows that mobile development is more than just writing UI; it requires understanding JVM thread synchronization, memory architectures, caching thresholds, and how frameworks integrate.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://imgur.com/EosbhJ7" rel="noopener noreferrer"&gt;Video&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  10. References &amp;amp; Further Reading
&lt;/h2&gt;

&lt;p&gt;To learn more about Android architectures, JVM interoperability, and best practices, check out these official developer resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://developer.android.com/topic/architecture" rel="noopener noreferrer"&gt;Android Developers - Guide to App Architecture&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://kotlinlang.org/docs/coroutines-overview.html" rel="noopener noreferrer"&gt;Kotlin Docs - Coroutines Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://square.github.io/retrofit/" rel="noopener noreferrer"&gt;Retrofit Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developer.android.com/training/data-storage/room" rel="noopener noreferrer"&gt;Android Developers - Room Persistence Library&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developer.android.com/topic/libraries/architecture/workmanager" rel="noopener noreferrer"&gt;Android Developers - WorkManager Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://kotlinlang.org/docs/java-to-kotlin-interop.html" rel="noopener noreferrer"&gt;Kotlin-Java Interop Guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can explore the full implementation code of this project in my GitHub Repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/LirielC/GitHubCompanion" rel="noopener noreferrer"&gt;&lt;strong&gt;GitHub Companion Repository&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Java Garbage Collector: Why Creating Objects Is Cheaper Than You Think</title>
      <dc:creator>Liriel</dc:creator>
      <pubDate>Sun, 28 Jun 2026 17:26:32 +0000</pubDate>
      <link>https://dev.to/lirielc/java-garbage-collector-why-creating-objects-is-cheaper-than-you-think-2dlm</link>
      <guid>https://dev.to/lirielc/java-garbage-collector-why-creating-objects-is-cheaper-than-you-think-2dlm</guid>
      <description>&lt;p&gt;When many developers first hear about Java's Garbage Collector, they often associate it with one thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Automatic memory management comes at the cost of performance."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This perception made sense twenty years ago.&lt;/p&gt;

&lt;p&gt;Today, however, some of the largest systems in the world run on the JVM, handling millions of requests per second with strict latency requirements.&lt;/p&gt;

&lt;p&gt;Companies like Netflix, Uber, LinkedIn, and many banks rely heavily on Java in production environments where performance is not optional.&lt;/p&gt;

&lt;p&gt;So what changed?&lt;/p&gt;

&lt;p&gt;The answer lies in understanding how the Java Garbage Collector actually works.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Memory Problem Every Language Must Solve
&lt;/h2&gt;

&lt;p&gt;Imagine the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application allocates memory for the &lt;code&gt;User&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Eventually, that object is no longer needed.&lt;/p&gt;

&lt;p&gt;The question is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who is responsible for freeing that memory?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In languages such as C, the developer is responsible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Forgetting to free memory causes leaks.&lt;/p&gt;

&lt;p&gt;Freeing memory too early can lead to crashes and undefined behavior.&lt;/p&gt;

&lt;p&gt;Java chose a different approach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The JVM itself determines when an object is no longer reachable and automatically reclaims its memory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This process is known as &lt;strong&gt;Garbage Collection&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Does Java Know an Object Is Dead?
&lt;/h2&gt;

&lt;p&gt;Java does not determine whether an object is alive based on variables or scope.&lt;/p&gt;

&lt;p&gt;Instead, it uses a concept called &lt;strong&gt;reachability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variable &lt;code&gt;user&lt;/code&gt; references the object.&lt;/p&gt;

&lt;p&gt;As long as that reference exists, the object is considered alive.&lt;/p&gt;

&lt;p&gt;Now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If no other references point to that object, it becomes unreachable.&lt;/p&gt;

&lt;p&gt;Unreachable objects become candidates for garbage collection.&lt;/p&gt;

&lt;p&gt;This approach is significantly safer than manual memory management because the JVM avoids both accidental deallocation and most memory corruption issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Observation That Changed Everything
&lt;/h2&gt;

&lt;p&gt;The JVM is built around an observation known as the &lt;strong&gt;Generational Hypothesis&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most objects die young.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Surprisingly, this is true for the majority of modern applications.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP request objects&lt;/li&gt;
&lt;li&gt;DTOs&lt;/li&gt;
&lt;li&gt;JSON parsing structures&lt;/li&gt;
&lt;li&gt;Temporary strings&lt;/li&gt;
&lt;li&gt;Stream operations&lt;/li&gt;
&lt;li&gt;Intermediate collections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These objects often live for only a few milliseconds.&lt;/p&gt;

&lt;p&gt;Meanwhile, objects that survive for longer periods tend to remain alive for a very long time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caches&lt;/li&gt;
&lt;li&gt;Singleton services&lt;/li&gt;
&lt;li&gt;Application configurations&lt;/li&gt;
&lt;li&gt;Database connection pools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This observation fundamentally shaped the design of Java's Garbage Collectors.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Heap Is Divided Into Generations
&lt;/h2&gt;

&lt;p&gt;Instead of treating all objects equally, Java separates memory into generations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Heap
│
├── Young Generation
│   ├── Eden
│   ├── Survivor 0
│   └── Survivor 1
│
└── Old Generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Eden: Where Objects Are Born
&lt;/h2&gt;

&lt;p&gt;Almost every object starts its life in &lt;strong&gt;Eden Space&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of them are allocated inside Eden.&lt;/p&gt;

&lt;p&gt;When Eden becomes full, the JVM triggers a &lt;strong&gt;Minor GC&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Minor GC
&lt;/h2&gt;

&lt;p&gt;During a Minor GC, the JVM identifies which objects in Eden are still alive.&lt;/p&gt;

&lt;p&gt;Dead objects are discarded immediately.&lt;/p&gt;

&lt;p&gt;Live objects are copied to one of the Survivor spaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Eden → Survivor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process is extremely efficient because most objects are already dead.&lt;/p&gt;

&lt;p&gt;Remember the Generational Hypothesis:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most objects die young.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a result, the JVM often removes the vast majority of objects during every Minor GC cycle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Survivor Spaces
&lt;/h2&gt;

&lt;p&gt;The JVM alternates between two survivor areas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Survivor 0&lt;/li&gt;
&lt;li&gt;Survivor 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Objects bounce between these spaces while they survive multiple garbage collection cycles.&lt;/p&gt;

&lt;p&gt;Each time an object survives, its age increases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Age 1
Age 2
Age 3
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eventually, the JVM decides that the object is probably long-lived.&lt;/p&gt;

&lt;p&gt;At this point, it gets promoted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Promotion to Old Generation
&lt;/h2&gt;

&lt;p&gt;Objects that survive enough collection cycles are moved to the &lt;strong&gt;Old Generation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Young Generation
        ↓
Old Generation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typical examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Beans&lt;/li&gt;
&lt;li&gt;Caches&lt;/li&gt;
&lt;li&gt;Singleton instances&lt;/li&gt;
&lt;li&gt;Application configuration objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These objects are expected to remain alive for much longer periods.&lt;/p&gt;




&lt;h2&gt;
  
  
  Major GC and Full GC
&lt;/h2&gt;

&lt;p&gt;Cleaning the Old Generation is considerably more expensive.&lt;/p&gt;

&lt;p&gt;This process is often called a &lt;strong&gt;Major GC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In some situations, the JVM may need to collect the entire heap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Young Generation&lt;/li&gt;
&lt;li&gt;Old Generation&lt;/li&gt;
&lt;li&gt;Metaspace&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is known as a &lt;strong&gt;Full GC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Historically, Full GCs were among the most feared events in Java applications because they frequently paused the application for long periods.&lt;/p&gt;

&lt;p&gt;Modern collectors significantly reduced this problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stop-The-World Moment
&lt;/h2&gt;

&lt;p&gt;During certain phases of garbage collection, the JVM pauses all application threads.&lt;/p&gt;

&lt;p&gt;This event is called:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stop-The-World (STW)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While the JVM performs critical operations, application threads remain suspended.&lt;/p&gt;

&lt;p&gt;The goal of modern collectors is not to eliminate these pauses entirely, but rather to make them extremely short and predictable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Enter G1GC
&lt;/h2&gt;

&lt;p&gt;Since Java 9, the default collector is &lt;strong&gt;Garbage First (G1)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of dividing memory into large contiguous spaces, G1 divides the heap into many small regions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+----+----+----+----+
| R1 | R2 | R3 | R4 |
+----+----+----+----+
| R5 | R6 | R7 | R8 |
+----+----+----+----+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some regions contain young objects.&lt;/p&gt;

&lt;p&gt;Others contain old objects.&lt;/p&gt;

&lt;p&gt;This design allows G1 to focus on collecting the regions that provide the highest memory recovery with the smallest pause times.&lt;/p&gt;

&lt;p&gt;Hence the name:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Garbage First.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Secret Behind Fast Object Allocation
&lt;/h2&gt;

&lt;p&gt;One of the biggest misconceptions in Java is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Creating objects is expensive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In reality, object allocation in Java is often incredibly cheap.&lt;/p&gt;

&lt;p&gt;Most allocations happen using a technique called &lt;strong&gt;Bump Pointer Allocation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Object A | Object B | Free Space |
                       ^
                    Pointer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a new object frequently means little more than:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pointer += object_size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No complex memory search.&lt;/p&gt;

&lt;p&gt;No traversal.&lt;/p&gt;

&lt;p&gt;No expensive allocation algorithms.&lt;/p&gt;

&lt;p&gt;Just moving a pointer forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Thread Local Allocation Buffers (TLAB)
&lt;/h2&gt;

&lt;p&gt;The JVM goes even further.&lt;/p&gt;

&lt;p&gt;Each thread often receives its own allocation area called a &lt;strong&gt;Thread Local Allocation Buffer (TLAB)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of multiple threads competing for access to the heap, they allocate objects inside their own local buffers.&lt;/p&gt;

&lt;p&gt;This dramatically reduces contention and synchronization overhead.&lt;/p&gt;

&lt;p&gt;For most applications, object allocation becomes almost lock-free.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sometimes the Object Never Exists
&lt;/h2&gt;

&lt;p&gt;Modern JVMs perform sophisticated optimizations.&lt;/p&gt;

&lt;p&gt;One of the most impressive is &lt;strong&gt;Escape Analysis&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the JVM determines that &lt;code&gt;point&lt;/code&gt; never escapes the method, it may avoid allocating the object entirely.&lt;/p&gt;

&lt;p&gt;In some cases:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The object is never created.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Is Garbage Collection Free?
&lt;/h2&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;Garbage Collection introduces overhead.&lt;/p&gt;

&lt;p&gt;The JVM spends CPU cycles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identifying live objects&lt;/li&gt;
&lt;li&gt;Moving objects&lt;/li&gt;
&lt;li&gt;Compacting memory&lt;/li&gt;
&lt;li&gt;Updating references&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the trade-off has proven extremely successful.&lt;/p&gt;

&lt;p&gt;Developers gain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory safety&lt;/li&gt;
&lt;li&gt;Higher productivity&lt;/li&gt;
&lt;li&gt;Fewer crashes caused by invalid pointers&lt;/li&gt;
&lt;li&gt;Simpler application code&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;The Garbage Collector is often described as a convenience feature.&lt;/p&gt;

&lt;p&gt;In reality, it is much more than that.&lt;/p&gt;

&lt;p&gt;The JVM combines decades of research in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allocation algorithms&lt;/li&gt;
&lt;li&gt;Concurrent programming&lt;/li&gt;
&lt;li&gt;Memory compaction&lt;/li&gt;
&lt;li&gt;Cache locality&lt;/li&gt;
&lt;li&gt;Latency reduction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern Java applications are not fast despite the Garbage Collector.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In many cases, they are fast precisely because of the engineering behind it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next time you write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;remember that behind this single line, the JVM is leveraging decades of computer science research to make that operation as efficient as possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Oracle Java HotSpot Garbage Collection Tuning Guide&lt;/li&gt;
&lt;li&gt;Oracle G1 Garbage Collector Documentation&lt;/li&gt;
&lt;li&gt;Aleksey Shipilev — JVM Anatomy Quarks&lt;/li&gt;
&lt;li&gt;Scott Oaks — &lt;em&gt;Java Performance: The Definitive Guide&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Plumbr Garbage Collection Handbook&lt;/li&gt;
&lt;li&gt;OpenJDK Documentation&lt;/li&gt;
&lt;li&gt;GCeasy JVM Performance Articles&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>computerscience</category>
      <category>java</category>
      <category>performance</category>
      <category>programming</category>
    </item>
    <item>
      <title>What Are Classes, Objects, and Methods in Java? (Explained Simply)</title>
      <dc:creator>Liriel</dc:creator>
      <pubDate>Fri, 26 Jun 2026 00:54:29 +0000</pubDate>
      <link>https://dev.to/lirielc/what-are-classes-objects-and-methods-in-java-explained-simply-1big</link>
      <guid>https://dev.to/lirielc/what-are-classes-objects-and-methods-in-java-explained-simply-1big</guid>
      <description>&lt;h1&gt;
  
  
  Classes, Objects, and Methods in Java
&lt;/h1&gt;

&lt;p&gt;When you start learning Java — or any object-oriented language — three concepts will show up everywhere: &lt;strong&gt;classes&lt;/strong&gt;, &lt;strong&gt;objects&lt;/strong&gt;, and &lt;strong&gt;methods&lt;/strong&gt;. Before you can write meaningful code, you need to understand what each of these is, why it exists, and how they relate to each other.&lt;/p&gt;

&lt;p&gt;This article breaks all three down in a practical, straightforward way, using a real-world example you would actually find in a backend application.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is a Class?
&lt;/h2&gt;

&lt;p&gt;A class is a &lt;strong&gt;blueprint&lt;/strong&gt;. It is a definition, a template that describes what a certain type of thing looks like and what it can do — but it is not the thing itself.&lt;/p&gt;

&lt;p&gt;Think of it like an architectural floor plan. The plan tells you how many rooms a house has, where the doors are, and how the kitchen is laid out. But the plan is not a house you can live in. You use the plan to &lt;em&gt;build&lt;/em&gt; a house.&lt;/p&gt;

&lt;p&gt;In the same way, a class tells Java what attributes (data) and behaviors (methods) a certain type of object will have. No memory is allocated for real data yet — the class is just the definition.&lt;/p&gt;

&lt;p&gt;A class defines two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attributes&lt;/strong&gt; — the data that each object of this type will hold&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods&lt;/strong&gt; — the actions that each object of this type can perform&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: the &lt;code&gt;User&lt;/code&gt; class
&lt;/h3&gt;

&lt;p&gt;In a web application, users are everywhere. Let's model one as a class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deactivate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;changeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") - Active: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class describes what every user in our system has and can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attributes:&lt;/strong&gt; &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;active&lt;/code&gt; — these are the pieces of data each user carries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods:&lt;/strong&gt; &lt;code&gt;deactivate()&lt;/code&gt;, &lt;code&gt;changeEmail()&lt;/code&gt;, and &lt;code&gt;getUserInfo()&lt;/code&gt; — these are the actions a user can perform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that the class alone does nothing. It just declares the structure. To actually work with a user, you need to create an object from it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is an Object?
&lt;/h2&gt;

&lt;p&gt;An object is a &lt;strong&gt;concrete instance of a class&lt;/strong&gt;. While the class is the blueprint, the object is the actual thing built from it — with its own real data stored in memory.&lt;/p&gt;

&lt;p&gt;Every time you write &lt;code&gt;new User(...)&lt;/code&gt;, Java uses the &lt;code&gt;User&lt;/code&gt; class to create a brand new object. That object gets its own copy of &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;active&lt;/code&gt;. Multiple objects can exist from the same class at the same time, and each one holds its own independent data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: creating and using objects
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Ana Silva"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ana@email.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Carlos Souza"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"carlos@email.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deactivate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;user2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;changeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"carlos.souza@newmail.com"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;user1&lt;/code&gt; and &lt;code&gt;user2&lt;/code&gt; are two separate objects, both created from the same &lt;code&gt;User&lt;/code&gt; class. Even though they share the same structure, they are completely independent. Deactivating &lt;code&gt;user1&lt;/code&gt; has no effect on &lt;code&gt;user2&lt;/code&gt;. Changing the email of &lt;code&gt;user2&lt;/code&gt; does not touch &lt;code&gt;user1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is one of the most important things to internalize: &lt;strong&gt;the class defines the shape, but each object has its own state&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is a Method?
&lt;/h2&gt;

&lt;p&gt;A method defines &lt;strong&gt;what an object can do&lt;/strong&gt;. It is a block of code attached to a class that describes a specific behavior or action.&lt;/p&gt;

&lt;p&gt;In real backend systems, methods tend to represent either business logic or data access. They are not just utility functions — they express what a concept &lt;em&gt;means&lt;/em&gt; in your domain.&lt;/p&gt;

&lt;p&gt;Let's look at the methods from our &lt;code&gt;User&lt;/code&gt; class more carefully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deactivate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;changeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getUserInfo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" ("&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;") - Active: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each method has a clear responsibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deactivate()&lt;/code&gt; encapsulates the business rule that deactivating a user means setting their &lt;code&gt;active&lt;/code&gt; flag to &lt;code&gt;false&lt;/code&gt;. Instead of writing &lt;code&gt;user.active = false&lt;/code&gt; scattered throughout your code, you put that logic in one place and call it by a meaningful name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;changeEmail()&lt;/code&gt; provides a controlled way to update the user's email. You could add validation inside it later without changing anything else in your codebase.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;getUserInfo()&lt;/code&gt; formats user data into a readable string, separating that concern from whoever is displaying it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the essence of why methods exist: they keep logic organized, named, and reusable.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Three Concepts Work Together
&lt;/h2&gt;

&lt;p&gt;These three concepts are not independent — they depend on each other to make object-oriented programming work.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;In our example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Class&lt;/td&gt;
&lt;td&gt;Defines the structure and behavior&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;User&lt;/code&gt; blueprint with its fields and methods&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object&lt;/td&gt;
&lt;td&gt;A real instance with actual data&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;user1&lt;/code&gt; (Ana) and &lt;code&gt;user2&lt;/code&gt; (Carlos) in memory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method&lt;/td&gt;
&lt;td&gt;An action the object can perform&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;deactivate()&lt;/code&gt;, &lt;code&gt;changeEmail()&lt;/code&gt;, &lt;code&gt;getUserInfo()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The relationship is straightforward: you write a &lt;strong&gt;class&lt;/strong&gt; once, create as many &lt;strong&gt;objects&lt;/strong&gt; from it as you need, and interact with those objects by calling &lt;strong&gt;methods&lt;/strong&gt; on them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters in Real Java Development
&lt;/h2&gt;

&lt;p&gt;This is not abstract theory you'll leave behind once you get to "the real stuff". This is exactly the foundation that real backend applications are built on.&lt;/p&gt;

&lt;p&gt;When you work with Spring Boot, for instance, your classes become the backbone of the entire application. The &lt;code&gt;User&lt;/code&gt; class from this article is one annotation away from being a database entity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// same fields and methods&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From there, it flows through your entire layered architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Controllers&lt;/strong&gt; receive HTTP requests and work with &lt;code&gt;User&lt;/code&gt; objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Services&lt;/strong&gt; contain business logic that operates on &lt;code&gt;User&lt;/code&gt; objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repositories&lt;/strong&gt; persist and retrieve &lt;code&gt;User&lt;/code&gt; objects from the database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every layer of a Spring Boot API is built on classes. Every piece of data passing through your system is an object. Every interaction with that data goes through methods. Understanding this clearly makes every other concept in Java easier to grasp.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Once you have a solid grip on these three ideas, a lot of what can seem confusing about Java starts to make sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Classes&lt;/strong&gt; give your code structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Objects&lt;/strong&gt; are the live, running instances of that structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Methods&lt;/strong&gt; define how those instances behave and interact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else in Java — inheritance, interfaces, annotations, frameworks — builds on top of this foundation. Get comfortable with it, and the rest of the language becomes much more approachable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Go Next
&lt;/h2&gt;

&lt;p&gt;If you feel confident with classes, objects, and methods, the natural next steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encapsulation and Access Modifiers&lt;/strong&gt; — understanding why fields are &lt;code&gt;private&lt;/code&gt; and what that protects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inheritance&lt;/strong&gt; — how one class can extend another to reuse and specialize behavior&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spring Boot REST APIs&lt;/strong&gt; — applying these concepts in a real web application context&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>java</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
