passion and relax

[JAVA] 10. 숫자는 정말 중요합니다 (수학, 포매팅, 래퍼, 통계) 본문

프로그래밍

[JAVA] 10. 숫자는 정말 중요합니다 (수학, 포매팅, 래퍼, 통계)

Grab Java 2024. 5. 24. 08:56

Math 클래스

Math.round (42.2);
. 가장 가까운 정수를 반환
. 입력이 float 이면 int를, 입력이 double 이면 long의 정수를 반환한다.
Math.min (1, 2);   Math.max(1,2);
. 입력된 두 숫자 중, 최소 / 최대값을 반환한다.
Math.abs(-123);
. 절대값을 반환한다.
Math.random();
. 0.0 이상 ~ 1.0 미만인 임의의 double 값을 반환한다.
Math math = new Math();  //이처럼 인스턴스 변수 생성 허용 안됨.

 


일반 메소드 VS 정적 메소드

일반 메소드
. 인스턴스 변수에 따라 행동이 달라짐
정적 메소드
. 인스턴스 변수가 변해도 행동은 동일
. 인스턴스의 생성이 무의미
. public static int max (int a, int b) { ~~ }
. 정적 메소드에서의 변수는 정적 변수만 사용해야 한다.
. 정적 메소드에서의 메소드는 다른 정적 메소드만 사용해야 한다.

정적 변수

모든 인스턴스에서 변수를 공유하고자 할 때, 정적변수 사용
매번 인스턴스가 생성될 때가 아닌, 클래스가 처음 로딩될 때만 초기화되기를 원할 때, 정적변수 사용
. private static int duckCount = 0;
    duck 인스턴스의 수를 count 할 때, 활용될 수 있겠다.
    private에 static으로 했으니, 외부 접근은 불가능하면서 한번만 초기화 되니 count에 적합하다.
정적변수는 속한 객체가 생성되기 전에 이미 초기화 된다.
정적변수는 속한 객체의 정적 메소드가 실행되기 전에 이미 초기화 된다.
class Player {
    static int playerCount = 0;
    private String name;

    public Player(String name) {
        this.name = name;
        playerCount++;
    }
}

public class PlayerTestDrive {
    public static void main (String[] args) {
        System.out.println (Player.playerCount);    //0
        Player one = new Player ("Tiger Woods");
        System.out.println (Player.playerCount);    //1
    }
}

 


상수

상수 변수명은 모두 대문자. 단어 사이는 밑줄
초기화 안하면 컴파일러 에러 발생
상수 설정 방법 1
public class Foo {
    public static final double PI = 3.141592653589793;
}


상수 설정 방법 2
public class Bar {
    public static final double BAR_SIGN;
    static {
        BAR_SIGN = (double) Math.random();
    }
}


final

변수 : 값 변경 불가
메소드 : 오버라이드 불가
    final void calcWhuffie() { ~~ }
클래스 : 확장 불가. 즉, 하위 클래스 생성 불가.
    final class MyMostPerfectClass { ~~ }
class Foo {
    final int size = 3;  //public 또는 static 이 아니어도 됨.
    final int whuffie;   //여기서 초기화 안하면, 반드시 생성자에서 해야 함.

    Foo() {
        whuffie = 42;
    }
}

 


wrapper 클래스

원시 형식을 객체처럼 다뤄야 할 때, wrap(포장) 하기 위해 사용
Boolean, Character, Byte, Short, Integer, Long, Float, Double
포장 : int i = 288;    Integer iWrap = new Integer(i);
포장 벗기기 : int unWrapped = iWrap.intValue();
String2원시값
. int x = Integer.parseInt(s);    //만약 s가 숫자가 아니라면, NumberFormatException 발생
. double d = Double.parseDouble(s);
. boolean b = new Boolean("true").booleanValue();    //parseBoolean()은 없다.
원시값2String
. String doubleString = Double.toString(d);
. String doubleString = "" + d;   //이것도 가능. 연산자 오버로드로 가능함.
Auto Boxing
. 원시값과 래퍼 객체 사이의 변환을 자동으로 처리해 주는 기능
. 예전에는 ArrayList<Integer> 이런 곳에 넣을 때마다, wrapper를 써야만 했었는데..
    Auto Boxing이 이 역할을 해주게 되어 코딩이 많이 편해졌단다.


숫자 포매팅

String s1 = String.format("%,d", 1000000000);
//1,000,000,000  => 1000마다 콤마

String s2 = String.format("I have %.2f bugs to fix.", 476578.09876);
//I have 476578.10   => 소숫점 3째 자리 반올림. 2째 자리까지 표현

String s3 = String.format("I have %,.2f bugs to fix.", 476578.09876);
//I have 476,578.10   => 1000마다 콤마. 소숫점 3째 자리 반올림. 2째 자리까지 표현

 

