我想知道如何改进这个非常简单的代码。
代码极其冗长,两个 for 循环绝对不实用或简洁。
我正在考虑使用
Stream.iterate().limit(LAST_DAY_MONTH)
,但是当我们需要返回值时它并不能解决。
public class WeekDaysPerMonth {
public Map getNumberWeekDaysPerMonth(int year) {
Map<Integer, Integer> weekDays = new Hashtable<>();
for (int monthCount = 1; monthCount <= 12; monthCount++) {
int daysCount = 0;
final int LAST_DAY_MONTH = getLastDayMonth(monthCount, year);
for (int day = 1; day <= LAST_DAY_MONTH; day++) {
final int weekDay = LocalDate.of(year, monthCount, day).getDayOfWeek().getValue();
daysCount = daysCount + (
(weekDay != DayOfWeek.SATURDAY.getValue()
&& weekDay != DayOfWeek.SUNDAY.getValue())
? 1 : 0);
}
weekDays.put(monthCount, daysCount);
}
return weekDays;
}
private int getLastDayMonth(int month, int year) {
final boolean yearBiSexto = (year % 4 ) == 0;
Map<Integer, Integer> lastDayMontMap = new HashMap<Integer, Integer>() {{
put(1, 31);
put(2, yearBiSexto ? 29 : 28);
put(3, 31);
put(4, 30);
put(5, 31);
put(6, 30);
put(7, 31);
put(8, 31);
put(9, 30);
put(10, 31);
put(11, 30);
put(12, 31);
}};
return lastDayMontMap.get(month);
}
这是我们提供2022年时的结果。
mes : 1 - mes : 21
mes : 2 - mes : 20
mes : 3 - mes : 23
mes : 4 - mes : 21
mes : 5 - mes : 22
mes : 6 - mes : 22
mes : 7 - mes : 21
mes : 8 - mes : 23
mes : 9 - mes : 22
mes : 10 - mes : 21
mes : 11 - mes : 22
mes : 12 - mes : 22
拜托,任何改进都会很棒!
基于实现java.timeJava 8。
import java.time.DayOfWeek;
import java.time.Month;
import java.time.YearMonth;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Main {
public static void main(String args[]){
Map<String, Long> map = getNumberWeekDaysPerMonth(2022);
for (Map.Entry<String, Long> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue().toString());
}
}
public static Map<String, Long> getNumberWeekDaysPerMonth(int year) {
Map<String, Long> weekDays = new LinkedHashMap<>();
EnumSet<DayOfWeek> weekends = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY );
Stream.of(Month.values()).forEach(month -> {
YearMonth yearMonth = YearMonth.of(year, month);
long countWeekDays = IntStream.rangeClosed(1, yearMonth.lengthOfMonth()).filter(day ->
!weekends.contains(yearMonth.atDay(day).getDayOfWeek())
).count();
weekDays.put(month.toString(), countWeekDays);
}
);
return weekDays;
}
}
输出:
JANUARY:21
FEBRUARY:20
MARCH:23
APRIL:21
MAY:22
JUNE:22
JULY:21
AUGUST:23
SEPTEMBER:22
OCTOBER:21
NOVEMBER:22
DECEMBER:22
YearMonth - 是一个不可变的日期时间对象,表示年和月的组合
Month - 是代表一年中 12 个月的枚举
LocalDate.getDayOfWeek() - 获取日期的星期几。
编辑:收集到一个流,但前一个变体更容易理解
public static Map<String, Long> getNumberWeekDaysPerMonth(int year) {
EnumSet<DayOfWeek> weekends = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY );
return Stream.of(Month.values()).collect(Collectors.toMap(
Enum::toString,
month -> IntStream.rangeClosed(1, YearMonth.of(year, month).lengthOfMonth()).
filter(day -> !weekends.contains(LocalDate.of(year, month, day).getDayOfWeek())).
count(),
(e1, e2) -> e1,
LinkedHashMap::new));
}
这是一个基于流的解决方案,它使用
Map
将值收集到
Collectors.toMap
中,并利用 Java 时间 API(您已经在使用)来确定有关所涉及的日期和月份的详细信息:
public Map<Integer, Integer> getNumberWeekDaysPerMonth(int year) {
EnumSet<DayOfWeek> weekDays = EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY);
return Arrays.stream(Month.values())
.map(month -> YearMonth.of(year, month))
.collect(Collectors.toMap(
YearMonth::getMonthValue,
yearMonth -> (int) IntStream.rangeClosed(1, yearMonth.lengthOfMonth())
.mapToObj(d -> yearMonth.atDay(d).getDayOfWeek())
.filter(weekDays::contains)
.count()));
}
valueMapper
的第二个参数Collectors.toMap
获取给定月份的天数。 它采用给定的 YearMonth
并流式传输该月从 1 到该月最后一天的所有天数。 它将这些天映射到星期几,使用 YearMonth.atDay
将日期转换为 LocalDate
,并使用 LocalDate.getDayOfWeek
获取该特定日期的 DayOfWeek
。 然后,它将流过滤为仅工作日,并使用 Stream.count
获取剩余项目的计数。