표준 함수형 interface

Runnable

입력 X, 출력 X
입력도 출력도 없이 함수 내의 동작만 수행 가능하다.

ex)

void hello(){
    System.out.println("Hello World!");
}

Consummer

입력 O, 출력 X
입력은 있지만 출력이 존재하지 않는다.

ex)

void hello(String msg){
    System.out.println("msg: " + msg);
}

Operation

입력 O, 출력 입력과 같은 Type
입력을 받아 함수가 동작한 뒤 입력과 같은 타입을 return 한다.

ex)

int plus(int a, int b){
    return a+b;
}

Function

입력 O, 출력 anyType
입력의 타입과 상관 없이 return한다. 같은 타입을 return 해도 Function이다. (Operation < Function)

ex)

String plusOperation(int a, int b){
    StringBuilder answer = new StringBuilder();
    answer.append("answer is ").append(a+b);
    return answer.toString();
}

Supplier

입력 X, 출력 O
입력 없이 출력만 존재한다. 정해진 data등을 return 한다.

ex)

String[] getDayArr(){
    String[] dayArray = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
    return dayArray;
}

Predicate

입력 O, 출력 Boolean
입력에 따라 적절한 Boolean값을 return 한다.

ex)

Boolean isSmall(int a, int b){
    if(a < b){
        return true;
    }
    return false;
}
728x90

가장 기본적인 자료구조이자, 앞으로 지겹도록 보게 될 JAVA의 배열에 관해 알아보겠습니다.

배열의 이론적인 부분은 다 아신다고 생각하고, 활용적인 면을 위주로 정리해보았습니다.

어느 정도 경험이 있으신 분들은 맨 아래의 코드만 보셔도 이해가 가능할 것 같습니다.

 

 

1. 선언

int[] array0;

선언만 하고 값의 대입은 나중으로 미룰 수 있다.


int[] array1 = new int [10];

배열의 크기만 잡아 선언하면 안의 값은 default값으로 채워진다.

 

int[] array2 = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };

최초에는 직접 값을 넣으면서 선언이 가능하다.

값을 변경할 때는 불가능하지만 새로운 배열을 만들어서 넣어주는 건 가능하다.

 

int[] array3 = new int [] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

새로운 배열을 만들면서 값을 곧바로 대입한다. 이 방법으론 나중에도 값의 변경이 가능하다.

ex) array3 = new int[] {1,2,3,4};

 

2. 기본 값

System.out.println(Arrays.toString(array1));

"{0,0,0,0,0,0,0,0,0,0}"

배열에 아무런 값을 넣지 않을 시 초기값은 0이다. (Int 타입의 경우, Boolean 타입은 false가 들어간다.)

 

3. Java.util.Arrays

Arrays를 import 하면 배열과 관련된 여러 유용한 메서드를 사용할 수 있다.

 

Arrays.fill();

배열 안을 지정된 값으로 채운다.

Arrays.toString();

기본적으로 toString()을 사용하거나 배열 자체를 출력하면 주소 값이 출력된다. Arrays.toString 메서드를 활용하면 배열의 값을 보기 좋게 출력한다. 

Arrays.sort();

배열의 원소들을 정렬한다. 기본적으론 오름차순 정렬이고, 정렬의 기준은 타입에 따라 내부적으로 구현된 compare메서드를 따른다.

 

람다식을 활용한 정렬

Arrays.sort(array, (e1, e2)->{
      return e1[1] - e2[1];
});

이런 식으로 람다식을 활용하면 내림차순 정렬은 물론이고 원하는 어떤 방식으로도 정렬이 가능하다.

단, 기본 타입 (Primitive) 배열엔 적용이 불가능하기 때문에, 동치 되는 class를 사용하면 된다.

ex) int[] -> Integer[] , char[] -> Character[] 등..

 

4. 주소 값 문제

JAVA는 기본 타입의 경우 Call by Value로 값을 전달하고 객체들의 경우엔 주소 값을 전달합니다.

배열도 객체로 취급되어 주소가 전달되다 보니, 개발자의 생각과 다르게 동작하는 경우가 생깁니다.

반복문을 통해 값을 하나하나 대입하는 방법도 있지만, clone메서드를 사용하면 쉽게 값의 복사가 가능합니다.

 

int[] array4 = array2;

array2의 주소 값이 들어갔다.

array4를 수정하면 array2도 동시에 수정되고, array2를 수정하면 array4도 바뀐다.


int[] array5 = array2.clone();

array2의 현재 상태를 복사해서 새로운 배열을 생성했다.

이후 둘의 수정은 서로에게 영향을 끼치지 않는다!

 

for(int i = 0; i < array.length; i++){

    copyArr[i] = arr[i].clone();

}

