-
-
Save onacit/b06c3f33ece93939e55f379ac569f468 to your computer and use it in GitHub Desktop.
Sexagenary cycle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package p_b06c3f33ece93939e55f379ac569f468; | |
import java.util.Collections; | |
import java.util.EnumMap; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* Constants of <a href="https://en.wikipedia.org/wiki/Earthly_Branches">Earthly Branches</a>. | |
* | |
* @author Jin Kwon <onacit_at_gmail.com> | |
* @see <a href="https://en.wikipedia.org/wiki/Earthly_Branches">Earthly Branches</a> | |
* @see <a href="https://ko.wikipedia.org/wiki/%EC%A7%80%EC%A7%80_(%EC%97%AD%EB%B2%95)">지지 (역법)</a> | |
*/ | |
public enum 地支 { // \u5730\u652f 지지(\uc9c0\uc9c0) | |
子, // 자 | |
丑, // 축 | |
寅, // 인 | |
卯, // 묘 | |
辰, // 진 | |
巳, // 사 | |
午, // 오 | |
未, // 미 | |
申, // 신 | |
酉, // 유 | |
戌, // 술 | |
亥; // 해 | |
// ----------------------------------------------------------------------------------------------------------------- | |
static final String REGEXP_NAME = "[\u5b50\u4e11\u5bc5\u536f\u8fb0\u5df3\u5348\u672a\u7533\u9149\u620c\u4ea5]"; | |
static final String REGEXP_KOREAN_NAME | |
= "[\uc790\ucd95\uc778\ubb18\uc9c4\uc0ac\uc624\ubbf8\uc2e0\uc720\uc220\ud574]"; | |
private static final Map<地支, String> KOREAN_NAMES_BY_VALUES; | |
static { | |
final Map<地支, String> m = new EnumMap<>(地支.class); | |
m.put(子, "자"); | |
m.put(丑, "축"); | |
m.put(寅, "인"); | |
m.put(卯, "묘"); | |
m.put(辰, "진"); | |
m.put(巳, "사"); | |
m.put(午, "오"); | |
m.put(未, "미"); | |
m.put(申, "신"); | |
m.put(酉, "유"); | |
m.put(戌, "술"); | |
m.put(亥, "해"); | |
KOREAN_NAMES_BY_VALUES = Collections.unmodifiableMap(m); | |
} | |
private static final Map<String, 地支> VALUES_BY_KOREAN_NAMES; | |
static { | |
final Map<String, 地支> m = new HashMap<>(); | |
KOREAN_NAMES_BY_VALUES.forEach((k, v) -> m.put(v, k)); | |
VALUES_BY_KOREAN_NAMES = Collections.unmodifiableMap(m); | |
} | |
public static 地支 valueOfKoreanName(final String koreanName) { | |
return VALUES_BY_KOREAN_NAMES.get(koreanName); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
public String koreanName() { | |
return KOREAN_NAMES_BY_VALUES.get(this); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
public 地支 getPrevious() { | |
地支 p = previous; | |
if (p == null) { | |
final 地支[] values = values(); | |
if (ordinal() == 0) { | |
previous = p = values[values.length - 1]; | |
} else { | |
previous = p = values()[ordinal() - 1]; | |
} | |
} | |
return p; | |
} | |
public 地支 getNext() { | |
地支 n = next; | |
if (n == null) { | |
final 地支[] values = values(); | |
if (ordinal() == values.length - 1) { | |
next = n = values[0]; | |
} else { | |
next = n = values()[ordinal() + 1]; | |
} | |
} | |
return n; | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
private volatile 地支 previous; | |
private volatile 地支 next; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package p_b06c3f33ece93939e55f379ac569f468; | |
import java.util.Collections; | |
import java.util.EnumMap; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* Constants of <a href="https://en.wikipedia.org/wiki/Heavenly_Stems">Heavenly Stems</a>. | |
* | |
* @author Jin Kwon <onacit_at_gmail.com> | |
* @see <a href="https://en.wikipedia.org/wiki/Heavenly_Stems">Heavenly Stems</a> | |
* @see <a href="https://ko.wikipedia.org/wiki/%EC%B2%9C%EA%B0%84">천간</a> | |
*/ | |
public enum 天干 { // 天干(\u5929\u5e72) 천간(\ucc9c\uac04) | |
甲, // 갑 | |
乙, // 을 | |
丙, // 병 | |
丁, // 정 | |
戊, // 무 | |
己, // 기 | |
庚, // 경 | |
辛, // 신 | |
壬, // 임 | |
癸; // 계 | |
// ----------------------------------------------------------------------------------------------------------------- | |
static final String REGEXP_NAME = "[\u7532\u4e59\u4e19\u4e01\u620a\u5df1\u5e9a\u8f9b\u58ec\u7678]"; | |
static final String REGEXP_KOREAN_NAME = "[\uac11\uc744\ubcd1\uc815\ubb34\uae30\uacbd\uc2e0\uc784\uacc4]"; | |
// ----------------------------------------------------------------------------------------------------------------- | |
private static final Map<天干, String> KOREAN_NAMES_BY_VALUES; | |
static { | |
final Map<天干, String> m = new EnumMap<>(天干.class); | |
m.put(甲, "갑"); | |
m.put(乙, "을"); | |
m.put(丙, "병"); | |
m.put(丁, "정"); | |
m.put(戊, "무"); | |
m.put(己, "기"); | |
m.put(庚, "경"); | |
m.put(辛, "신"); | |
m.put(壬, "임"); | |
m.put(癸, "계"); | |
KOREAN_NAMES_BY_VALUES = Collections.unmodifiableMap(m); | |
} | |
private static final Map<String, 天干> VALUES_BY_KOREAN_NAMES; | |
static { | |
final Map<String, 天干> m = new HashMap<>(); | |
KOREAN_NAMES_BY_VALUES.forEach((k, v) -> m.put(v, k)); | |
VALUES_BY_KOREAN_NAMES = Collections.unmodifiableMap(m); | |
} | |
/** | |
* Returns the value of specified Korean name. | |
* | |
* @param koreanName the Korean name. | |
* @return the value of specified Korean name. | |
*/ | |
public static 天干 valueOfKoreanName(final String koreanName) { | |
return VALUES_BY_KOREAN_NAMES.get(koreanName); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the Korean name of this 天干. | |
* | |
* @return the Korean name of this 天干. | |
*/ | |
public String koreanName() { | |
return KOREAN_NAMES_BY_VALUES.get(this); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the previous value of this 天干. | |
* | |
* @return the previous value of this 天干. | |
*/ | |
public 天干 getPrevious() { | |
天干 p = previous; | |
if (p == null) { | |
final 天干[] values = values(); | |
if (ordinal() == 0) { | |
previous = p = values[values.length - 1]; | |
} else { | |
previous = p = values()[ordinal() - 1]; | |
} | |
} | |
return p; | |
} | |
/** | |
* Returns the next value of this 天干. | |
* | |
* @return the next value of this 天干. | |
*/ | |
public 天干 getNext() { | |
天干 n = next; | |
if (n == null) { | |
final 天干[] values = values(); | |
if (ordinal() == values.length - 1) { | |
next = n = values[0]; | |
} else { | |
next = n = values()[ordinal() + 1]; | |
} | |
} | |
return n; | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
private volatile 天干 previous; | |
private volatile 天干 next; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package p_b06c3f33ece93939e55f379ac569f468; | |
import java.time.Month; | |
import java.time.Year; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.EnumMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Objects; | |
import static java.util.Objects.requireNonNull; | |
import static java.util.Optional.ofNullable; | |
/** | |
* A class for <a href="https://en.wikipedia.org/wiki/Sexagenary_cycle">Sexagenary cycle</a>. | |
* | |
* @author Jin Kwon <onacit_at_gmail.com> | |
* @see <a href="https://en.wikipedia.org/wiki/Sexagenary_cycle">Sexagenary cycle</a> | |
* @see <a href="https://ko.wikipedia.org/wiki/%EA%B0%84%EC%A7%80">간지</a> | |
*/ | |
public final class 干支 { // \u5e72\u652f 간지(\uac04\uc9c0) | |
// ----------------------------------------------------------------------------------------------------------------- | |
abstract static class Assigned<T extends Assigned<T>> implements Comparable<T>, Cloneable { | |
Assigned(final 干支 干支) { | |
super(); | |
this.干支 = 干支; | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns a string representation of the object. | |
* | |
* @return a string representation of the object. | |
*/ | |
@Override | |
public String toString() { | |
return super.toString() + '{' | |
+ "干支=" + 干支 | |
+ '}'; | |
} | |
/** | |
* Indicates whether some other object is "equal to" this one. | |
* | |
* @param o the reference object with which to compare. | |
* @return {@code true} if this object is the same as the obj argument; {@code false} otherwise. | |
*/ | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
Assigned<?> assigned = (Assigned<?>) o; | |
return Objects.equals(干支, assigned.干支); | |
} | |
/** | |
* Returns a hash code value for the object. | |
* | |
* @return a hash code value for this object. | |
*/ | |
@Override | |
public int hashCode() { | |
return Objects.hash(干支); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
@Override | |
@SuppressWarnings({"unchecked"}) | |
public T clone() throws CloneNotSupportedException { | |
return (T) super.clone(); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the 干支 of this object. | |
* | |
* @return the 干支 of this object. | |
* @see #getGanzhi() | |
*/ | |
public 干支 get干支() { | |
return 干支; | |
} | |
/** | |
* Returns the ganzhi of this object. | |
* | |
* @return the ganzhi of this object. | |
* @see #get干支() | |
*/ | |
public 干支 getGanzhi() { | |
return get干支(); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
private final 干支 干支; // may be null | |
} | |
/** | |
* Represents a 干支 assigned to a specific year. | |
* | |
* @author Jin Kwon <onacit_at_gmail.com> | |
* @see <a href="https://ko.wikipedia.org/wiki/%EC%84%B8%EC%B0%A8_(%EA%B0%84%EC%A7%80)">세차 (간지)</a> | |
*/ | |
public static class 歲次 extends Assigned<歲次> { // 세차 | |
static final Comparator<歲次> COMPARING_YEAR = Comparator.comparing(歲次::getYear); | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Creates a new instance with specified 干支 and year. | |
* | |
* @param 干支 the 干支. | |
* @param year the year. | |
*/ | |
public 歲次(final 干支 干支, final Year year) { | |
super(requireNonNull(干支, "干支 is null")); | |
this.year = requireNonNull(year, "year is null"); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns a string representation of the object. | |
* | |
* @return a string representation of the object. | |
*/ | |
@Override | |
public String toString() { | |
return super.toString() + '{' | |
+ "year=" + year | |
+ '}'; | |
} | |
/** | |
* Indicates whether some other object is "equal to" this one. | |
* | |
* @param o the reference object with which to compare. | |
* @return {@code true} if this object is the same as the obj argument; {@code false} otherwise. | |
*/ | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
if (!super.equals(o)) return false; | |
歲次 歲次 = (歲次) o; | |
return year.equals(歲次.year); | |
} | |
/** | |
* Returns a hash code value for the object. | |
* | |
* @return a hash code value for this object. | |
*/ | |
@Override | |
public int hashCode() { | |
return Objects.hash(super.hashCode(), year); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
@Override | |
public int compareTo(final 歲次 o) { | |
return COMPARING_YEAR.compare(this, o); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the previous value of this 歲次. | |
* | |
* @return the previous value of this 歲次. | |
*/ | |
public 歲次 getPrevious() { | |
return new 歲次(get干支().getPrevious(), year.minusYears(1L)); | |
} | |
/** | |
* Returns the next value of this 歲次. | |
* | |
* @return the next value of this 歲次. | |
*/ | |
public 歲次 getNext() { | |
return new 歲次(get干支().getNext(), year.plusYears(1L)); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the year of this 歲次. | |
* | |
* @return the year of this 歲次. | |
*/ | |
public Year getYear() { | |
return year; | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
private final Year year; | |
} | |
/** | |
* Represents a 干支 assigned to a specific month of a year. | |
* | |
* @author Jin Kwon <onacit_at_gmail.com> | |
* @see <a href="https://ko.wikipedia.org/wiki/%EC%9B%94%EA%B1%B4">월건</a> | |
*/ | |
public static class 月建 extends Assigned<月建> { // 월건 | |
static final Comparator<月建> LEAP_MONTH_FIRST = (o1, o2) -> Boolean.compare(o1.isLeapMonth(), o2.isLeapMonth()); | |
static final Comparator<月建> LEAP_MONTH_LAST = (o1, o2) -> LEAP_MONTH_FIRST.compare(o2, o1); | |
static final Comparator<月建> COMPARING_歲次_THEN_COMPARING_MONTH | |
= Comparator.comparing(月建::get歲次).thenComparing(月建::getMonth); | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Creates a new instance with specified 歲次 and month representing a leap month. | |
* | |
* @param 歲次 the 歲次. | |
* @param month the month. | |
* @return a new instance represents a leap month. | |
*/ | |
public static 月建 ofLeapMonth(final 歲次 歲次, final Month month) { | |
return new 月建(null, 歲次, month); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Creates a new instance with specified 干支, 歲次, and month. | |
* | |
* @param 干支 the 干支; {@code null} for a leap month. | |
* @param 歲次 the 歲次. | |
* @param month the month. | |
*/ | |
public 月建(final 干支 干支, final 歲次 歲次, final Month month) { | |
super(干支); | |
this.歲次 = requireNonNull(歲次, " 歲次 is null"); | |
this.month = requireNonNull(month, "month is null"); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns a string representation of the object. | |
* | |
* @return a string representation of the object. | |
*/ | |
@Override | |
public String toString() { | |
return super.toString() + '{' | |
+ "歲次=" + 歲次 | |
+ ",month=" + month | |
+ '}'; | |
} | |
/** | |
* Indicates whether some other object is "equal to" this one. | |
* | |
* @param o the reference object with which to compare. | |
* @return {@code true} if this object is the same as the obj argument; {@code false} otherwise. | |
*/ | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
if (!super.equals(o)) return false; | |
月建 月建 = (月建) o; | |
return 歲次.equals(月建.歲次) && month == 月建.month; | |
} | |
/** | |
* Returns a hash code value for the object. | |
* | |
* @return a hash code value for this object. | |
*/ | |
@Override | |
public int hashCode() { | |
return Objects.hash(super.hashCode(), 歲次, month); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
@Override | |
public int compareTo(final 月建 o) { | |
return COMPARING_歲次_THEN_COMPARING_MONTH.thenComparing(LEAP_MONTH_LAST).compare(this, o); | |
} | |
// // ------------------------------------------------------------------------------------------------------------- | |
// | |
// /** | |
// * Returns the previous value of this 月建. | |
// * | |
// * @return the previous value of this 月建. | |
// */ | |
// public 月建 getPrevious() { | |
// return new 月建(get干支().getPrevious(), month == Month.JANUARY ? 歲次.getPrevious() : 歲次, month.minus(1L)); | |
// } | |
// | |
// /** | |
// * Returns the next value of this 月建. | |
// * | |
// * @return the next value of this 月建. | |
// */ | |
// public 月建 getNext() { | |
// return new 月建(get干支().getNext(), month == Month.DECEMBER ? 歲次.getNext() : 歲次, month.plus(1L)); | |
// } | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the 歲次 of this 月建. | |
* | |
* @return the 歲次 of this 月建. | |
*/ | |
public 歲次 get歲次() { | |
return 歲次; | |
} | |
/** | |
* Returns the year of this the 月建. | |
* | |
* @return the year of this the 月建. | |
*/ | |
public Year getYear() { | |
return get歲次().getYear(); | |
} | |
/** | |
* Returns the month of this the 月建. | |
* | |
* @return the month of this the 月建. | |
*/ | |
public Month getMonth() { | |
return month; | |
} | |
/** | |
* Indicates whether this 月建 represents a leap month. | |
* | |
* @return {@code true} when this 月建 represents a a leap month; {@code false} otherwise. | |
*/ | |
public boolean isLeapMonth() { | |
return get干支() == null; | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
private final 歲次 歲次; | |
private final Month month; | |
} | |
/** | |
* Represents a 干支 assigned to a specific date. | |
* | |
* @author Jin Kwon <onacit_at_gmail.com> | |
* @see <a href="https://ko.wikipedia.org/wiki/%EC%9D%BC%EC%A7%84_(%EA%B0%84%EC%A7%80)">일진 (간지)</a> | |
*/ | |
public static class 日辰 extends Assigned<日辰> { // 일진 | |
static final Comparator<日辰> COMPARING_月建_THEN_COMPARING_DAY_OF_MOHTH = | |
Comparator.comparing(日辰::get月建).thenComparingInt(日辰::getDayOfMonth); | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Creates a new instance with specified 干支, 月建, and day of month. | |
* | |
* @param 干支 the 干支. | |
* @param 月建 the 月建. | |
* @param dayOfMonth the day of month. | |
*/ | |
public 日辰(final 干支 干支, final 月建 月建, final int dayOfMonth) { | |
super(requireNonNull(干支, "干支 is null")); | |
this.月建 = requireNonNull(月建, "月建 is null"); | |
if (dayOfMonth <= 0 || dayOfMonth > 30) { | |
throw new IllegalArgumentException("invalid dayOfMonth: " + dayOfMonth); | |
} | |
this.dayOfMonth = dayOfMonth; | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns a string representation of the object. | |
* | |
* @return a string representation of the object. | |
*/ | |
@Override | |
public String toString() { | |
return super.toString() + '{' | |
+ "月建=" + 月建 | |
+ ",dayOfMonth=" + dayOfMonth | |
+ '}'; | |
} | |
/** | |
* Indicates whether some other object is "equal to" this one. | |
* | |
* @param o the reference object with which to compare. | |
* @return {@code true} if this object is the same as the obj argument; {@code false} otherwise. | |
*/ | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
if (!super.equals(o)) return false; | |
日辰 日辰 = (日辰) o; | |
return dayOfMonth == 日辰.dayOfMonth && 月建.equals(日辰.月建); | |
} | |
/** | |
* Returns a hash code value for the object. | |
* | |
* @return a hash code value for this object. | |
*/ | |
@Override | |
public int hashCode() { | |
return Objects.hash(super.hashCode(), 月建, dayOfMonth); | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
@Override | |
public int compareTo(final 日辰 o) { | |
return COMPARING_月建_THEN_COMPARING_DAY_OF_MOHTH.compare(this, o); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the 月建 of this 日辰. | |
* | |
* @return the 月建 of this 日辰. | |
*/ | |
public 月建 get月建() { | |
return 月建; | |
} | |
/** | |
* Returns the year of this 日辰. | |
* | |
* @return the year of this 日辰. | |
*/ | |
public Year getYear() { | |
return get月建().getYear(); | |
} | |
/** | |
* Returns the month of this 日辰. | |
* | |
* @return the month of this 日辰. | |
*/ | |
public Month getMonth() { | |
return get月建().getMonth(); | |
} | |
/** | |
* Returns the day of month of this 日辰. | |
* | |
* @return the day of month of this 日辰. | |
*/ | |
public int getDayOfMonth() { | |
return dayOfMonth; | |
} | |
// ------------------------------------------------------------------------------------------------------------- | |
private final 月建 月建; | |
private final int dayOfMonth; | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
static final String REGEXP_NAME_GROUP_STEM = "stem"; | |
static final String REGEXP_NAME_GROUP_BRANCH = "branch"; | |
static final String REGEXP_NAME = "(?<" + REGEXP_NAME_GROUP_STEM + ">" + 天干.REGEXP_NAME + ")" | |
+ "(?<" + REGEXP_NAME_GROUP_BRANCH + ">" + 地支.REGEXP_NAME + ")"; | |
static final String REGEXP_KOREAN_NAME = "(?<" + REGEXP_NAME_GROUP_STEM + ">" + 天干.REGEXP_KOREAN_NAME + ")" | |
+ "(?<" + REGEXP_NAME_GROUP_BRANCH + ">" + 地支.REGEXP_KOREAN_NAME + ")"; | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* An unmodifiable list of all values. | |
*/ | |
public static final List<干支> VALUES; | |
static { | |
final List<干支> values = new ArrayList<>(); | |
{ | |
final 天干[] stems = 天干.values(); | |
final 地支[] branches = 地支.values(); | |
for (int s = 0, b = 0; ; s = ++s % stems.length, b = ++b % branches.length) { | |
values.add(new 干支(stems[s], branches[b])); | |
if (s == stems.length - 1 && b == branches.length - 1) { | |
break; | |
} | |
} | |
} | |
VALUES = Collections.unmodifiableList(values); | |
} | |
private static final Map<天干, Map<地支, 干支>> HASHED_VALUES; | |
static { | |
final Map<天干, Map<地支, 干支>> hashedValues = new EnumMap<>(天干.class); | |
VALUES.forEach(stemAndBranch -> { | |
hashedValues.computeIfAbsent(stemAndBranch.getStem(), k -> new EnumMap<>(地支.class)) | |
.compute(stemAndBranch.getBranch(), (k, v) -> { | |
assert v == null; | |
return stemAndBranch; | |
}); | |
}); | |
HASHED_VALUES = Collections.unmodifiableMap(hashedValues); | |
} | |
/** | |
* Returns the value of specified 天干 and 地支. | |
* | |
* @param 干 the 天干. | |
* @param 支 the 地支. | |
* @return the value of specified 天干 and 地支. | |
*/ | |
public static 干支 valueOf(final 天干 干, final 地支 支) { | |
requireNonNull(干, "干 is null"); | |
requireNonNull(支, "支 is null"); | |
return ofNullable(HASHED_VALUES.get(干)) | |
.map(m -> m.get(支)) | |
.orElseThrow(() -> new IllegalArgumentException("no value for " + 干 + " and " + 支)); | |
} | |
/** | |
* Returns the value associated to specified name. | |
* | |
* @param name the name. | |
* @return the value of {@code name}. | |
*/ | |
public static 干支 valueOfName(final String name) { | |
requireNonNull(name, "name is null"); | |
final int[] codepoints = name.chars().toArray(); | |
if (codepoints.length != 2) { | |
throw new IllegalArgumentException( | |
"invalid number of codepoints(" + codepoints.length + ") from " + name); | |
} | |
final 天干 干 = 天干.valueOf(new String(codepoints, 0, 1)); | |
final 地支 支 = 地支.valueOf(new String(codepoints, 1, 1)); | |
return valueOf(干, 支); | |
} | |
/** | |
* Returns the value associated to specified name in Korean. | |
* | |
* @param name the name. | |
* @return the value of {@code name}. | |
*/ | |
public static 干支 valueOfKoreanName(final String name) { | |
requireNonNull(name, "koreanName is null"); | |
final int[] codepoints = name.chars().toArray(); | |
if (codepoints.length != 2) { | |
throw new IllegalArgumentException( | |
"invalid number of codepoints(" + codepoints.length + ") from " + name); | |
} | |
final 天干 干 = 天干.valueOfKoreanName(new String(codepoints, 0, 1)); | |
final 地支 支 = 地支.valueOfKoreanName(new String(codepoints, 1, 1)); | |
return valueOf(干, 支); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Creates a new instance with specified 天干 and 地支. | |
* | |
* @param 干 the 天干. | |
* @param 支 the 地支. | |
*/ | |
private 干支(final 天干 干, final 地支 支) { | |
super(); | |
this.干 = requireNonNull(干, "干 is null"); | |
this.支 = requireNonNull(支, "支 is null"); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns a string representation of the object. | |
* | |
* @return a string representation of the object. | |
*/ | |
@Override | |
public String toString() { | |
return super.toString() + '{' | |
+ "干=" + 干 | |
+ ",支=" + 支 | |
+ '}'; | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Indicates whether some other object is "equal to" this one. | |
* | |
* @param o the reference object with which to compare. | |
* @return {@code true} if this object is the same as the obj argument; {@code false} otherwise. | |
*/ | |
@Override | |
public boolean equals(final Object o) { | |
if (this == o) { | |
return true; | |
} | |
if (o == null || getClass() != o.getClass()) { | |
return false; | |
} | |
final 干支 casted = (干支) o; | |
return 干 == casted.干 && 支 == casted.支; | |
} | |
/** | |
* Returns a hash code value for the object. | |
* | |
* @return a hash code value for this object. | |
*/ | |
@Override | |
public int hashCode() { | |
return Objects.hash(干, 支); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the previous value of this 干支. | |
* | |
* @return previous value of this 干支. | |
*/ | |
// http://jtechies.blogspot.com/2012/07/item-71-use-lazy-initialization.html | |
public 干支 getPrevious() { | |
干支 p = previous; | |
if (p == null) { | |
previous = p = valueOf(干.getPrevious(), 支.getPrevious()); | |
} | |
return p; | |
} | |
/** | |
* Returns the next value of this 干支. | |
* | |
* @return next value of this 干支. | |
*/ | |
// http://jtechies.blogspot.com/2012/07/item-71-use-lazy-initialization.html | |
public 干支 getNext() { | |
干支 n = next; | |
if (n == null) { | |
next = n = valueOf(干.getNext(), 支.getNext()); | |
} | |
return n; | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the name of this 干支. | |
* | |
* @return the name of this 干支. | |
* @see #valueOfName(String) | |
*/ | |
public String getName() { | |
return 干.name() + 支.name(); | |
} | |
/** | |
* Returns the Korean name of this 干支. | |
* | |
* @return the Korean name of this 干支. | |
* @see #valueOfKoreanName(String) | |
*/ | |
public String getKoreanName() { | |
return 干.koreanName() + 支.koreanName(); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the 天干 of this 干支. | |
* | |
* @return the 天干 of this 干支. | |
* @see #getStem() | |
*/ | |
public 天干 get干() { | |
return 干; | |
} | |
/** | |
* Returns the 天干 of this 干支. | |
* | |
* @return the 天干 of this 干支. | |
* @see #get干() | |
*/ | |
public 天干 getStem() { | |
return get干(); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
/** | |
* Returns the 地支 of this 干支. | |
* | |
* @return the 地支 of this 干支. | |
* @see #getBranch() | |
*/ | |
public 地支 get支() { | |
return 支; | |
} | |
/** | |
* Returns the 地支 of this 干支. | |
* | |
* @return the 地支 of this 干支. | |
* @see #get支() | |
*/ | |
public 地支 getBranch() { | |
return get支(); | |
} | |
// ----------------------------------------------------------------------------------------------------------------- | |
private final 天干 干; | |
private final 地支 支; | |
// ----------------------------------------------------------------------------------------------------------------- | |
private volatile 干支 previous; | |
private volatile 干支 next; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment