[java] 21. java.lang패키지(2)


StringBuffer 클래스



String 클래스는 인스턴스를 생성할 때 지정된 문자열을 변경할 수 없지만 StringBuffer 클래스는 변경이 가능합니다.

내부적으로 문자열 편집을 위한 버퍼(buffer)를 가지고 있으며,

StringBuffer인스턴스를 생성할 때 그 크기를 지정할 수 있습니다.

이 때, 편집할 문자열의 길이를 고려하여 버퍼의 길이를 충분히 잡아주는 것이 좋습니다.

편집 중인 문자열이 버퍼의 길이를 넘어서게 되면

버퍼의 길이를 늘려주는 작업이 추가로 수행되어야하기 때문에 작업효율이 떨어집니다.

버퍼의 길이를 늘려줄 때 배열의 길이는 변경될 수 없으므로 새로운 길이의 배열을 생성한 후에 이전 배열의 값을 복사해야하기 때문입니다.



StringBuffer의 생성자



StringBuffer클래스의 인스턴스를 생성할 때, 적절한 길이의 char형 배열이 생성되고,

이 배열은 문자열을 저장하고 편집하기 위한 공간(buffer)으로 사용됩니다.

StringBuffer 인스턴스를 생성할 때는 생성자 StringBuffer(int length)를 사용해서

StringBuffer 인스턴스에 저장될 문자열의 길이를 고려하여 충분히 여유있는 크기로 지정하는 것이 좋습니다.

StringBuffer인스턴스를 생성할 때, 버퍼의 크기를 지정해주지 않으면

16개의 문자를 저장할 수 있는 크기의 버퍼를 생성합니다.


//StringBuffer 클래스의 생성자


public StringBuffer(int length){
	value=new char[length];
	shared=false;
}

public StringBuffer(){
	this(16);
}

public StringBuffer(String str){
	this(str.length()+16); //지정한 문자열의 길이보다 16 더크게 버퍼 생성
	append(str);
}



StringBuffer의 변경과 비교



String과 달리 StringBuffer는 내용을 변경할 수 있습니다.


//문자열 abc에 de를 추가하고 싶을 때

String str=new String("abc");

str="abcde"; //주소가 바뀜

StringBuffer str2=new StringBuffer("abc");

str2.append("de"); //주소가 안 바뀜



다음과 같이 연속적으로 append()를 호출하는 것도 가능합니다.


StringBuffer sb=new StringBuffer("abc");

sb.append("123").append("ZZ"); //sb="abc123ZZ"



그리고 String에서는 equals()가 오버라이딩 되어있어서 비교를 할 때

두 인스턴스의 참조 값이 아닌 내용 값을 가지고 비교했는데,

StringBuffer에서는 equals()가 오버라이딩 되어 있지 않기 때문에.

두 참조값을 비교합니다.


//String 클래스

String s=new String("abc");

String s2=new String("abc");

System.out.println(s.equals(s2)); //true



//StringBuffer 클래스

StringBuffer sb=new StringBuffer("abc");

StringBuffer sb2=new StringBuffer("abc");

System.out.println(sb.equals(sb2)); //false



반면에, toString()은 오버라이딩되어 있어서 StringBuffer 인스턴스에 toString()을 호출하면,

담고있는 문자열을 String으로 반환합니다.

그래서 StringBuffer 인스턴스에 담긴 문자열을 비교하기 위해서는 toString()을 사용해서

String 인스턴스를 얻은 다음, 여기에 equals 메서드를 사용해서 비교해야 합니다.


String s=sb.toString();
String s2=sb2.toString();

System.out.println(s.equals(s2)); //true



StringBuffer클래스의 생성자와 메서드



다음은 StringBuffer 클래스의 생성자와 메서드입니다.


image



image



image



image



StringBuilder 클래스



StringBuffer는 멀티쓰레드에 안전하도록 동기화되어 있습니다.

아직 멀티쓰레드나 동기화에 대해 배우지 않았기에, 동기화가 StringBuffer의 성능을 떨어뜨린다는 것만 알아두면 됩니다.

멀티쓰레드로 작성된 프로그램이 아닌 경우, StringBuffer의 동기화는 불필요하게 성능만 떨어뜨리게 됩니다.

그래서 StringBuffer에서 쓰레드의 동기화만 뺀 StringBuilder가 새로 추가되었습니다.

StringBuilder는 StringBuffer와 완전히 똑같은 기능으로 작성되어 있어서,

소스코드에서 StringBuffer 대신 StringBuilder를 사용하도록 바꾸기만 하면 됩니다.


StringBuilder sb;

sb=new StringBuilder();

sb.append("abc");



Math 클래스



Math클래스는 기본적인 수학계산에 유용한 메서드로 구성되어 있습니다.

Math 클래스의 생성자는 접근 제어자가 private이기 때문에 다른 클래스에서 Math인스턴스를 생성할 수 없도록 되어있는데,

모든 메서드가 static이고 멤버는 상수 E와 PI뿐이므로 인스턴스를 생성할 필요가 없기 때문입니다.



올림, 버림, 반올림



소수점 n번째 자리에서 반올림한 값을 얻기 위해서는 round()를 사용합니다.

이 메서드는 항상 소수점 첫째자리에서 반올림 해서 정수값을 결과로 돌려줍니다.

예를 들어 90.7552라는 값을 소수점 셋째자리에서 반올림 한 후

소수점 두 자리까지의 값을 얻고 싶은 경우 다음과 같이합니다.


1.원래 값에 100을 곱한다.

90.7552->9075.52

2.위의 결과에 Math.round()를 사용한다.

Math.round(9075.52)->9076

3.위의 결과를 다시 100.0으로 나눈다.

9076/100.0 -> 90.76

9076/100 -> 90 (정수를 정수로 나누면 결과는 정수)



다음은 올림, 내림, 반올림에 대한 예제입니다.


image



예외를 발생시키는 메서드



메서드 이름에 ‘Exact’가 포함된 메서드들이 JDK 1.8부터 새로 추가되었습니다.

이들은 정수형 간의 연산에서 발생할 수 있는 오버플로우(overflow)를 감지하기 위한 것입니다.


int addExact(int x, int y) //x+y

int subtractExact(int x, int y) //x-y

int multiplyExact(int x, int y) //x*y

int incrementExact(int a) //a++

int decrementExact(int a) //a--

int negateExact(int a) //-a

int toIntExact(long value) //(int)value



연산자는 단지 결과를 반환할 뿐, 오버플로우의 발생여부에 대해 알려주지 않습니다.

그러나 위의 메서드들은 오버플로우가 발생하면, 예외를 발생시킵니다.

다음 예제에서 확인해보시죠~


image



삼각함수와 지수, 로그



다음은 삼각함수와 지수, 로그를 Math의 메서드로 구현한 것입니다.


image



StrictMath 클래스



Math클래스는 최대한의 성능을 얻기위해 JVM이 설치된 OS의 메서드를 호출해서 사용합니다.

즉 OS에 의존적인 계산을 하고 있는 것입니다.

예를 들어 부동소수점 계산의 경우, 반올림의 처리방법 설정이 OS마다 다를 수 있기 때문에

자바로 작성된 프로그램임에도 불구하고 컴퓨터마다 결과가 다를 수 있습니다.

이러한 차이를 없애기 위해 성능은 다소 포기하는 대신, 어떤 OS에서 실행되어도 항상 같은 결과를 얻도록

Math클래스를 새로 작성한 것이 StrictMath 클래스입니다.



Math클래스의 기타 메서드



다음은 Math클래스에서 자주 사용되는 메서드에 대한 예제입니다.


image



래퍼(wrapper) 클래스



기본형(int,long,float,double,…) 변수도 어쩔 수 없이 객체로 다뤄야 하는 경우가 있습니다.

예를 들면, 매개변수로 객체를 요구할 때, 기본형 값이 아닌 객체로 저장해야할 때,

객체 간의 비교가 필요할 때 등등의 경우에는 기본형 값들을 객체로 변환하여 작업을 수행해야합니다.

이 때 사용되는 것이 레퍼(wrapper)클래스입니다.

8개의 기본형을 대표하는 8개의 래퍼클래스가 있는데, 이 클래스들을 이용하면 기본형 값을 객체로 다룰 수 있습니다.

주의할 점은 래퍼 클래스의 생성자의 매개변수 타입으로 문자열이 가능한데,

자료형에 알맞은 문자열을 사용해야한다는 것입니다.


new Integer("1.0"); //NumberFormatException 발생



래퍼클래스는 다음과 같습니다.


image



다음은 래퍼클래스에 대한 예제입니다.


image



Number 클래스



Number 클래스는 추상클래스로 내부적으로 숫자를 멤버변수로 갖는 래퍼 클래스들의 부모입니다.

아래의 그림은 래퍼클래스의 상송계층도인데, 기본형 중에서 숫자와 관련된 래퍼클래스들은 모두 Number 클래스의 자식입니다.


image



그 외에도 Number 클래스 자식으로 BigInteger와 BigDecimal이 있는데,

BigInteger는 long으로도 다룰 수 없는 큰 범위의 정수를,

BigDecimal은 double로도 다룰 수 없는 큰 범위의 부동 소수점수를 처리하기 위한 것으로

연산자의 역할을 대신하는 다양한 메서드를 제공합니다.



문자열을 숫자로 변환하기



문자열을 숫자로 변환하는 방법은 다음과 같습니다.


int i=new Integer("100").intValue();

int i2=Integer.parseInt("100"); //주로 이 방법 사용

Integer i3=Integer.valueOf("100");

int i4=Integer.valueOf("100"); //오토박싱 기능 때문에 가능



다음은 문자열을 숫자로 바꾸는 예제입니다.


image



오토박싱 & 언박싱



JDK 1.5 이전에는 기본형과 참조형 간의 연산이 불가능했기 때문에,

래퍼클래스로 기본형을 객체로 만들어서 연산해야 했습니다.


//컴파일 전 코드


int i=5;
Integer iObj=new Integer(7);

int sum=i+iObj; //에러. 기본형과 참조형 간의 덧셈불가(JDK1.5 이전)



그러나 이제는 기본형과 참조형 간의 덧셈이 가능합니다.

자바 언어의 규칙이 바뀐 것은 아니고, 컴파일러가 자동으로 변환하는 코드를 넣어주기 때문입니다.


//컴파일 후 코드

int i=5;
Integer iObj=new Integer(7);

int sum=i+iObj.intValue(); //컴파일러가 intValue() 자동으로 추가



이 외에도 내부적으로 객체 배열을 가지고 있는 Vector 클래스나 ArrayList 클래스에

기본형 값을 저장해야할 때나 형변환이 필요할 때도 컴파일러가 자동적으로 코드를 추가해줍니다.

기본형 값을 래퍼클래스의 객체로 자동 변환해주는 것을 오토박싱(autoboxing)이라 하고,

그 반대는 언박싱(unboxing)이라고 합니다.


ArryList<Integer> list=new ArrayList<Integer>();

list.add(10); //오토박싱. 10->new Integer(10)

int value=list.get(0); //언박싱. new Integer(10)->10



다음은 오토박싱에 대한 예제입니다.


image