이런 식으로 반복문을 활용해 다차원 배열의 복사도 가능하다!

 

import java.util.Arrays;

public class Main {
	public static void main(String[] args) {

		int[] array0;
		int[] array1 = new int[10];
		int[] array2 = { 9, 8, 7, 6, 5, 4, 3, 2, 1 };
		int[] array3 = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

		System.out.println("----> array의 기본 값은 0");
		System.out.println(Arrays.toString(array1));

		System.out.println("----> array2");
		System.out.println(Arrays.toString(array2));

		int[] array4 = array2;
		int[] array5 = array2.clone();

		Arrays.sort(array2);

		System.out.println("----> array2 sort 후");
		System.out.println(Arrays.toString(array2));
		System.out.println("----> array4는 array2의 주소를 가리킨다.");
		System.out.println(Arrays.toString(array4));
		System.out.println("----> array5는 array2의 값을 복사했다.");
		System.out.println(Arrays.toString(array5));

		System.out.println("----> array3");
		System.out.println(Arrays.toString(array3));

		array3 = new int[] { 1, 1, 1, 1 };

		System.out.println("----> array3에 새로운 값 넣기");
		System.out.println(Arrays.toString(array3));

		Arrays.fill(array3, 999);

		System.out.println("----> array3 값 채우기");
		System.out.println(Arrays.toString(array3));

		Integer[] array6 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

		System.out.println("----> Integer 배열 array6");
		System.out.println(Arrays.toString(array6));
		Arrays.sort(array6, (e1, e2) -> {
			return e2 - 21;
		});
		System.out.println("----> array6 역순으로 sort");
		System.out.println(Arrays.toString(array6));

		System.out.println("인자로 전달해 출력하기");
		printArr(array1);

		System.out.println("인자로 전달해 변경하기");
		System.out.println(Arrays.toString(array1));
		fillArr(array1);
		System.out.println(Arrays.toString(array1));

		Integer[][] array7 = { { 1, 2, 3, 4 }, { 4, 3, 2, 1 }, { 4, 1, 2, 3 }, { 1, 4, 3, 2 } };

		System.out.println("----> array7 출력");
		System.out.println(Arrays.toString(array7));

		System.out.println("----> array7 반복문 출력");
		for (int i = 0; i < array7.length; i++) {
			System.out.println(Arrays.toString(array7[i]));
		}

		Integer[][] array8 = { { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, { 4, 3 }, { 3, 1, 5 }, { 1, 4, 3 } };
		System.out.println(array8.length);
		for (int i = 0; i < array8.length; i++) {
			System.out.println("----> array8의 길이 출력");
			System.out.println(array8[i].length);
		}

		Arrays.sort(array8, (e1, e2) -> {
			return e1[1] - e2[1];
		});

		System.out.println("----> array8 두번째 원소로 정렬해 출력");
		for (int i = 0; i < array8.length; i++) {
			System.out.println(Arrays.toString(array8[i]));
		}

		Arrays.sort(array8, (e1, e2) -> {
			return e1.length - e2.length;
		});

		System.out.println("----> array8 배열 길이로 정렬해 출력");
		for (int i = 0; i < array8.length; i++) {
			System.out.println(Arrays.toString(array8[i]));
		}

		int[] array9 = { 1, 2, 3, 4, 5 };
		int[] array10 = { 1, 2, 3, 4, 5 };

		System.out.println(array9.equals(array10));
	}

	static void printArr(int[] arr) {
		System.out.println(Arrays.toString(arr));
	}

	static void fillArr(int[] arr) {
		Arrays.fill(arr, 1);
	}
}

 

728x90

'🔠 Language > ☕ Java' 카테고리의 다른 글

[JAVA] 함수 Interface  (0) 2021.12.07
[JAVA] PS에 유용하게 쓰이는 JAVA의 입출력 방법들  (0) 2021.11.26

알고리즘 풀이 포스팅을 작성하다 보니! 

JAVA 언어에 입출력 방법이 많아서 처음 PS를 접하시는 분들이 헷갈릴 법도 하다!라는 생각이 들었습니다.

그래서 JAVA에서 주로 사용되는 입출력 방법들을 총 정리해보도록 하겠습니다!

 

입력


1. Scanner

import java.util.Scanner;
//util 패키지에서 Scanner import

public class io_test {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// Scanner 선언

		int i = sc.nextInt();
		// Integer 타입 받아오기

		long l = sc.nextLong();
		// Long 타입 받아오기 (JAVA의 Long은 C의 LongLong과 같은 크기입니다.)

		double d = sc.nextDouble();
		// Double 타입 받아오기

		float f = sc.nextFloat();
		// Float 타입 받아오기

