Product 클래스를 캡슐화하여 작성하세요. 필드: code(변경 불가), name, price, stock. 제약: 가격은 0 이상, 재고는 0 이상, 이름은 공백 불가. setPrice, rename, addStock(int), removeStock(int)(부족 시 IllegalStateException)를 구현하고 setStock은 만들지 마세요.
public class Product {
private final String code;
private String name;
private int price;
private int stock;
public Product(String code, String name, int price, int stock) {
if (code == null || code.isBlank()) throw new IllegalArgumentException("코드 필수");
if (stock < 0) throw new IllegalArgumentException("재고는 0 이상");
this.code = code;
rename(name);
setPrice(price);
this.stock = stock;
}
public void rename(String name) {
if (name == null || name.isBlank()) throw new IllegalArgumentException("이름 필수");
this.name = name.trim();
}
public void setPrice(int price) {
if (price < 0) throw new IllegalArgumentException("가격은 0 이상: " + price);
this.price = price;
}
public void addStock(int qty) {
if (qty <= 0) throw new IllegalArgumentException("입고 수량은 양수");
stock += qty;
}
public void removeStock(int qty) {
if (qty <= 0) throw new IllegalArgumentException("출고 수량은 양수");
if (qty > stock) throw new IllegalStateException("재고 부족: " + stock + " < " + qty);
stock -= qty;
}
public String getCode() { return code; }
public String getName() { return name; }
public int getPrice() { return price; }
public int getStock() { return stock; }
public static void main(String[] args) {
Product p = new Product("P-1", " 키보드 ", 89_000, 10);
p.removeStock(4);
p.addStock(1);
System.out.println(p.getName() + " " + p.getPrice() + "원 재고 " + p.getStock());
// 출력: 키보드 89000원 재고 7
try {
p.removeStock(100);
} catch (IllegalStateException e) {
System.out.println(e.getMessage()); // 출력: 재고 부족: 7 < 100
}
}
}위도(-9090)와 경도(-180180)를 갖는 불변 GeoPoint를 record로 작성하고, 범위를 컴팩트 생성자에서 검증하세요. 두 지점의 직선 거리(단순 유클리드)를 반환하는 distanceTo 메서드를 추가하세요.
public class Exercise2 {
record GeoPoint(double lat, double lon) {
GeoPoint {
if (lat < -90 || lat > 90) throw new IllegalArgumentException("위도 범위 오류: " + lat);
if (lon < -180 || lon > 180) throw new IllegalArgumentException("경도 범위 오류: " + lon);
}
double distanceTo(GeoPoint o) {
return Math.hypot(lat - o.lat, lon - o.lon);
}
}
public static void main(String[] args) {
GeoPoint seoul = new GeoPoint(37.5665, 126.9780);
GeoPoint busan = new GeoPoint(35.1796, 129.0756);
System.out.println(seoul); // 출력: GeoPoint[lat=37.5665, lon=126.978]
System.out.printf("%.4f%n", seoul.distanceTo(busan)); // 출력: 3.1919
System.out.println(seoul.equals(new GeoPoint(37.5665, 126.9780))); // 출력: true
try {
new GeoPoint(91, 0);
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // 출력: 위도 범위 오류: 91.0
}
}
}다음 클래스의 캡슐화 문제점을 4가지 이상 찾아 고치세요.
public class Student {
public String name;
public int[] scores;
public Student(String name, int[] scores) { this.name = name; this.scores = scores; }
public int[] getScores() { return scores; }
public void setScores(int[] scores) { this.scores = scores; }
public double average() {
int s = 0; for (int v : scores) s += v; return (double) s / scores.length;
}
}import java.util.Arrays;
public class Student {
// 문제 1: 필드가 public → private으로
// 문제 2: 생성자가 배열을 그대로 저장 → 호출자가 나중에 바꾸면 내부 상태 변경 (방어적 복사 필요)
// 문제 3: getScores가 내부 배열을 그대로 반환 → 외부에서 점수 조작 가능
// 문제 4: setScores에 검증 없음 (null, 빈 배열, 0~100 범위)
// 문제 5: average()가 빈 배열이면 0으로 나눔 → NaN
private String name;
private int[] scores;
public Student(String name, int[] scores) {
if (name == null || name.isBlank()) throw new IllegalArgumentException("이름 필수");
this.name = name;
setScores(scores);
}
public void setScores(int[] scores) {
if (scores == null || scores.length == 0) throw new IllegalArgumentException("점수 최소 1개");
for (int v : scores) {
if (v < 0 || v > 100) throw new IllegalArgumentException("점수 범위 0~100: " + v);
}
this.scores = scores.clone(); // 방어적 복사 (입력)
}
public int[] getScores() { return scores.clone(); } // 방어적 복사 (출력)
public String getName() { return name; }
public double average() {
int s = 0;
for (int v : scores) s += v;
return (double) s / scores.length; // setScores가 빈 배열을 막으므로 안전
}
public static void main(String[] args) {
int[] raw = {80, 90, 100};
Student st = new Student("Kim", raw);
raw[0] = 0; // 외부 배열 변경
st.getScores()[1] = 0; // 반환 배열 변경
System.out.println(Arrays.toString(st.getScores())); // 출력: [80, 90, 100] (둘 다 영향 없음)
System.out.println(st.average()); // 출력: 90.0
try {
st.setScores(new int[]{101});
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage()); // 출력: 점수 범위 0~100: 101
}
}
}