문자열 속에 있는 포매팅은 어디서 부터 어디까지 인가?
. %가 나오면 시작. 이전에는 그냥 문자열
. % 이후에 유형지시자(d, f, ...)가 나오면 끝. 이후 부터는 그냥 문자열
% [인자번호] [플래그] [너비] [.정밀도] 유형 == format("%,6.1f", 4321.0);
. 인자번호 : 인자가 둘 이상일 때, 어떤 인자를 쓸지 지정
. 플래그 (,) : 쉼표넣기, 음수는 괄호안에 넣기, 숫자는 왼쪽정렬 등의 특별 포매팅 옵션 지정
. 너비 (6) : 너비가 작으면, 그냥 작은 대로 출력.
. 정밀도 (.2) : "."을 같이 넣는다.
. 유형 (f) : 포매팅의 끝을 알린다. 반드시 넣어야 한다.
    d (십진정수) : byte, short, int, char
    f (부동소수점) : float, double, BigDecimal
    x (16진수) : byte, short, int, long, BigDecimal
    c (문자) : byte, short, char, int  => format("%c", 42);  //아스키로 42번인 "*"가 출력됨.
인자가 둘 이상인 경우
int one = 20456657;
double two = 100567890.248907;
String s = String.format("aaa %,d bbb %,.2f", one, two);
// aaa 20,456,654 bbb 100,567,890.25

인자는 몇개까지 오버로딩 되어 있을까?  VarArgs (Variable Argument lists : 가변인자목록)
. 가변 인자 목록 기능이 추가되어, 인자는 얼마든지 가능하다.

 



날짜 포매팅

String.format ("%tc", new Date());    //날짜, 시간
=> Sun Nov 28 14:52:41 MST 2004
String.format ("%tr", new Date());    //시간
=> 03:01:47 PM
String.format ("%tA, %tB, %td", new Date(), new Date(), new Date());    //","의 역할 볼 것.
String.format ("%tA, %<tB, %<td", new Date());    //같은 인자 세번 쓰기 싫으니깐..
=> Sunday, November, 28


Calendar 객체 얻기 (예전에는 Date를 썼었지만..)

java.util.Date 에서 java.util.Calendar 로 갈아 타자~
Calendar 인스턴스 얻기 : 추상클래스이므로, 아래처럼 얻어야 한다.
. Calendar cal = new Calendar();    //컴파일 에러
. Calendar cal = Calendar.getInstance();    //OK. 정적메소드 호출로 구상클래스의 인스턴스 획득


Calendar 객체 활용

Calendar c = Calendar.getInstance();

c.set (2004, 0, 7, 15, 40);    //2004년, 0은 1월, 7일, 15시, 40분
long day1 = c.getTimeInMillis();    //19700101부터의 밀리초로 받아 day1에 담음.
day1 += 1000 * 60 * 60;    //1시간 더하기. 밀리초 변환 * 60초 * 60분
c.setTimeInMillis(day1);    //1시간이 더해진 밀리초로 Calendar 설정
sout("#" + c.get(c.HOUR_OF_DAY));    //#16

c.add (c.DATE, 35);    //35일을 더하라.
sout("#" + c.getTime());    //Wed Feb 11 16:40:41 MST 2004

c.roll (c.DATE, 35);    //35일을 더하되, roll이니깐, 이번달에서만..
sout("#" + c.getTime());    //Tue Feb 17 16:40:41 MST 2004

c.set (c.DATE, 1);    //날짜를 1로 설정.
sout("#" + c.getTime());    //Sun Feb 01 16:40:41 MST 2004

 


Calendar 주요 메소드

add (int field, int amount);  //Calendar 필드의 시간을 더하거나 뺀다.
get (int field);  //주어진 필드의 값을 리턴
getInstance ();  //Calendar 리턴. 지역설정 가능
getTimeInMillis ();  //밀리초 단위의 long 값을 리턴
roll (int field, boolean up);  //더 큰 단위의 필드는 바꾸지 않은 채 시간을 더하거나 뺀다
set (int field, int value);  //주어진 Calendar 필드의 값을 설정
set (year, month, day, hour, minute);  //Calendar 설정
setTimerInMillis (long millis);  //19700101부터의 경과 시간의 밀리초로 Calendar 시각 설정

 

field

. 일 : DATE / DAT_OF_MONTH
. 12시간 또는 24시간 값 : HOUR / MOUR_OF_DAY
. 밀리초 : MILLISECOND
. 분 : MINUTE
. 달 : MONTH
. 연도 : YEAR
. 그리니치 표준시와의 밀리초 차이 : ZONE_OFFSET

 


정적 import

가독성이 떨어진다는 평이 있다. 중복도 될 수 있다.
Math를 많이 써야 한다면, 아래 처럼 써라. "*"의 와일드 카드도 사용 가능하다.
import static java.lang.System.out;
import static java.lang.Math.*;

class WithStatic {
    public static void main (String[] args) {
        out.println(sqrt(2.0));    //System 이나 Math를 쓰지 않음.
        out.println(tan(60));
    }
}