		String str1 = sc.next();
		//String으로 입력 받아오기 (공백문자로 끊어서 가져옴)
		String str2 = sc.nextLine();
		//String으로 입력 받아오기 (개행문자로 끊어서 가져옴)

		char[] charArr = sc.nextLine().toCharArray();
		char c = charArr[i];
		//String으로 입력 받아와서 Character 타입의 배열로 변환
		
	}
}

 

Scanner는 아주 간편하고 강력한 입력방법입니다.

내부적으로 입력을 parsing해서 여러 타입으로 변환하는 메소드들이 미리 구현되어 있기 때문에 간편하고 예외적인 상황을 통제하기도 좋지만, 시간이 오래 걸립니다. (trade off)

 

PS 문제들은 입력이 정확하게 규칙대로 주어지기 때문에 

풀이자가 입력의 예외를 잘 캐치하고 코드를 정확하게 작성했다면 Scanner를 사용하는 일은 괜히 동작 시간만 손해 보는 일이 될 수도 있습니다.

고난도의 PS 문제들은 입력의 개수가 10만, 100만 단위로 주어지기 때문에 A+B 같은 간단한 문제에선 신경 쓰이지 않던 시간 손해가 크리티컬 하게 작동할 수도 있기 때문입니다.

 

 

 

2. BufferedReader

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//BufferedReader와 InputStreamReader 그리고 입출력 예외 IOException import

public class io_test {
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//BufferedReader 선언하기
		
		String str = br.readLine();
		//String으로 입력 받아오기 (개행문자로 끊어서 가져옴)
		
		int i = Integer.parseInt(str);
		//String을 Integer로 parsing

		long l = Long.parseLong(str);
		//String을 Long으로 parsing

		double d = Double.parseDouble(str);
		//String을 Double로 parsing

		float f = Float.parseFloat(str);
		//String을 Float으로 parsing

		char[] charArr = str.toCharArray();
		char c1 = charArr[i];
		//String으로 입력 받아와서 Character 타입의 배열로 변환
		char c2 = str.charAt(i);
		//String으로 입력 받아와서 그 문자열의 index가 가리키는 Character 가져오기
	}
}

BufferedReader는 그 좋은 대안이 될 수 있습니다.

Buffered란 이름 그대로 버퍼에 입력을 쌓아두었다가 뭉탱이로 가져오는 놈이거든요.

대신 내부적인 타입 변환이 구현되어있지 않아 String, 또는 char[] 형태로 입력을 읽어옵니다.

 

가져온 값을 사용자가 직접 변환해주어야 하는데, 기본 타입 (Primitive type)들이나 기본적으로 재공 되는 Array, String 같은 Class 내부의 메소드를 이용해서 가능합니다.

 

하지만 이놈엔 문제가 있으니... 

input = "1 2 3" 과 같은 경우, Scanner는 nextInt()를 쓸 때마다 알아서 1,2,3을 가져왔던 반면 BufferedReader는 "1 2 3"의 String을 그대로 가져오게 되고, 이 String을 곧바로 parseInt에 넣는다면 에러가 나오게 됩니다.

parseInt는 하나의 숫자를 기대했는데, 들어온 값을 도무지 이해하기가 힘들기 때문이죠.

그래서 BufferedReader를 사용할 땐 StringTokenizer를 자주 같이 쓰게 됩니다.

 

3. BufferedReader + StringTokenizer

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//BufferedReader와 InputStreamReader 그리고 입출력 예외 IOException import
import java.util.StringTokenizer;
//StringTokenizer import

public class io_test {
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//BufferedReader 선언하기
		
		StringTokenizer st = new StringTokenizer(br.readLine());
		//br에서 가져온 String을 StringTokenizer로 쪼개기
		//기본적으로 공백문자로 쪼개지게 됨
		
		int a = Integer.parseInt(st.nextToken());
		int b = Integer.parseInt(st.nextToken());
		int c = Integer.parseInt(st.nextToken());
		//nextToken 메소드로 쪼개진 String을 가져옴
		
		System.out.println( a + ", " + b + ", " + c);
	}
}

위처럼 StringTokenizer를 사용해서 읽어온 String을 나누어 parsing 해주면, "1 2 3"같은 입력도 원하는 값으로 변환이 가능합니다.

 

StringTokenizer가 String을 쪼개는 기본적인 값은 공백문자이지만

StringTokenizer st = new StringTokenizer(br.readLine(), "a");

이런 식으로 쪼갤 delim을 지정해주게 되면

원하는 대로 String을 쪼개고 입력을 받을 수 있습니다.

또, hasMoreToken()과 같은 메서드로 남아있는 token이 있는지를 판별해 오류 없이 입력을 마무리할 수 있습니다.

 

