널 참조 발명을 실수라고 생각할 수도 있지만 소프트웨어 시스템에서는 무언가가 없다는 사실을 기술해야 할 필요가 있다.
public class Legs {
public static Optional<Leg> findLongestLegOver(
List<Leg> legs,
Duration duration
) {
Leg result = null;
for (Leg leg : legs) {
if (isLongerThan(leg, duration))
if (result == null ||
isLongerThan(leg, result.getPlannedDuration())
) {
result = leg;
}
}
return Optional.ofNullable(result);
}
private static boolean isLongerThan(Leg leg, Duration duration) {
return leg.getPlannedDuration().compareTo(duration) > 0;
}
}
public class LongestLegOverTests {
private final List<Leg> legs = List.of(
leg("one hour", Duration.ofHours(1)),
leg("one day", Duration.ofDays(1)),
leg("two hours", Duration.ofHours(2))
);
private final Duration oneDay = Duration.ofDays(1);
@Test
public void is_absent_when_no_legs() {
assertEquals(
Optional.empty(),
findLongestLegOver(emptyList(), Duration.ZERO)
);
}
@Test
public void is_absent_when_no_legs_long_enough() {
assertEquals(
Optional.empty(),
findLongestLegOver(legs, oneDay)
);
}
@Test
public void is_longest_leg_when_one_match() {
assertEquals(
"one day",
findLongestLegOver(legs, oneDay.minusMillis(1))
.orElseThrow().getDescription()
);
}
@Test
public void is_longest_leg_when_more_than_one_match() {
assertEquals(
"one day",
findLongestLegOver(legs, Duration.ofMinutes(59))
.orElseThrow().getDescription()
);
}
private static final Leg leg(String description, Duration duration) {
var start = ZonedDateTime.ofInstant(
Instant.ofEpochSecond(ThreadLocalRandom.current().nextInt()),
ZoneId.of("UTC"));
return new Leg(description, start, start.plus(duration));
}
}
object Legs {
@JvmStatic
fun findLongestLegOver(
legs: List<Leg>,
duration: Duration
): Optional<Leg> {
var result: Leg? = null
for (leg in legs) {
if (isLongerThan(leg, duration))
if (result == null ||
isLongerThan(leg, result.plannedDuration))
result = leg
}
return Optional.ofNullable(result)
}
private fun isLongerThan(leg: Leg, duration: Duration): Boolean {
return leg.plannedDuration.compareTo(duration) > 0
}
}
class LongestLegOverTests {
private val legs = List.of(
leg("one hour", Duration.ofHours(1)),
leg("one day", Duration.ofDays(1)),
leg("two hours", Duration.ofHours(2))
)
private val oneDay = Duration.ofDays(1)
@Test
fun is_absent_when_no_legs() {
Assertions.assertEquals(
Optional.empty<Any>(),
findLongestLegOver(emptyList(), Duration.ZERO)
)
}
@Test
fun is_absent_when_no_legs_long_enough() {
Assertions.assertEquals(
Optional.empty<Any>(),
findLongestLegOver(legs, oneDay)
)
}
@Test
fun is_longest_leg_when_one_match() {
Assertions.assertEquals(
"one day",
findLongestLegOver(legs, oneDay.minusMillis(1))
.orElseThrow().description
)
}
@Test
fun is_longest_leg_when_more_than_one_match() {
Assertions.assertEquals(
"one day",
findLongestLegOver(legs, Duration.ofMinutes(59))
.orElseThrow().description
)
}
private fun leg(description: String, duration: Duration): Leg {
val start = ZonedDateTime.ofInstant(
Instant.ofEpochSecond(ThreadLocalRandom.current().nextInt().toLong()),
ZoneId.of("UTC"));
return Leg(description, start, start.plus(duration));
}
}