Skip to main content
 首页 » 编程设计

performance之为什么这个 Java 代码有这个年龄验证日期比较

2025年05月04日18pengyingh

Here is a responsequestion关于用 Java 计算年龄。

/** 
 * This Method is unit tested properly for very different cases ,  
 * taking care of Leap Year days difference in a year,  
 * and date cases month and Year boundary cases (12/31/1980, 01/01/1980 etc) 
**/ 
 
public static int getAge(Date dateOfBirth) { 
 
    Calendar today = Calendar.getInstance(); 
    Calendar birthDate = Calendar.getInstance(); 
 
    int age = 0; 
 
    birthDate.setTime(dateOfBirth); 
    if (birthDate.after(today)) { 
        throw new IllegalArgumentException("Can't be born in the future"); 
    } 
 
    age = today.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR); 
 
    // If birth date is greater than todays date (after 2 days adjustment of leap year) then decrement age one year    
    if ( (birthDate.get(Calendar.DAY_OF_YEAR) - today.get(Calendar.DAY_OF_YEAR) > 3) || 
            (birthDate.get(Calendar.MONTH) > today.get(Calendar.MONTH ))){ 
        age--; 
 
     // If birth date and todays date are of same month and birth day of month is greater than todays day of month then decrement age 
    }else if ((birthDate.get(Calendar.MONTH) == today.get(Calendar.MONTH )) && 
              (birthDate.get(Calendar.DAY_OF_MONTH) > today.get(Calendar.DAY_OF_MONTH ))){ 
        age--; 
    } 
 
    return age; 
} 

这段代码运行得很好,但为什么会有这样的比较: (birthDate.get(Calendar.DAY_OF_YEAR) - Today.get(Calendar.DAY_OF_YEAR) > 3)

我甚至创建了一个巨大的电子表格,其中包含一年中所有天的差异,试图了解它可能涵盖哪些情况,但我没有看到其他比较未涵盖的任何内容。谁能解释一下这种比较背后的目的吗?它在某些方面是否更有效?

请您参考如下方法:

以下代码示例来自 ThreetenBP (Java-8 的向后移植)支持不需要进行年中日期检查的声明:

@Override  
public long until(Temporal endExclusive, TemporalUnit unit) {  
LocalDate end = LocalDate.from(endExclusive);  
    if (unit instanceof ChronoUnit) {  
         switch ((ChronoUnit) unit) {  
             case DAYS: return daysUntil(end);  
             case WEEKS: return daysUntil(end) / 7;  
             case MONTHS: return monthsUntil(end);  
             case YEARS: return monthsUntil(end) / 12;  
             case DECADES: return monthsUntil(end) / 120;  
             case CENTURIES: return monthsUntil(end) / 1200;  
             case MILLENNIA: return monthsUntil(end) / 12000;  
             case ERAS: return end.getLong(ERA) - getLong(ERA);  
         }  
         throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);  
     }  
     return unit.between(this, end);  
}  
 
[...]      
 
private long monthsUntil(LocalDate end) {  
   long packed1 = getProlepticMonth() * 32L + getDayOfMonth();  // no overflow  
   long packed2 = end.getProlepticMonth() * 32L + end.getDayOfMonth();  // no overflow  
   return (packed2 - packed1) / 32;  
}  

case YEARS: return MonthsUntil(end)/12; (表达式 birthday.until(today, YEARS)YEARS. Between(birthday ,今天) 是等价的 - 一个委托(delegate)给另一个)利用与 OP 引用的以下简化代码相同的算法,并且不引用任何一年中的日期检查:

age = today.get(Calendar.YEAR) - birthDate.get(Calendar.YEAR); 
 
if (birthDate.get(Calendar.MONTH) > today.get(Calendar.MONTH)) { 
    age--; 
}else if ((birthDate.get(Calendar.MONTH) == today.get(Calendar.MONTH )) && 
          (birthDate.get(Calendar.DAY_OF_MONTH) > today.get(Calendar.DAY_OF_MONTH ))){ 
    age--; 
} 

问题出现了:为什么要进行年度检查?

a) 发帖者最初认真对待了一年中的某一天的想法,然后在后来的版本中忘记了清理

b) 发帖者希望“提高”表现

如果认真对待并作为完整版本,以下 Java-8 代码演示了基于日期的算法的问题(库的选择在这里不相关,只有算法很重要):

LocalDate birthday = LocalDate.of(2001, 3, 6); 
LocalDate today = LocalDate.of(2016, 3, 5); // leap year 
 
int age = today.getYear() - birthday.getYear(); 
if (birthday.getDayOfYear() > today.getDayOfYear()) { 
    age--; 
} 
System.out.println("age based on day-of-year: " + age); // 15 (wrong) 
System.out.println("age based on month and day-of-month: "  
  + ChronoUnit.YEARS.between(birthday, today)); // 14 (correct) 

结论:

您引用的提议的年份条款只是噪音,因为算法的其余部分对应于 Java-8 的功能。也许年中日期检查源自提议代码的一些早期的基于年中日期的版本,并且尚未清理。

为了回答你的最后一个问题:像这样不必要的检查是不好的。就性能而言是高效的(尽管我们在这里讨论的是微优化)。