문제

주어진 숫자를 며칠에서 밀리 초로 변환하는 방법을 작성했습니다.

private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = expireTimeInDays * 24 * 60 * 60 * 1000;
}

나는 내가 잘못한 것을 알아 내기가 어려웠다. 이제 내 질문 :그 오류가 그렇게 분명합니까?

수정 된 방법 :

private long expireTimeInMilliseconds;
...
public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = ((long) expireTimeInDays) * 24 * 60 * 60 * 1000;
}

정수를 계산하기 오래 전에 정수를 변환하지 않으면 완전히 잘못된 결과를 얻습니다.

도움이 되었습니까?

해결책

분명합니까? 나는 당신이 Java를 얼마나 오래 사용했는지, 그리고 밀리 초를 몇 번이나 다루어야했는지에 달려 있다고 생각합니다. 물론 최대 약 24 일 동안 괜찮을 것입니다 ...

가장 큰 힌트는 그렇게해야한다고 생각합니다 System.currentTimeMillis() 반환 a long. 그것은 많은 밀리 초가 커질 수 있다는 좋은 표시입니다. 설정하는 변수의 유형도 좋은 힌트 여야합니다.

물론, 당신은 또한 ints로 산술 작업을 수행하면 결과가 int 오버플로에 랩 어라운드가 있습니다. 그것이 충분히 명백한 지 여부에 대해 토론 할 수는 있지만, 그것은 꽤 무의미한 토론 일 것입니다. C#에서 오버플로 체크를 켜면 버그가 꽤 빨리 발견되었을 것입니다. 그러나 많은 개발자가 그렇게하지는 않습니다 (실제로는 그렇습니다.

다른 팁

예, 전에 한 적이 있다면 꽤 분명합니다. 일련의 숫자가 곱하기를 볼 때마다 정수 오버플로 오류에 대해 자동으로 생각하기 시작해야합니다. 이 경우 오버플로로 설정됩니다 expireTimeInDays 기술적으로 오류 오류에 대해 생각해야합니다. 정수와 함께 일할 때마다, 그러나 이와 같이 그룹을 곱하는 것은 매우 큰 적기가되어야합니다.

피연산자 변수와 문자 번호는 유형 int입니다. INT 데이터 유형의 최대 값은 2^31-1입니다. 따라서 이러한 숫자가 많으면 데이터 유형의 int 오버 플로우가 잘못된 대답으로 보이게됩니다.

첫 번째 예에서 int는 발생하는 변수에 대한 할당 할 때만 홍보됩니다. ~ 후에 계산. 계산 결과는 int입니다.

두 번째 예는 첫 번째 피연산자를 길게 시전하여 계산을 촉진시킵니다. 이 경우, 계산 결과는 프로모션으로 인해 길다. 긴 데이터 유형은 계산을 위해 충분히 크다.

이것이 Joshua Bloch와 Neal Gafter의 "Java Puzzlers"로 덮여 있음을 알고 싶습니다.

alt text
(원천: javapuzzlers.com)

그 책에서 다른 많은 자바 함정, 함정 및 코너 케이스를 찾을 수 있습니다.

나는 의견을 남긴 스타 블루에 동의합니다. L을 숫자에 추가하십시오.

아니요, 분명하지 않습니다.

그러나 몇 년 동안 연습하고 이와 같은 버그를 고치면 정수 오버플로에 대해 매우 합리적이되고 생각조차하지 않고 올바른 일을합니다.

그것은 모두에게 행복한 것입니다. 확실히 나쁜 코드 실습, 무지 등의 징후가 없습니다.

다른 답변에 추가하기 위해, 나는 과거에 상수를 정의하는 것이 도움이된다는 것을 알았습니다 (public static final long) 와 같은 MILLISECS_DAY 또는 MILLISECS_HOUR. 훨씬 더 읽기 쉽고 유용합니다.

이것을 쓰는 또 다른 방법입니다

public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = (long) expireTimeInDays * 24 * 60 * 60 * 1000;
}

또는

public void setExpireTimeInDays(int expireTimeInDays)
{
   expireTimeInMilliseconds = expireTimeInDays * 24L * 60 * 60 * 1000;
}

코드에서 FindBugs를 사용하면이 정확한 문제가 감지됩니다. "ICAST : 정수 곱셈의 결과는 오랫동안 캐스팅됩니다." FindBugs의 예는 당신이하는 일입니다. 밀리 초의 일을 계산합니다.

이 문제는 내가 처음으로 뛰어 들었을 때 나에게 분명하지 않았다.

이러한 유형의 오류를 찾을 수있는 정적 분석 도구 (FindBugs)가 있습니다.

컴퓨터의 수치 수학은 어려울 수 있습니다. 운영 순서 문제는 예상치 못한 방식으로 정밀도와 정확도에 영향을 줄 수 있습니다. 날짜 수학은 놀랍게도 까다로울 수 있습니다. 종종 수학을 직접 수행하려고하는 대신 날짜/캘린더 루틴을 사용하는 것이 좋습니다. 그러나 그 루틴은 Java 클래스 라이브러리에서 가장 잘 설계된 것이 아닙니다.

나는 내 실수를 정당화하려고하지는 않지만 Java 컴파일러가 계산 전에 int를 홍보 할만 큼 똑똑하다면 (계산이 유형의 길이가 길어지면)

그건 그렇고, 나는 C/C ++와 함께 일했고 C 프로그램이라면 같은 문제가 있었지만 몇 년 전에는 이런 종류의 작업에 더주의를 기울였습니다.

다음에 더 많은 관심을 기울일 것입니다 (또는 파이썬으로 전환) ... : D

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top