본문 바로가기
Today I Learned 2024. 5. 3.

(24.05.03)[3주차] 0/0 NaN , Stream -> List 변환

 

팀 과제를 하면서 진짜 너무 코드가 많아서 눈이 너무 아파서 순간 머리가 잠깐 횡 돌아서 쓰러질 뻔

그래도 배웠던 것들이 코드로써 나온것을 보고 있자면 괜시리 반갑기도 하고

좀더 실제처럼 코드를 짜면서 익숙해질 수 있도록 해야할 것이다.


과제 이슈

 

0/0  NaN 이슈

더보기
...
       case "CHOICE":
       ...
       if (average < 50) {
                            averageGrade = "N";
                        }
                        break;
                }
    if (averageGrade == null) {
                        averageGrade = "점수 미등록";
    }
    System.out.println(subject.getSubjectName() + "(" + subject.getSubjectType() + ")  :  " + averageGrade);
...

이슈

  • 과목횟수별총합/과목횟수 값을 average라고 했을 때, 어떠한 점수와 회차가 등록이 되지 않을경우, ArithmeticException이 발생 X
  • ArithmeticException이 발생할 줄 알고 try-catch문으로 이 예외를 던지면서 "점수 미등록" 을 출력 하려고 했으나, 예외가 발생이 안되고 null 이 계속 averageGrade로 등록
    • 과목횟수별총합/과목횟수 은 double타입임에도 null이 발생

원인

  • double  에서 0/0이 발생하면 Java 컴파일러는 ArithmeticException 를 발생시키는 게 아니라 숫자가 아닌 not-a-number 즉 NaN을 반환
    • Double 클래스의 static 필드값임
    • NaN은 특수한 어떤 특별한 값의 개념임
    • String 타입도 아님. 그자체로 숫자가 아니다라는 얘기
  • 따라서, NaN(수가 아님) 과 어떠한 수를 비교하더라도 말이 안되기 때문에 false 를 반환하게 되고, 결국 NaN인 average가 if문의 맨 밑으로 떨어져 결국 averageGrade는 초기에 설정된 null 로 반환이 되었던 것

해결

  • 그냥, 어떻게 하던 averageGrade는 null이 될 수 밖에 없고, switch 문 case 안의 if 문 안에 쓰이면서 해당 점수 미등록 출력을 하는 것을 모든 case에 다 써줘야하기 때문에 맨 밑으로 빼서 정리
 

stream -> List 변환 & 다른 컬렉션/배열로 변환 정리

더보기
...
 for (Subject subject : resultStudent.getEnrolledSubjects()) {
double average = 0; // 과목별 평균 점수
String averageGrade = null; // 과목별 평균 등급
List<Score> subjectScore = scoreStore
        .stream()
        .filter(s -> s.getStudent().equals(resultStudent) && s.getSubject().equals(subject))
        .toList();

...
  • Stream을 통해 List에서 간단하게 원하는 값만 찾아서 가져오는 함수를 사용하는데 Collectors클래스를 사용할 필요가 없음(다른 팀원의 코드에서 발견하고 학습하기위해 공부)
    • 원래 알고있는 바로는 stream을 다시 List Set Map Collection Array로 바꿔야할 때, Stream의 최종 연산에서 메서드로 사용
    • 위의 scoreStore이라는 List<Score>일 경우, .stream().filter(람다식).collect(Collectors.toList()); 로 사용했었음
      • .collect(Collectors.toArray()) 등등 가능
      • Collection일 경우엔 해당 자료형 생성자 메서드 참조를 써서 가능 .collect(Collectors.toCollection(ArrayList::new));
    • **주의, toArray일 경우 래퍼클래스와 데이터 타입이 다른 요소를 가고 있는 스트림일 경우엔 주의를 해야함
      • int[] intArray = IntStream.toArray(); 는 가능하지만, Stream<Integer> stream 일 경우, int[] intArray = stream.toArray(size->new int[size]); 이렇게 새로운 크기의 기본형 타입의 배열을 만들어야함!
  • ** collect를 쓰지 않고도 바로 collectors의 메서드를 바로 쓸 수 있음! 
    • filter.toList() 이런식으로 바로 가능하다는 점 알고 있을 수 있도록

 


주말에는 선약이 있어 빠르게 해결할 수 있도록 해야할 것