[문제] 성적처리
1. 필드로 번호(no), 이름(name), 국어(kor), 영어(eng), 수학(math), 총점(tot), 평균(avg) 잡는다
2. 번호 입력할 때 중복해서 넣지 않는다.
3. 1인분의 클래스로 SungJukDTO.java 사용한다.
4. SungJukDTO.java 에서 toString() Override 한다.
toString()에서 평균은 소수이하 2째자리까지 한다.
생성자
setter / getter 메소드
calc() - 총점과 평균을 계산한다.
5. 입력, 출력, 수정, 삭제, 소트하는 클래스는 반드시 interface를 상속받는다.
6. menu() 작성한다.
만약에 1 ~ 6번 외의 숫자가 들어오면 "1~6중에 선택하세요" 메세지를 출력 후 다시 입력받는다.
1. 입력
2. 출력
3. 수정
4. 삭제
5. 정렬
6. 끝
7. SungJukInsert.java
- 번호, 이름, 국어, 영어, 수학를 입력하여 총점과 평균을 계산한다.
번호 입력 :
이름 입력 :
국어 입력 :
영어 입력 :
수학 입력 :
입력되었습니다
8. SungJukPrint.java
- ArrayList에 저장된 모든 데이터를 출력한다.
번호 이름 국어 영어 수학 총점 평균
9. SungJukUpdate.java
- 없는 번호가 입력되면 "잘못된 번호 입니다." 라고 출력한다.
- 있는 번호가 입력되면 번호에 해당하는 데이터를 출력 후 수정한다.
수정한 후에는 총점과 평균을 재계산해야 한다.
번호 입력 :
잘못된 번호 입니다.
또는
번호 이름 국어 영어 수학 총점 평균
수정 할 이름 입력 :
수정 할 국어 입력 :
수정 할 영어 입력 :
수정 할 수학 입력 :
수정하였습니다.
10. SungJukDelete.java
- 이름을 입력하여 없는 이름이면 "회원의 정보가 없습니다" 출력하시오
- 똑같은 이름이 있으면 모두 삭제한다.
삭제할 이름 입력 : 천사
회원의 정보가 없습니다
또는
x건의 항목을 삭제하였습니다.
11. SungJukSort.java
- menu() 작성한다.
********************
1. 총점으로 내림차순
2. 이름으로 오름차순
3. 이전 메뉴
********************
번호 :
SungJukDTO.java
package sungJuk;
public class SungJukDTO implements Comparable<SungJukDTO>{
private int no, kor, eng, math, tot;
private String name;
private double avg;
public SungJukDTO() {
}
public SungJukDTO(int no, int kor, int eng, int math, int tot) {
this.no = no;
this.kor = kor;
this.eng = eng;
this.math = math;
this.tot = tot;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public int getKor() {
return kor;
}
public void setKor(int kor) {
this.kor = kor;
}
public int getEng() {
return eng;
}
public void setEng(int eng) {
this.eng = eng;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getTot() {
return tot;
}
public void setTot(int tot) {
this.tot = tot;
}
public double getAvg() {
return avg;
}
public void setAvg(double avg) {
this.avg = avg;
}
public void calc() {
tot = kor + eng + math;
avg = tot / 3.0;
}
@Override
public String toString() {
return no + " "
+ name + "\t"
+ kor + "\t"
+ eng + "\t"
+ math + "\t"
+ tot + "\t"
+ String.format("%.2f", avg);
}
@Override
public int compareTo(SungJukDTO sungJukDTO) {
//총점으로 내림차순이므로 숫자를 바꾼경우 1 → -1
if(this.tot > sungJukDTO.tot)
return -1;
else if(this.tot < sungJukDTO.tot)
return 1;
else
return 0;
}
}
SungJukMain.java
package sungJuk;
public class SungJukMain {
public static void main(String[] args) {
SungJukService sungjukService = new SungJukService();
sungjukService.menu();
System.out.println("프로그램을 종료합니다.");
}
}
SungJukService.java
package sungJuk;
import java.util.ArrayList;
import java.util.Scanner;
public class SungJukService {
private ArrayList<SungJukDTO> list = new ArrayList<SungJukDTO>();
public void menu() {
Scanner scan = new Scanner(System.in);
int num=0;
SungJuk sungJuk = null;
while(true) {
System.out.println("1. 입력");
System.out.println("2. 출력");
System.out.println("3. 수정");
System.out.println("4. 삭제");
System.out.println("5. 정렬");
System.out.println("6. 끝");
System.out.print("번호 : ");
num = scan.nextInt();
System.out.println();
if(num == 6)
break;
else if(num == 1)
sungJuk = new SungJukInsert();
else if(num == 2)
sungJuk = new SungJukPrint();
else if(num == 3)
sungJuk = new SungJukUpdate();
else if(num == 4)
sungJuk = new SungJukDelete();
else if(num == 5)
sungJuk = new SungJukSort();
else {
System.out.println("1~6중에 선택하세요");
System.out.println();
continue;
}
sungJuk.execute(list);
}
}
}
SungJuk.java
package sungJuk;
import java.util.ArrayList;
public interface SungJuk {
public void execute(ArrayList<SungJukDTO> list);
}
SungJukInsert.java
package sungJuk;
import java.util.ArrayList;
import java.util.Scanner;
public class SungJukInsert implements SungJuk{
public void execute(ArrayList<SungJukDTO> list) {
Scanner scan = new Scanner(System.in);
SungJukDTO sungJukDTO = new SungJukDTO();
System.out.print("번호 입력 : ");
sungJukDTO.setNo(scan.nextInt());
System.out.print("이름 입력 : ");
sungJukDTO.setName(scan.next());
System.out.print("국어 입력 : ");
sungJukDTO.setKor(scan.nextInt());
System.out.print("영어 입력 : ");
sungJukDTO.setEng(scan.nextInt());
System.out.print("수학 입력 : ");
sungJukDTO.setMath(scan.nextInt());
sungJukDTO.calc();
list.add(sungJukDTO);
System.out.println("입력되었습니다.");
System.out.println();
}
}
SungJukPrint.java
package sungJuk;
import java.util.ArrayList;
public class SungJukPrint implements SungJuk{
@Override
public void execute(ArrayList<SungJukDTO> list) {
System.out.println("번호\t이름\t국어\t영어\t수학\t총점\t평균");
for(SungJukDTO sungJukdto : list) {
System.out.println(sungJukdto);
}
System.out.println();
}
}
SungJukUpdate.java
package sungJuk;
import java.util.ArrayList;
import java.util.Scanner;
public class SungJukUpdate implements SungJuk{
@Override
public void execute(ArrayList<SungJukDTO> list) {
Scanner scan = new Scanner(System.in);
System.out.print("번호 입력 : ");
int no = scan.nextInt();
boolean sw = false; //★★★★★
for(SungJukDTO sungJukDTO : list) {
if(sungJukDTO.getNo() == no) {
sw = true;
System.out.println("번호\t이름\t국어\t영어\t수학\t총점\t평균");
System.out.println(sungJukDTO);
System.out.println("수정 할 이름 입력 : ");
sungJukDTO.setName(scan.next());
System.out.println("수정 할 국어 입력 : ");
sungJukDTO.setKor(scan.nextInt());
System.out.println("수정 할 영어 입력 : ");
sungJukDTO.setEng(scan.nextInt());
System.out.println("수정 할 수학 입력 : ");
sungJukDTO.setMath(scan.nextInt());
sungJukDTO.calc();
System.out.println("수정하였습니다.");
System.out.println();
break;
}
}
if(!sw) { // sw == false 이렇게 하지말기.
System.out.println("잘못된 번호입니다.");
System.out.println();
}
}
}
여기서 boolean 값을 이용해야되는 이유
위에서 그냥 if-else문을 써버리면 찾는 no가 없으면 "잘못된 번호입니다."가 출력되고 또 찾았을 때 없으면 "잘못된 번호입니다."가 출력되고 그리고 나서야 찾으면 수정하는 코드가 나오게 된다.
그러므로 boolean 값을 이용해서해야 내가 찾는 번호를 찾았는지 안 찾았는지를 확인해서 올바르게 코드를 출력할 수 있다.
SungJukDelete.java
package sungJuk;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
public class SungJukDelete implements SungJuk{
@Override
public void execute(ArrayList<SungJukDTO> list) {
Scanner scan = new Scanner(System.in);
String name;
int count = 0;
System.out.print("삭제할 이름 입력 : ");
name = scan.next();
/*
for(int i=list.size()-1; i<=0; i--) {
if(list.get(i).getName().equals(name)) {
list.remove(i);
count++;
}
}
*/
위에 for문처럼 해서 거꾸로 찾는 이름이 있는지 확인하면 그나마 오류가 발생하는 것을 고칠 수 있는 것 같지만 위의 코드에도 약간의 문제가 있다.
그러므로 밑의 코드처럼 해야한다.
//★★★★★
Iterator<SungJukDTO> it = list.iterator();
while(it.hasNext()) { //현재 위치에 항목이 있습니까? true / false
//항목을 꺼내고 임시공간에 보관하고, 다음으로 이동한다.
SungJukDTO sungJukDTO = it.next();
if(sungJukDTO.getName().equals(name)) {
it.remove(); //it.next()가 반환한 항목을 제거한다.
count++;
}
}
if(count == 0) {
System.out.println("회원의 정보가 없습니다");
System.out.println();
}
else {
System.out.println(count + "건의 항목을 삭제했습니다.");
System.out.println();
}
}
}
위의 Iterator같은 경우에는 현재 위치에 항목이 있는지 확인을 하고 있으면 임시공간 즉, 버퍼에 저장을 한다. 그리고 그 다음 항목으로 넘어가게된다.
넘어가고 나서야 버퍼에 있는 이름과 내가 찾는 이름이 같은지를 비교를 하게된다.
비교를 했을 때 같으면 그 항목을 제거하게 된다.
[설명]
자바에서 ArrayList와 같은 컬렉션에서 요소를 삭제할 때,
for문 대신 Iterator를 사용해야 하는 이유는 ConcurrentModificationException 예외를 피하기 위해서이다.
- for문을 사용한 삭제
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i).getName().equals(name)) {
list.remove(i);
count++;
}
}
이 코드에서는 리스트의 크기와 인덱스를 직접 조작하면서 요소를 삭제하기 때문에 문제가 발생하지 않는다.
하지만 만약 인덱스를 0부터 시작하거나 리스트 크기가 동적으로 변경되는 상황에서는 ConcurrentModificationException이 발생할 수 있다.
- Iterator를 사용한 삭제
Iterator<SungJukDTO> it = list.iterator();
while (it.hasNext()) {
SungJukDTO sungJukDTO = it.next();
if (sungJukDTO.getName().equals(name)) {
it.remove();
count++;
}
}
위 코드에서 Iterator를 사용하여 요소를 삭제하면 ConcurrentModificationException이 발생하지 않는다.
그 이유는 Iterator의 remove() 메서드가 Iterator가 순회하고 있는 컬렉션에 안전하게 접근하여 요소를 삭제할 수 있기 때문이다.
[요약]
- for문을 사용한 삭제: 요소를 삭제할 때 리스트의 크기와 인덱스를 직접 조작하므로 위험할 수 있다. 잘못된 접근으로 인해 ConcurrentModificationException이 발생할 수 있다.
- Iterator를 사용한 삭제: 컬렉션을 순회하면서 안전하게 요소를 삭제할 수 있다. Iterator는 컬렉션의 구조가 변경되었을 때 이를 감지하고 적절히 처리다.
따라서, 컬렉션의 요소를 삭제할 때는 Iterator를 사용하는 것이 더 안전하고 권장되는 방법이이다.
SungJukSort.java
package sungJuk;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
import collection.PersonDTO;
public class SungJukSort implements SungJuk{
@Override
public void execute(ArrayList<SungJukDTO> list) {
Scanner scan = new Scanner(System.in);
int num;
while(true) {
System.out.println("********************");
System.out.println(" 1. 총점으로 내림차순");
System.out.println(" 2. 이름으로 오름차순");
System.out.println(" 3. 이전 메뉴");
System.out.println("********************");
System.out.println(" 번호 :");
num = scan.nextInt();
if(num == 1) {
Collections.sort(list); //원본을 바꿔줌 - 원본 유지 x
}else if(num == 2) {
//익명 inner class
Comparator<SungJukDTO> com = new Comparator<SungJukDTO>() {
@Override
public int compare(SungJukDTO p1, SungJukDTO p2) {
return p1.getName().compareTo(p2.getName());
}
};
Collections.sort(list, com);
}else if(num == 3)
//밑에처럼 하면 안 되는 이유: 클래스 새롭게 또 만들어짐. (초기화)
//SungJukService sungjukService = new SungJukService();
//sungjukService.menu();
break;//나가서 제자리로 가야됨.
System.out.println("번호\t이름\t국어\t영어\t수학\t총점\t평균");
for(SungJukDTO sungJukdto : list) {
System.out.println(sungJukdto);
}
}
}
}
num == 1인 경우:
- Collections.sort(list)를 사용하여 리스트를 기본 정렬 순서에 따라 정렬한다.
- 기본 정렬 순서는 SungJukDTO 클래스의 compareTo 메서드에 정의되어 있으며, 총점(tot)을 기준으로 내림차순 정렬된다.
num == 2인 경우:
- 익명 내부 클래스를 사용하여 Comparator<SungJukDTO>를 구현한다.
- Comparator는 compare 메서드에서 두 SungJukDTO 객체의 name 필드를 비교하여 사전 순으로 정렬한다.
- Collections.sort(list, com)를 사용하여 이 사용자 정의 정렬 순서를 적용한다.
이미 SungJukDTO에서 총점으로 내림차순하는 것으로 기준이 되어있기 때문에 이름으로 오름차순하기 위해서는 Comparator를 사용하여 구현해야한다.
'HOMEWORK' 카테고리의 다른 글
DAY 9 - HOMEWORK - 과일판매량 (2024.07.15) (0) | 2024.08.12 |
---|---|
DAY 10 - HOMEWORK - 달력 (2024.07.16) (0) | 2024.08.12 |
DAY 29 - CSS HOMEWORK (2024.08.12) (0) | 2024.08.12 |
DAY 28 - ORACLE DB HOMEWORK (2024.08.09) (0) | 2024.08.11 |
DAY 28 - CSS HOMEWORK (2024.08.09) (0) | 2024.08.11 |