Temperature 불변 클래스를 작성하세요. private 생성자와 정적 팩토리 celsius(double), fahrenheit(double)(내부적으로 섭씨로 변환 저장), with-메서드 plus(double deltaC), 그리고 equals/hashCode/toString/compareTo를 구현하세요. toString은 "23.5°C" 형식입니다.
import java.util.Objects;
import java.util.TreeSet;
import java.util.List;
public final class Temperature implements Comparable<Temperature> {
private final double celsius;
private Temperature(double celsius) { this.celsius = celsius; }
public static Temperature celsius(double c) { return new Temperature(c); }
public static Temperature fahrenheit(double f) { return new Temperature((f - 32) * 5 / 9); }
public Temperature plus(double deltaC) { return new Temperature(celsius + deltaC); }
@Override public boolean equals(Object o) {
return o instanceof Temperature t && Double.compare(celsius, t.celsius) == 0;
}
@Override public int hashCode() { return Objects.hash(celsius); }
@Override public String toString() { return String.format("%.1f°C", celsius); }
@Override public int compareTo(Temperature o) { return Double.compare(celsius, o.celsius); }
public static void main(String[] args) {
Temperature a = Temperature.celsius(20);
Temperature b = Temperature.fahrenheit(68);
System.out.println(a.equals(b)); // 출력: true
System.out.println(a.plus(3.5)); // 출력: 23.5°C
System.out.println(a); // 출력: 20.0°C (원본 불변)
TreeSet<Temperature> set = new TreeSet<>(List.of(Temperature.celsius(30), a, b));
System.out.println(set); // 출력: [20.0°C, 30.0°C]
}
}HttpRequest 빌더를 작성하세요. 필수: url. 선택: method(기본 "GET"), 헤더 여러 개(header(k, v) 반복 호출), body(기본 null). build()는 method가 "GET"인데 body가 있으면 IllegalStateException을 던집니다. 완성된 객체는 불변이며 headers()는 수정 불가 Map을 반환해야 합니다.
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
public final class HttpRequest {
private final String url, method, body;
private final Map<String, String> headers;
private HttpRequest(Builder b) {
this.url = b.url;
this.method = b.method;
this.body = b.body;
this.headers = Collections.unmodifiableMap(new LinkedHashMap<>(b.headers)); // 복사 + 불변
}
public static Builder builder(String url) { return new Builder(url); }
public Map<String, String> headers() { return headers; }
public static class Builder {
private final String url;
private String method = "GET";
private String body = null;
private final Map<String, String> headers = new LinkedHashMap<>();
private Builder(String url) {
if (url == null || url.isBlank()) throw new IllegalArgumentException("url 필수");
this.url = url;
}
public Builder method(String m) { this.method = m; return this; }
public Builder header(String k, String v) { headers.put(k, v); return this; }
public Builder body(String b) { this.body = b; return this; }
public HttpRequest build() {
if (method.equals("GET") && body != null) throw new IllegalStateException("GET은 body 불가");
return new HttpRequest(this);
}
}
@Override public String toString() {
return method + " " + url + " " + headers + (body == null ? "" : " body=" + body);
}
public static void main(String[] args) {
HttpRequest r = HttpRequest.builder("https://api.shop.com/orders")
.method("POST").header("Accept", "json").header("Auth", "t0k3n").body("{}").build();
System.out.println(r); // 출력: POST https://api.shop.com/orders {Accept=json, Auth=t0k3n} body={}
try {
r.headers().put("X", "y");
} catch (UnsupportedOperationException e) {
System.out.println("헤더 수정 불가"); // 출력: 헤더 수정 불가
}
try {
HttpRequest.builder("https://x").body("{}").build();
} catch (IllegalStateException e) {
System.out.println(e.getMessage()); // 출력: GET은 body 불가
}
}
}Inventory 클래스에 Optional<Integer> stockOf(String sku)와 Result<Integer> take(String sku, int qty)를 작성하세요. take는 없는 SKU면 Fail("없는 상품"), 재고 부족이면 Fail("재고 부족"), 성공하면 남은 수량을 Ok로 돌려줍니다. 본문의 Result 타입을 그대로 쓰세요.
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class Inventory {
private final Map<String, Integer> stock = new HashMap<>();
public Inventory put(String sku, int qty) { stock.put(sku, qty); return this; }
public Optional<Integer> stockOf(String sku) {
return Optional.ofNullable(stock.get(sku));
}
public Result<Integer> take(String sku, int qty) {
Integer cur = stock.get(sku);
if (cur == null) return Result.fail("없는 상품");
if (cur < qty) return Result.fail("재고 부족");
stock.put(sku, cur - qty);
return Result.ok(cur - qty);
}
static String show(Result<Integer> r) {
return switch (r) {
case Result.Ok<Integer> ok -> "OK 남은 " + ok.value();
case Result.Fail<Integer> f -> "FAIL " + f.reason();
};
}
public static void main(String[] args) {
Inventory inv = new Inventory().put("A1", 5);
System.out.println(inv.stockOf("A1").orElse(0)); // 출력: 5
System.out.println(inv.stockOf("Z9").orElse(0)); // 출력: 0
System.out.println(show(inv.take("A1", 3))); // 출력: OK 남은 2
System.out.println(show(inv.take("A1", 3))); // 출력: FAIL 재고 부족
System.out.println(show(inv.take("Z9", 1))); // 출력: FAIL 없는 상품
}
}