英文:
How do I put months in each array?
问题
我正在制作一个用于统计一个月内花费的程序;然而,我不知道在for循环中应该做什么,以便使其按正确顺序使用相应的月份名称初始化每个MonthlyExpensePeriods
?
for (int i = 0; i < 12; i++) {
monthlyExpensePeriods[i] = new MonthlyExpensePeriods(月份名称);
}
英文:
I'm making a program for expense statistics over a month; however, I don't know what I should do in the for loop in order to make it initialize each MonthlyExpensePeriods
with the corresponding name of that month in the correct order?
for(int i = 0; i < 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriods(month's name);
}
答案1
得分: 1
你可以使用 DateFormatSymbols.getMonths()
方法:
String[] monthNames = new DateFormatSymbols().getMonths();
for (int i = 0; i < 12; i++) {
monthlyExpensePeriods[i] = new MonthlyExpensePeriods(monthNames[i]);
}
英文:
You could use DateFormatSymbols.getMonths()
:
String[] monthNames = new DateFormatSymbols().getMonths();
for(int i = 0; i < 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriods(monthNames[i]);
}
答案2
得分: 1
# tl;dr
使用`Month`枚举对象而不是仅仅使用月份名称的文本。
for(int i = 1; i <= 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriod( Month.of( i ) );
}
# 使用智能对象,而不是愚蠢的字符串
对于特殊值(例如追踪一年中的每个月份),使用字符串是脆弱且容易出错的。
# `Month`
相反,使用对象。
在Java 8及更高版本中,我们内置了[`Month`][1]枚举类。此枚举预定义了十二个对象,每个对象代表一年中的一个月,并分配了命名常量。
你的类`MonthlyExpensePeriod`应该持有一个类型为`Month`的成员变量。
public class MonthlyExpensePeriod {
// 成员字段
public Month month ;
…
// 构造函数
public MonthlyExpensePeriod( final Month monthArg ) {
this.month = monthArg ;
…
}
}
要使用该类及其构造函数,传递其中一个命名常量。
new MonthlyExpensePeriod ( Month.MARCH )
你可以通过月份编号检索`Month`对象之一。请注意合理的编号,1到12分别代表一月到十二月。
Month month = Month.of( 3 ) ; // Month.MARCH
因此,你的示例代码将如下所示。将你的`for`循环改为计数1到12。
for(int i = 1; i <= 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriod( Month.of( i ) );
}
## 集合
你可能希望使用[Java集合][2]而不是仅仅使用数组。
List< MonthlyExpensePeriod > periods = new ArrayList<>( 12 ) ;
for(int i = 1; i <= 12; i++){
MonthlyExpensePeriod period = new MonthlyExpensePeriod( Month.of( i ) ) ;
periods.add( period );
}
## 流式处理
我想我们可以使用流式处理来变得更加高级,但在这种情况下我没有看到任何附加价值。
调用[`Month.values()`][3]返回一个数组,其中包含按照定义顺序排列的所有枚举对象。我们可以通过调用实用类方法[`Arrays.stream`][4]生成一个流。
List < MonthlyExpensePeriod > periods =
Arrays.stream( Month.values() )
.map( month -> new MonthlyExpensePeriod( month ) )
.collect( Collectors.toList() )
;
或者作为单行代码。
List < MonthlyExpensePeriod > periods = Arrays.stream( Month.values() ).map( month -> new MonthlyExpensePeriod( month ) ).collect( Collectors.toList() );
你可能希望创建一个不可修改的副本列表。
List < MonthlyExpensePeriod > periodsUnmod = List.copyOf( periods );
或者通过调用`Collectors.toUnmodifiableList()`将原始列表设置为不可修改,详情请参阅[这里的讨论][5]。
List < MonthlyExpensePeriod > periods =
Arrays
.stream( Month.values() )
.map( month -> new MonthlyExpensePeriod( month ) )
.collect( Collectors.toUnmodifiableList() )
;
## 生成显示文本
你可能希望显示月份的名称。
调用`Month::toString`会生成全大写的英文名称文本。但你可以自动进行本地化处理。
要进行本地化处理,传递一个[`TextStyle`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/TextStyle.html)对象,以指示你希望名称的长度或缩写程度。请注意,`TextStyle`提供了`STANDALONE`变体,用于某些语言(不是英语),其中月份名称出现在日期上下文之外。
并传递一个`Locale`来确定用于本地化的人类语言和文化规范。
Locale locale = Locale.CANADA_FRENCH ; // 或 Locale.US 等等。
String output = Month.MARCH.getDisplayName( TextStyle.FULL , locale ) ;
[1]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Month.html
[2]: https://en.wikipedia.org/wiki/Java_collections_framework
[3]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Month.html#values()
[4]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Arrays.html
[5]: https://stackoverflow.com/q/61132631/642706
英文:
tl;dr
Use Month
enum objects rather than mere text of name of month.
for(int i = 1; i <= 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriod( Month.of( i ) );
}
Use smart objects, not dumb strings
Using strings for special values, such as tracking each month of the year, is fragile and error-prone.
Month
Instead, use objects.
In Java 8 and later, we have the Month
enum class built-in. This enum predefines a dozen objects, one for each month of the year, each assigned to a named constant.
Your class MonthlyExpensePeriod
should hold a member variable of type Month
.
public class MonthlyExpensePeriod {
// Member fields
public Month month ;
…
// Constructor
public MonthlyExpensePeriod( final Month monthArg ) {
this.month = monthArg ;
…
}
}
To use that class and its constructor, pass one of the named constants.
new MonthlyExpensePeriod ( Month.MARCH )
You can retrieve one of the Month
objects by month number. Notice the sane numbering, 1-12 for January-December.
Month month = Month.of( 3 ) ; // Month.MARCH
So your example code would look like the following. Change your for
loop to count 1-12.
for(int i = 1; i <= 12; i++){
monthlyExpensePeriods[i] = new MonthlyExpensePeriod( Month.of( i ) );
}
Collections
You may want to use Java Collections rather than mere arrays.
List< MonthlyExpensePeriod > periods = new ArrayList<>( 12 ) ;
for(int i = 1; i <= 12; i++){
MonthlyExpensePeriod period = new MonthlyExpensePeriod( Month.of( i ) ) ;
periods.add( period );
}
Streams
I suppose we could get fancy and use streams. But in this case I do not see any added-value.
Calling Month.values()
returns an array of all the objects defined on the enum, in the order in which they were defined. From that, we can generate a stream by calling the utility class method Arrays.stream
.
List < MonthlyExpensePeriod > periods =
Arrays.stream( Month.values() )
.map( month -> new MonthlyExpensePeriod( month ) )
.collect( Collectors.toList() )
;
Or as a single-line of code.
List < MonthlyExpensePeriod > periods = Arrays.stream( Month.values() ).map( month -> new MonthlyExpensePeriod( month ) ).collect( Collectors.toList() );
You might want to make an unmodifiable copy of your list.
List < MonthlyExpensePeriod > periodsUnmod = List.copyOf( periods );
Or make the original list unmodifiable, by calling Collectors.toUnmodifiableList()
, as discussed here.
List < MonthlyExpensePeriod > periods =
Arrays
.stream( Month.values() )
.map( month -> new MonthlyExpensePeriod( month ) )
.collect( Collectors.toUnmodifiableList() )
;
Generating display text
You may want to display the name of the month.
Calling Month::toString
generates text of the name in English in all caps. Instead you can automatically localize.
To localize, pass a TextStyle
object to signal how long or abbreviated you want the name. Notice that TextStyle
offers STANDALONE
variations used in some languages (not English) where the month name appears outside the context of a date.
And pass a Locale
to determine the human language and cultural norms to use in localizing.
Locale locale = Locale.CANADA_FRENCH ; // Or Locale.US and so on.
String output = Month.MARCH.getDisplayName( TextStyle.FULL , locale ) ;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论