[External] : Re: Question about potential optimization for Year.isLeap()

Naoto Sato naoto.sato at oracle.com
Mon Dec 15 18:31:24 UTC 2025


+1 for JMH experiment. I would like to see how it would improve in real 
use cases.

Naoto

On 12/15/25 3:32 AM, Raffaello Giulietti wrote:
> In OpenJDK we use the JMH framework to measure performance.
> 
> See the documentation in
> https://github.com/openjdk/jmh
> https://github.com/openjdk/jdk/blob/master/doc/testing.md and search for "microbenchmark"
> 
> You can find some samples in
> https://github.com/openjdk/jmh/tree/master/jmh-samples/src/main/java/org/openjdk/jmh/samples
> 
> In OpenJDK itself, you can find real world usage of JMH in
> https://github.com/openjdk/jdk/tree/master/test/micro/org/openjdk/bench
> 
> Once you are ready to use JMH, on the mailing list you can then provide the JMH results comparing the "before change" and "after change" figures.
> 
> Hope this helps
> 
> 
> ________________________________________
> From: Memory <smqy2314 at gmail.com>
> Sent: Sunday, December 14, 2025 18:23
> To: Raffaello Giulietti
> Cc: core-libs-dev at openjdk.org
> Subject: [External] : Re: Question about potential optimization for Year.isLeap()
> 
> Hi,
> 
> Thanks for the correction. I confused the implementations.
> 
> I'm proposing to change:
> 
> ```java
> return (year & 15) == 0 ? (year & 3) == 0 : (year & 3) == 0 && year % 100 != 0;
> ```
> 
> to:
> 
> ```java
> return (year & 15) == 0 || ((year & 3) == 0 && year % 100 != 0);
> ```
> 
> At the low level, this should be slightly faster because:
> 
> 1. Fewer CPU branches - Ternary creates a true branch, while logical operators use short-circuit evaluation
> 2. Better for branch prediction - Simpler control flow pattern
> 3. Less operation duplication - The current code conceptually checks (year & 3) == 0 twice in the false case
> 
> However, I understand any performance difference would likely be minimal. If the team prefers the current ternary operator for better readability, I fully respect that decision.
> 
> Raffaello Giulietti <raffaello.giulietti at oracle.com<mailto:raffaello.giulietti at oracle.com>> 于 2025年12月14日周日 19:45写道:
> Hi,
> 
> the current logic in mainline is
> ```
>          return (year & 15) == 0 ? (year & 3) == 0 : (year & 3) == 0 && year % 100 != 0;
> ```
> (see https://github.com/openjdk/jdk/blob/fb531cdaf3b30034e0efa86b9b20558478ce94d0/src/java.base/share/classes/java/time/Year.java#L321<https://urldefense.com/v3/__https://github.com/openjdk/jdk/blob/fb531cdaf3b30034e0efa86b9b20558478ce94d0/src/java.base/share/classes/java/time/Year.java*L321__;Iw!!ACWV5N9M2RV99hQ!ILBGqbgmHKbXqqdQShgtaBhShlZKl8_Pe_pvHC1yFBjQp2pUZrgcTzDZP6efKRPT8iVsh9IrxVmyRfl8LtnSiu_w$>)
> 
> 
> ________________________________________
> From: core-libs-dev <core-libs-dev-retn at openjdk.org<mailto:core-libs-dev-retn at openjdk.org>> on behalf of Memory <smqy2314 at gmail.com<mailto:smqy2314 at gmail.com>>
> Sent: Sunday, December 14, 2025 09:45
> To: core-libs-dev at openjdk.org<mailto:core-libs-dev at openjdk.org>
> Subject: Question about potential optimization for Year.isLeap()
> 
> Hello core-libs-dev team,
> 
> My name is Memory2314, and I am a new contributor currently waiting for my Oracle Contributor Agreement (OCA) to be processed.
> 
> I have been studying the `java.time.Year.isLeap()` method and would like to propose a micro-optimization:
> 
> **Current logic:**
> ```java
> return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
> ```
> 
> **Proposed optimization:**
> ```java
> return (year & 15) == 0 || ((year & 3) == 0 && year % 100 != 0);
> ```
> 
> **Key improvements:**
> - Replaces `year % 4 == 0` with bitwise `(year & 3) == 0`
> - Uses `(year & 15) == 0` to efficiently detect years divisible by 400
> - Reduces modulo operations from 3 to 1 in the common case
> 
> **Verification benchmark:**
> ```java
> public static void main(String[] args) {
>      int[] years = new int[1_000_000_000];
>      Random random = new Random();
>      for (int i = 0; i < years.length; i++) {
>          years[i] = 1970 + random.nextInt(5000 - 1970 + 1);
>      }
> 
>      long start1 = System.currentTimeMillis();
>      for (int year : years) {
>          boolean result = isLeapOriginal(year);
>      }
>      System.out.println("Original: " + (System.currentTimeMillis()-start1) + "ms");
> 
>      long start2 = System.currentTimeMillis();
>      for (int year : years) {
>          boolean result = isLeapOptimized(year);
>      }
>      System.out.println("Optimized: " + (System.currentTimeMillis()-start2) + "ms");
> }
> 
> public static boolean isLeapOriginal(long year) {
>      return (year & 15) == 0 ? (year & 3) == 0 : (year & 3) == 0 && year % 100 != 0;
> }
> 
> public static boolean isLeapOptimized(long year) {
>      return (year & 15) == 0 || ((year & 3) == 0 && year % 100 != 0);
> }
> ```
> 
> **Correctness verification:** I've tested this logic extensively, including edge cases like year 0, negative years (proleptic Gregorian), and all century boundaries from -10,000 to 10,000.
> 
> I am aware that I cannot submit a formal patch until my OCA is complete. However, I would be very grateful for your initial technical feedback on this approach before I proceed to create a fully tested patch with benchmarks.
> 
> Once my OCA is in place, would there be a maintainer or an experienced contributor interested in sponsoring this change if it proves worthwhile?
> 
> Thank you for your time and consideration.
> 
> Best regards,
> Memory2314



More information about the core-libs-dev mailing list