출력


1. System.out.println

System.out.println("Hello JAVA");

정말 간단합니다. 기본적으로 제공되기 때문에 따로 import 할 패키지도 없습니다.

(Eclipse IDE 기준) sysout을 치고 ctrl+space를 누르면 자동으로 완성됩니다.

System.out.print(); 는 출력 문장의 뒤에 개행 문자 \n이 없고 System.out.println();은 기본적으로 줄 바꿈 하나가 들어가며 System.out.printf();는 c언어의 printf와 유사하게 format을 넣고 뒤에 그 안에 들어갈 변수들을 써서 사용할 수 있습니다.

 

간단한 프로그램에선 이 방법 만으로도 충분할 겁니다. 

하지만 출력이 수만, 수십만 개 반복되어야 하는 문제에선 출력 시간으로 인해 문제를 틀리는 경우가 생깁니다.

겉으로 보는 우리는 간편하고, 안정적이지만 메소드의 내부에선 출력마다 Sync와 Outputstream을 부르면서 시간을 잡아먹기 때문입니다.

(trade-off는 프로그래밍에서 뗄 수 없는 진리와도 같습니다.)

 

 

2. BufferedWriter

그래서 우리는 BufferedWriter를 사용할 수 있습니다. 이름을 보면 알 수 있듯, BufferedWriter는 BufferedReader의 출력 버전입니다. 

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class io_test {
	public static void main(String[] args) throws IOException{
		
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		//BufferedWriter 선언해주기! Reader와 마찬가지로 Stream의 import가 필요하다.
		
		bw.write("123\n");
		bw.write("456\n");
		bw.write("789\n");
		//Buffer에 출력할 값들을 쌓아놓는다.
		
		bw.flush();
		//쌓여있는 문장을 한 번에 출력!
		
		bw.close();
		//BufferedWriter를 닫아준다.
	}
}

사용법도 BufferedReader와 유사합니다.

여러 문장을 각각 출력하지 않고, Buffer에 Write해놓았다가 flush 메소드로 한 번에 출력하는 방법으로 시간을 단축합니다. 더 이상 BufferedWriter를 사용하지 않을땐 close해주는걸 잊지마세요!

 

 

3. System.out.println + StringBuilder

BufferedWriter 사용하기가 어렵게 느껴진다면, StringBuilder를 활용하는것도 좋은 방법입니다.

String을 하나로 만들어주는데 concat 메소드와 달리 시간이 많이 걸리지 않습니다. concat이 새로운 String객체를 계속 생성한다면 StringBuilder는 StringBuilder하나의 값들을 계속 이어 붙이는 방식입니다.

(JAVA 버전에 따라 + 연산이 내부적으로 concat으로도, StringBuilder로도 구현되어있다고 합니다. 헷갈리지 않게 하나로 통일감있게 사용합시다.)

public class io_test {
	public static void main(String[] args) {
		
		StringBuilder sb = new StringBuilder();
		//StringBuilder 선언, 따로 import할 package가 없다.
		
		sb.append("123 ");
		sb.append("456 ");
		sb.append("789\n");
		//StringBuilder에 출력할 문장을 계속 덧붙여준다.
		
		System.out.println(sb);
		//System.out.println(sb.toString());
		//출력한다. sb.toString()이 조금 더 명확하지만 그냥 출력해도 동작한다.
		
		//concat 메소드 예시
		 String str1 = "123 ";
		 str1 = str1.concat("456 ");
		 str1 = str1.concat("789\n");
		 
		 System.out.println(str1);
		 
		 //+연산 예시
		 String str2 = "123 "+"456 "+"789\n";
		 System.out.println(str2);
		
	}
}

출력된 결과는 모두 같습니다!

 

 

이상으로 JAVA의 입출력에 대해 설명을 마치겠습니다.

제가 쓴 내용은 기능적인 쪽에 중점을 두었고, Deep한 이론적인 내용은

 

JAVA [자바] - 입력 뜯어보기 [Scanner, InputStream, BufferedReader]

이 글을 지금 이 시점에 써야 할까 고민을 많이 했다. 사실 자바를 그냥 다룰 줄만 아는 것에 목표를 둔다면 이 글이 무의미할 수도 있다. 그러나 자바에 대해 조금이라도 관심이 있고 더 배우고

st-lab.tistory.com

이곳을 참고하시면 저어어엉말 잘 정리가 되어있습니다 ㅎㅎ

728x90

'🔠 Language > ☕ Java' 카테고리의 다른 글

[JAVA] 함수 Interface  (0) 2021.12.07
[JAVA] JAVA 배열 자주 쓰이는 코드 정리!  (0) 2021.11.30

+ Recent posts