tl;dr
In 2 lines, using streams and lambda syntax.
Year currentYear = Year.now( ZoneId.of( "Pacific/Auckland" ) ); // Determining the current year requires a time zone when near the ending/beginning of the year.
List < Year > years = // A list of objects of the class `Year`. Better to use a specific type than use a mere integer number.
IntStream // Generates a stream of `int` primitive numbers.
.range( // Get numbers from the specified beginning to the specified ending.
currentYear.getValue() , // Get `int` number of the current year.
currentYear.plusYears( 10 ).getValue() // Yet the `int` number of a later year.
) // Returns a `IntStream` object.
.boxed() // Converts the `int` primitive values into a stream of `Integer` objects.
.map( integer -> Year.of( integer ) ) // Uses each `Integer` object to instantiate a `Year` object. The `Integer` object is auto-boxed back into an `int` primitive`. Primitives cannot be mapped in a stream with a lambda. So we had to do this funky `int` -> `Integer` -> `int` conversion juggling.
.collect( Collectors.toList() ) // Gather the `Year` objects produced by the `map` method into a `List` collection.
;
In a few lines, using conventional syntax.
Year currentYear = Year.now( ZoneId.of( "Asia/Tokyo" ) ) ;
List< Year > years = new ArrayList<>( 10 ) ;
for( int i = 0 ; i < 10 ; i ++ )
{
years.add( currentYear.plusYears( i ) ) ;
}
See this code run live at IdeOne.com.
years.toString(): [2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029]
java.time.Year
Java offers a specific class to represent a year, appropriately named Year
. I suggest using that class rather than a mere integer to make your code type-safe and more self-documenting.
Time zone is crucial
Getting the current year requires a time zone. For any given moment, the date various around the world by time zone. While "tomorrow" in Tokyo Japan, it is simultaneously "yesterday" in Montréal Québec.
Therefore, around the last day / first day of the year, it may be "next year" in Tokyo Japan while simultaneously "last year" in Montréal Québec. So when determining the current year, specify the desired/expected time zone.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
Year currentYear = Year.now( z ) ;
Get your next ten years by iterating.
List< Year > years = new ArrayList<>( 10 ) ;
Year year = currentYear ;
for( int i = 0 ; i < 10 ; i ++ )
{
// Remember this year.
years.add( year ) ;
// Set up the next loop.
year = currentYear.plusYears( i ) ;
}
Make an unmodifiable list from that ArrayList
by calling List.copyOf
.
List< Year > years = List.copyOf( years ) ; // Returns an unmodifiable `List`, with adding/removing elements disallowed.
java.time.Month
For expiration year-month, you also need the a widget for picking month. There you can use the Month
class.
List< Month > months = List.copyOf( Month.values() )
The toString
method of Month
gives you the name of the month in English in all uppercase, based on the name of enum element. You might want to make a list of localized names for display to users.
List< String > monthsLocalized = new ArrayList<>( months.size() ) ;
Locale locale = Locale.CANADA_FRENCH ;
for( Month month : months )
{
monthsLocalized.add( month.getDisplayName( TextStyle.FULL , locale ) ;
}
monthsLocalized = List.copyOf( monthsLocalized ) ;
java.time.YearMonth
For your final result of a user picking a year and a month, use YearMonth
. Oddly, the YearMonth
factory methods do not take a Year
object, only a mere integer. So call Year::getValue
to get the number.
YearMonth yearMonth = YearMonth.of( selectedYear.getValue() , selectedMonth ) ;
Premature Optimization
You expressed concern about optimizing for performance. This is not the kind of code you need to optimize. Indeed, do not fall into the trap of premature optimization. Even the most experienced programmers have been shown to be notoriously bad at intuitively guessing where the bottlenecks live in their codebase. Optimize only after having empirically proven a significant slowdown that materially affects the performance of your code and the running of the business. Most often, writing simple straightforward short lines of Java code will result in highly optimized executing code after the Java compiler and runtime optimizer (HotSpot, OpenJ9) do their job.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?