-
[java] 메소드
intro : java 메소드에 대한 개념을 알아보자.
메서드 시작
두 숫자를 입력 받아서 더하고 출력하는 단순한 기능을 개발해보자. 먼저 1 + 2 를 수행하고, 그 다음으로 10 + 20 을 수행할 것인데, 아래 코드를 보면 두개의 변수를 받아서 합을 구하는 연산 과정이 중복이 된다. 이 중복되는 부분 어떻게 개선을 하면 좋을까 ?
public class Method1 {
public static void main(String[] args) {
// 계산1
int a = 1;
int b = 2;
System.out.println(a + "+" + b + " 연산 수행");
int sum1 = a + b;
System.out.println("결과1 출력:" + sum1);
// 계산2
int x = 10;
int y = 20;
System.out.println(x + "+" + y + " 연산 수행");
int sum2 = x + y;
System.out.println("결과2 출력:" + sum2);
}
}
메서드 사용
자바에서는 함수를 메서드(Method)라 한다. 메서드도 함수의 한 종류라고 생각하면 된다. 지금은 둘을 구분하지 않고, 이정도만 알아두자. 앞서 작성한 코드의 중복된 부분을 메서드를 이용하여 개선해보자.
public class Method1Ref {
public static void main(String[] args) {
int sum1 = add(5, 10);
System.out.println("결과1 출력:" + sum1);
int sum2 = add(15, 20);
System.out.println("결과2 출력:" + sum2);
}
// add 메서드
public static int add(int a, int b) {
System.out.println(a + "+" + b + " 연산 수행");
int sum = a + b;
return sum;
}
}
아래와 같은 코드에 add 함수를 메서드라고 한다. 메서드의 역할은 어떤 연산을 처리한 다음에 결과를 반환한다. (무조건적인 반환을 해주어야 하는건 아니다.)
public static int add(int a, int b) {
System.out.println(a + "+" + b + " 연산 수행");
int sum = a + b;
return sum;
}
메서드의 구조
메서드의 구조는 크게 2가지로 나눌 수 있는데, 메서드 선언부와 본문으로 나눌 수 있다.
메서드 선언
메서드 이름 반환타입 매개변수 목록을 포함한다. 이름 그대로 이런 메서드가 있다고 선언하는 것이다. 메서드 선언 정보를 통해 다른 곳에서 해당 메서드를 호출할 수 있다.
// add 메서드 선언부
public static int add(int a, int b)
메서드 본문
메서드가 수행해야 하는 코드 블록이다. 메서드를 호출하면 메서드 본문이 순서대로 실행된다. 메서드 본문은 블랙박스이다. 메서드를 호출하는 곳에서는 메서드 선언은 알지만 메서드 본문은 모른다. 메서드의 실행 결과를 반환하려면 return 문을 사용해야 한다. return 문 다음에 반환할 결과를 적어주면 된다.
{
// add 메서드 본문
System.out.println(a + "+" + b + " 연산 수행");
int sum = a + b;
return sum;
}
메서드 호출과 용어정리
메서드를 호출할 때는 다음과 같이 메서드에 넘기는 값과 매개변수(파라미터)의 타입이 맞아야 한다. 물론 넘기는 값과 매개변수(파라미터)의 순서와 갯수도 맞아야 한다.
인수 (Argument)
여기서 "hello" , 20 처럼 메서드에 넘기는 값을 영어로 Argument(아규먼트), 한글로 인수 또는 인자라 한다.실무에서는 아규먼트, 인수, 인자라는 용어를 모두 사용한다.
매개변수(Parameter)
메서드를 정의할 때 선언한 변수인 String str , int age 를 매개변수, 파라미터라 한다. 메서드를 호출할 때 인수를 넘기면, 그 인수가 매개변수에 대입된다. 실무에서는 매개변수, 파라미터 용어를 모두 사용한다.
위 둘의 단어는 반드시 분리되어 사용되어야 한다 혼용되어선 안된다.
메서드 정의
메서드는 다음과 같이 정의 할 수 있다.
public static int add(int a, int b) {
// 메서드 본문, 실행 코드
}
제어자 반환타입 메서드이름(매개변수 목록) {
메서드 본문
}
제어자(Modifier)
public , static 과 같은 부분이다. 제어자는 뒤에서 설명한다. 지금은 항상 public static 키워드를 입력하자.
반환 타입(Return Type)
메서드가 실행 된 후 반환하는 데이터의 타입을 지정한다. 메서드가 값을 반환하지 않는 경우, 없다는 뜻의 void 를 사용해야 한다. 예) void print(String str)
메서드 이름(Method Name)
메서드의 이름이다. 이 이름은 메서드를 호출하는 데 사용된다.
매개변수(Parameter)
입력 값으로, 메서드 내부에서 사용할 수 있는 변수이다. 매개변수는 옵션이다. 입력값이 필요 없는 메서드는 매개변수를 지정하지 않아도 된다. 예) add()
메서드 본문(Method Body)
실제 메서드의 코드가 위치한다. 중괄호 {} 사이에 코드를 작성한다.
반환 타입
반환 타입이 있으면 반드시 값을 반환해야 한다. 반환 타입이 있는 메서드는 반드시 return 을 사용해서 값을 반환해야 한다.
아래 코드에서 if 조건이 만족할 때는 true 가 반환되지만, 조건을 만족하지 않으면 어떻게 될까? 조건을 만족하지 않은 경우에는 return 문이 실행되지 않는다. 따라서 이 코드를 실행하면 return 문을 누락했다는 다음과 같은 컴파일 오류가 발생한다.
public class MethodReturn1 {
public static void main(String[] args) {
boolean result = odd(2);
System.out.println(result);
}
public static boolean odd(int i) {
if (i % 2 == 1) {
return true;
}
// 반드시 boolean 타입으로 return이 되어야 하는 메서드 인데 if문 조건을 만족하지 못한다면
// return 되지 않기에 컴파일 오류가 발생한다.
}
}
위 코드는 다음과 같이 수정되어야 한다.
public class MethodReturn1 {
public static void main(String[] args) {
boolean result = odd(2);
System.out.println(result);
}
public static boolean odd(int i) {
if (i % 2 == 1) {
return true;
} else {
// 조건문을 만족하지 않는다면 false 반환
return false;
}
}
}
return 문을 만나면 그 즉시 메서드를 빠져나간다.
return 문을 만나면 그 즉시 해당 메서드를 빠져나가는데 다음과 같이 활용할 수 있다. (메서드를 특정 시점에 강제로 종료해야할때 자주 사용한다.)
public class MethodReturn2 {
public static void main(String[] args) {
checkAge(10);
checkAge(20);
}
public static void checkAge(int age) {
if (age < 18) {
System.out.println(age + "살, 미성년자는 출입이 불가능합니다.");
// return 문을 만나면 메서드가 종료되고, 아래 출력문이 실행되지 않는다.
return;
}
System.out.println(age + "살, 입장하세요.");
}
}
메서드 호출과 값 전달1
자바에서 중요한 원칙이 있는데, 자바는 값을 대입할때 변수의 값을 복사해서 대입한다. 아래 코드를 통해서 내가 이해한 중요한 원칙을 제대로 이해했는지 확인해보자. 아래 주석으로 출력 결과를 작성했다. 혹시 틀리게 생각한 부분이 있다면 변수의 값을 복사해서 대입한다는 개념이 아직 부족하다는 뜻이다.
public class MethodValue1 {
public static void main(String[] args) {
int num1 = 5;
System.out.println("1. changeNumber 호출 전, num1: " + num1);
changeNumber(num1);
System.out.println("4. changeNumber 호출 후, num1: " + num1);
}
public static void changeNumber(int num2) {
System.out.println("2. changeNumber 변경 전, num2: " + num2);
num2 = num2 * 2;
System.out.println("3. changeNumber 변경 후, num2: " + num2);
}
}
// 1. changeNumber 호출 전, num1: 5
// 2. changeNumber 변경 전, num2: 5
// 3. changeNumber 변경 후, num2: 10
// 4. changeNumber 호출 후, num1: 5
메서드 호출과 값 전달2
다시한번 중요한 원칙인 자바는 값을 복사해서 대입한다라는 개념을 이해했는지 재확인해보자.
public class MethodValue2 {
public static void main(String[] args) {
int number = 5;
System.out.println("1. changeNumber 호출 전, number: " + number); // 출력: 5
changeNumber(number);
System.out.println("4. changeNumber 호출 후, number: " + number); // 출력: 5
}
public static void changeNumber(int number) {
System.out.println("2. changeNumber 변경 전, number: " + number); // 출력: 5
number = number * 2;
System.out.println("3. changeNumber 변경 후, number: " + number); // 출력: 10
}
}
// 1. changeNumber 호출 전, number: 5
// 2. changeNumber 변경 전, number: 5
// 3. changeNumber 변경 후, number: 10
// 4. changeNumber 호출 후, number: 5
메서드 호출과 값 반환받기
메서드를 사용해서 값을 변경하려면 어떻게 해야할까? 메서드의 호출 결과를 반환 받아서 사용하면 된다.
public class MethodValue3 {
public static void main(String[] args) {
int num1 = 5;
System.out.println("changeNumber 호출 전, num1: " + num1); // 출력: 5
num1 = changeNumber(num1);
System.out.println("changeNumber 호출 후, num1: " + num1); // 출력: 10
}
public static int changeNumber(int num2) {
num2 = num2 * 2;
return num2;
}
}
메서드와 형변환
메서드를 호출할 때도 형변환이 적용된다. 메서드 호출과 명시적 형변환, 자동 형변환에 대해 알아보자.
명시적 형변환
메서드를 호출하는데 인자와 매개변수의 타입이 맞지 않다면 어떻게 해야할까? 아래 주석을 풀고 실행하면 다음과 같은 오류가 발생한다. (java: incompatible types: possible lossy conversion from double to int)
public class MethodCasting1 {
public static void main(String[] args) {
double number = 1.5;
// double을 int형에 대입하므로 컴파일 오류
// 반드시 실행하고 싶다면 (int) number 을 인수로 전달해야 한다.
//printNumber(number);
printNumber((int) number); // 명시적 형변환을 사용해 double을 int로 변환
}
public static void printNumber(int n) {
System.out.println("숫자: " + n);
}
}
자동 형변환
int < long < double 메서드를 호출할 때 매개변수에 값을 전달하는 것도 결국 변수에 값을 대입하는 것이다. 따라서 앞서 배운 자동 형변환이 그대로 적용된다. 메서드를 호출할 때는 전달하는 인수의 타입과 매개변수의 타입이 맞아야 한다. 단 타입이 달라도 자동 형변환이 가능한 경우에는 호출할 수 있다.
byte → short → int → long → float → double
char → int → long → float → double
public class MethodCasting2 {
public static void main(String[] args) {
int number = 100;
printNumber(number); // int에서 double로 자동 형변환
}
public static void printNumber(double n) {
System.out.println("숫자: " + n);
}
}
메서드 오버로딩
자바는 메서드의 이름 뿐만 아니라 매개변수 정보를 함께 사용해서 메서드를 구분한다. 따라서 다음과 같이 이름이 같고, 매개변수가 다른 메서드를 정의할 수 있다. 이렇게 이름이 같고 매개변수가 다른 메서드를 여러개 정의하는 것을 메서드 오버로딩(Overloading)이라 한다. 오버로딩은 번역하면 과적인데, 과하게 물건을 담았다는 뜻이다. 따라서 같은 이름의 메서드를 여러개 정의했다고 이해하면 된다.
오버로딩 규칙
메서드의 이름이 같아도 매개변수의 타입 및 순서가 다르면 오버로딩을 할 수 있다. 참고로 반환 타입은 인정하지 않는다.
메서드 시그니처(method signature)
메서드 시그니처 = 메서드 이름 + 매개변수 타입(순서)
메서드 시그니처는 자바에서 메서드를 구분할 수 있는 고유한 식별자나 서명을 뜻한다. 메서드 시그니처는 메서드의 이름과 매개변수 타입(순서 포함)으로 구성되어 있다. 쉽게 이야기해서 메서드를 구분할 수 있는 기준이다. 자바 입장에서는 각각의 메서드를 고유하게 구분할 수 있어야한다. 그래야 어떤 메서드를 호출 할 지 결정할 수 있다. 따라서 메서드 오버로딩에서 설명한 것 처럼 메서드 이름이 같아도 메서드 시그니처가 다르면 다른 메서드로 간주한다. 반환 타입은 시그니처에 포함되지 않는다.
다음 코드는 오버로딩을 활용한 코드이다.
public class Overloading1 {
public static void main(String[] args) {
System.out.println("1: " + add(1, 2));
System.out.println("2: " + add(1, 2, 3));
}
// 첫 번째 add 메서드: 두 정수를 받아서 합을 반환한다.
public static int add(int a, int b) {
System.out.println("1번 호출");
return a + b;
}
// 두 번째 add 메서드: 세 정수를 받아서 합을 반환한다.
// 첫 번째 메서드와 이름은 같지만, 매개변수 목록이 다르다.
public static int add(int a, int b, int c) {
System.out.println("2번 호출");
return a + b + c;
}
}
아래코도는 오버로딩 케이스중에 헷갈릴만한 케이스인데, add 메서드는 파라미터가 실수형 타입 double을 인자값으로 받고있다. 이때 add(1, 2)를 호출하게 된다면 어떻게 될까? 단순히 실수형 타입에 정수형 타입을 넣어야 하니 오류가발생할것 같지만 실제로는 자동형변환이 일어나서 add(1, 2) 가 정상적으로 실행된다.
public class Main {
public static void main(String[] args) {
System.out.println("1: " + add(1, 2));
System.out.println("2: " + add(1.2, 1.5));
}
public static double add(double a, double b) {
System.out.println("add 메서드 호출");
return a + b;
}
}
// add 메서드 호출
// 1: 3.0
// add 메서드 호출
// 2: 2.7
-
[java] 배열
intro : java 배열에 대한 개념을 알아보자.
배열 시작
배열이 필요한 이유
만약 학생의 점수를 출력해야하는 간단한 프로그램을 구성한다고 생각해보자. 각 학생이 추가될때마다 새로운 변수에 점수를 담고, 해당 점수를 출력을 하게되는데, 아직 배열에 대한 개념을 배우기 전이기 때문에 다음과 같은 코드를 통해 조금 힘들게 구성을 해야한다. 이렇게 같은 타입의 변수를 반복해서 선언하고 반복해서 사용하는 문제를 해결할수 있는게 배열이라는 개념이다.
public class Array1 {
public static void main(String[] args) {
int student1 = 90;
int student2 = 80;
int student3 = 70;
int student4 = 60;
int student5 = 50;
System.out.println("학생1 점수: " + student1);
System.out.println("학생2 점수: " + student2);
System.out.println("학생3 점수: " + student3);
System.out.println("학생4 점수: " + student4);
System.out.println("학생5 점수: " + student5);
}
}
배열의 선언과 생성
배열은 같은 타입의 변수를 사용하기 편리하게 하나로 묶어둔 것이다. 위 예제에서는 학생이라는 변수는 같은 int형 타입으로 묶을수 있는데 다음과 같이 코드를 구성할 수 있다.
public class Array1Ref1 {
public static void main(String[] args) {
int[] students; // 배열 변수 선언
students = new int[5]; // 배열 생성
// 변수 값 대입
students[0] = 90;
students[1] = 80;
students[2] = 70;
students[3] = 60;
students[4] = 50;
// 변수 값 사용
System.out.println("학생1 점수: " + students[0]);
System.out.println("학생2 점수: " + students[1]);
System.out.println("학생3 점수: " + students[2]);
System.out.println("학생4 점수: " + students[3]);
System.out.println("학생5 점수: " + students[4]);
}
}
배열의 생성 단계
배열의 생성 단계에는 다음과 같은 단계를 따르는데 배열의 선언, 배열 생성, 배열 참조값 보관을 따른다. 배열의 선언은 int[] students; 이처럼 내가 공통으로 묶고자 하는 타입을 [ ] 대괄호를 이용하여 묶고 변수를 선언하는 것을 말한다. 이후 해당 변수의 실제 생성 부분은 new 연산자를 이용해 new int[5] 배열의 사이즈를 지정한다. 이렇게 배열을 선언하고 생성하게되면 선언한 변수에 생성한 배열 참조값을 보관하게 된다. 참조값이란? 기존 변수 Chapter에서 배운 내용은 기본형 변수 타입 인데, 기본형 변수 타입을 제외한 모든 변수 타입은 참조형 변수 타입으로 주소값(참조값)을 통해 접근할 수 있다.
배열 사용
인덱스
배열은 변수와 사용법이 비슷한데, 차이점이 있다면 다음과 같이 [] 사이에 숫자번호를 넣어주면 된다. 배열의 위치를 나타내는 것을 index(인덱스) 라고 한다. 참고로 배열에서 인덱스는 1이 아니라 0 부터시작한다. 만약 접근 가능한 배열의 인덱스 범위를 넘어가면 java.lang.ArrayIndexOutOfBoundsException 오류가 발생한다.
// 변수 값 대입
students[0] = 90;
students[1] = 80;
// 변수 값 사용
System.out.println("학생1 점수: " + students[0]);
System.out.println("학생2 점수: " + students[1]);
배열에 값 대입
배열에 값을 대입하던지 배열의 값을 사용하던지 일반적인 변수와 사용법은 같다. 추가로 [] 를 통해 접근하고자 하는 배열의 인덱스 값만 넣어주면 된다.
students[0] = 90; // 1. 배열에 값을 대입
x001[0] = 90; // 2. 변수에 있는 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근, 값 대입
students[1] = 80; // 1. 배열에 값을 대입
x001[1] = 80; // 2. 변수에 있는 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근, 값 대입
배열 값 읽기
배열을 사용할때는 다음과 같이 참조값을 통해서 실제 배열에 접근하고 인덱스를 통해서 원하는 요소를 찾을 수 있다.
// 1. 변수 값 읽기
System.out.println("학생1 점수: " + students[0]);
// 2. 변수에 있는 참조값을 통해 실제 배열에 접근. 인덱스를 사용해서 해당 위치의 요소에 접근
System.out.println("학생1 점수: " + x001[0]); // students 변수의 주소값이 x001 가정
// 3. 배열의 값을 읽어옴
System.out.println("학생1 점수: " + 90);
기본형 vs 참조형
자바의 변수 데이터 타입을 가장 크게 보면 기본형과 참조형으로 분류할 수 있다. 사용하는 값을 직접 넣을 수 있는 기본
형, 그리고 방금 본 배열 변수와 같이 메모리의 참조값을 넣을 수 있는 참조형으로 분류할 수 있다. 기본형(Primitive Type): 우리가 지금까지 봤던 int , long , double , boolean 처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입을 기본형(Primitive Type)이라 한다. 참조형(Reference Type): int[] students 와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입을 참조형(Reference Type)이라 한다. (위에서 살짝 언급한 내용을 다시 한번 정리한다.)
배열은 왜 참조형을 사용할까 ?
int, long, double 등 기본형 타입 변수들은 선언과 동시에 사이즈가 정해진다. int (4 Byte), long(8 Byte), double(8 Byte) ….. 배열은 생성시점에 동적으로 크기를 지정하게 되는데 예를들면 int[] array = new int[10] 인 경우는 배열의 사이즈가 int 타입이 10개 있기에 40 Byte가 할당된다. 이렇게 참조형 타입을 사용하면 동적으로 크기를 설정할 수 있는 유연성을 제공 할 수 있고 복잡한 데이터 구조도 만들고 관리할 수 있는 장점이 생기기에 배열은 참조형을 사용한다.
배열 리펙토링
아래 코드를 보면 배열의 선언과 생성 부분에서 나왔던 코드랑은 굉장히 비교가 될 정도로 짧아지고 효율적인 코드를 작성할 수 잇게된다. 학생이 추가 될때마다 변수를 새로 생성하고, 출력문을 다시 작성했던것에 비해 아래 코드는 만약 학생이 추가될 경우 students 변수에 값을 하나 더 추가해주면 반복문을 통해 자동으로 새로 추가된 학생의 값 또한 출력 할 수 있게 된다.
public class Array1Ref4 {
public static void main(String[] args) {
//배열 생성 간략 버전, 배열 선언과 함께 사용시 new int[] 생략 가능
int[] students = {90, 80, 70, 60, 50};
for (int i = 0; i < students.length; i++) {
System.out.println("학생" + (i + 1) + " 점수: " + students[i]);
}
}
}
2차원 배열 - 시작
지금까지 학습한 배열은 단순히 순서대로 나열되어 있었다. 이것을 1차원 배열이라 한다. 이번에 학습할 2차원 배열은 이름 그대로 하나의 차원이 추가된다. 2차원 배열은 행과 열로 구성된다. 2차원 배열의 사용법은 [] 가 하나 추가되는 것을 제외하고는 앞서본 1차원 배열과 같다. 아래 코드를 통해 2차원 배열에 대해서 알아보자.
public class ArrayDi0 {
public static void main(String[] args) {
// 2x3 2차원 배열을 만든다.
int[][] arr = new int[2][3]; // 행(row), 열(column)
arr[0][0] = 1; // 0행, 0열
arr[0][1] = 2; // 0행, 1열
arr[0][2] = 3; // 0행, 2열
arr[1][0] = 4; // 1행, 0열
arr[1][1] = 5; // 1행, 1열
arr[1][2] = 6; // 1행, 2열
// 0행 출력
System.out.print(arr[0][0] + " "); // 0열 출력
System.out.print(arr[0][1] + " "); // 1열 출력
System.out.print(arr[0][2] + " "); // 2열 출력
System.out.println(); // 한 행이 끝나면 라인을 변경한다.
// 1행 출력
System.out.print(arr[1][0] + " "); // 0열 출력
System.out.print(arr[1][1] + " "); // 1열 출력
System.out.print(arr[1][2] + " "); // 2열 출력
System.out.println(); // 한 행이 끝나면 라인을 변경한다.
}
}
2차원 배열 - 리펙토링1
위 2차원 배열에서의 코드를 보면 중복된 부분이 존재한다. 0행과 1행을 출력하는 코드의 내용을 자세히보면 결국 2차원 배열에서의 행과 열에 대한 인덱스를 순차적으로 접근하여 출력하면 된다는 것을 눈치 챌 수 있다. 아래 코드처럼 2중 반복문을 통해 순차적으로 2차원 배열의 인덱스를 활용하여 코드를 깔끔하게 작성할 수 있다.
public class ArrayDi2 {
public static void main(String[] args) {
// 2x3 2차원 배열을 만듭니다.
int[][] arr = new int[2][3]; // 행(row), 열(column)
arr[0][0] = 1; // 0행, 0열
arr[0][1] = 2; // 0행, 1열
arr[0][2] = 3; // 0행, 2열
arr[1][0] = 4; // 1행, 0열
arr[1][1] = 5; // 1행, 1열
arr[1][2] = 6; // 1행, 2열
for (int row = 0; row < 2; row++) {
for (int column = 0; column < 3; column++) {
System.out.print(arr[row][column] + " ");
}
System.out.println(); // 한 행이 끝나면 라인을 변경한다.
}
}
}
2차원 배열 - 리펙토링2
리팩토링 1번에서의 부족한 부분을 조금더 찾아보면 배열의 선언과 초기화하는 부분에서 조금 아쉬운 부분이 존재한다, 2중 반복문에서 조건식에 해당하는 부분의 코드가 하드코딩으로 행과 열의 값 2, 3 으로 작성되어 있는게 아쉽다. 배열은 동적으로 크기가 변할 수 있기 때문에 변경 포인트를 최대한 줄이는게 유지보수 측면에서도 좋기에 위 문제를 리팩토링하여 개선한 코드는 다음과 같이 작성할 수 있다.
public class ArrayDi3 {
public static void main(String[] args) {
// 2x3 2차원 배열, 초기화
// 배열의 생성시 new int[2][3] 대신에 다음과 같이 {} 를 이용해 직접 작성할 수 있다.
int[][] arr = {
{1, 2, 3},
{4, 5, 6}
};
// 2차원 배열의 길이를 활용
// 행과 열의 크기를 배열의 length 메소드를 통해 지정
for (int row = 0; row < arr.length; row++) {
for (int column = 0; column < arr[row].length; column++) {
System.out.print(arr[row][column] + " ");
}
System.out.println();
}
}
}
향상된 for문 (배열같은 순차적인 데이터에 접근해야할때 유용하다)
보통 for-each 문으로 부르며 향상된 for문은 기존의 반복문 보다 더 편리하게 사용할 수 있다. 물론 모든 상황에서 편리하게 사용할 수 있는건 아니지만 대부분의 상황에서는 향상된 for문을 사용한다. (index 값을 사용해야 하는 경우는 향상된 for문이 아니라, 기존에 사용하던 for문을 사용하자)
향상된 for문 정의
for (변수 : 배열 또는 컬렉션) {
// 배열 또는 컬렉션의 요소를 순회하면서 수행할 작업
}
향상된 for문 예제
public class EnhancedFor1 {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
//일반 for문
for(int i = 0; i < numbers.length; ++i) {
int number = numbers[i];
System.out.println(number);
}
//향상된 for문, for-each문
for (int number : numbers) {
System.out.println(number);
}
//for-each문을 사용할 수 없는 경우, 증가하는 index 값 필요
for(int i = 0; i < numbers.length; ++i) {
System.out.println("number" + i + "번의 결과는: " + numbers[i]);
}
}
}
-
[java] 스코프, 형변환
intro : java 스코프, 형변환에 대한 개념을 알아보자.
스코프1 - 지역 변수와 스코프
변수는 선언한 위치에 따라 지역 변수, 멤버 변수(클래스 변수, 인스턴스 변수)와 같이 분류된다. 지역 변수는 이름 그대로 특정 지역에서만 사용할 수 있는 변수라는 뜻이다. 그 특정 지역을 벗어나면 사용할 수 없다. 여기서 말하는 지역이 바로 변수가 선언된 코드 블록 ({ })이다. 지역 변수는 자신이 선언된 코드 블록 안에서만 생존하고, 자신이 선언된 코드 블록을 벗어나면 제거된다. 따라서 이후에는 접근 할 수 없다.
public class Scope1 {
public static void main(String[] args) {
int m = 10; //m 생존 시작
if (true) {
int x = 20; //x 생존 시작
System.out.println("if m = " + m); //블록 내부에서 블록 외부는 접근 가능
System.out.println("if x = " + x);
} //x 생존 종료
//System.out.println("main x = " + x); //오류, 변수 x에 접근 불가
System.out.println("main m = " + m);
} //m 생존 종료
}
정리하자면 지역변수는 본인의 코드블록 안에서만 생존하고 자신의 코드블록을 벗어나면 제거되기 때문에 접근할 수 없다. 이렇게 변수의 접근 가능한 범위를 스코프(Scope) 라고 한다. 참고로 번역하면 범위라는 뜻이다. 아래 코드에서는 변수 m은 main 메소드 안에서 접근 가능한 지역변수 이지만, 변수 i는 for문 안에서만 접근 가능한 지역변수이다.
public class Scope2 {
public static void main(String[] args) {
int m = 10;
for (int i = 0; i < 2; i++) { //블록 내부, for문 내
System.out.println("for m = " + m); //블록 내부에서 외부는 접근 가능
System.out.println("for i = " + i);
} //i 생존 종료
//System.out.println("main i = " + i); //오류, i에 접근 불가
System.out.println("main m = " + m);
}
}
스코프2 - 스코프 존재 이유
변수를 선언한 시점부터 변수를 계속 사용할 수 있께 해도 되지 않을까? 왜 복잡하게 접근 범위라는 개념을 만들었을까?
public class Scope3_1 {
public static void main(String[] args) {
int m = 10;
int temp = 0;
if (m > 0) {
temp = m * 2;
System.out.println("temp = " + temp);
}
System.out.println("m = " + m);
}
}
위 코드를 보면 변수 m을 2배로 증가해서 출력하는 코드이다. 여기서 두배 증가한 값을 저장하기 위해 변수 temp를 사용하였는데, 해당 변수의 사용범위는 if 조건 안에서만 사용된다. 그런데 현재 temp 변수는 main 코드 블록안에 선언되어 있다. 이런경우 다음과 같은 문제가 발생한다.
비효율적 메모리 사용
temp는 if 코드 블록에서만 필요하지만 main 코드 블록이 종료될떄까지 메모리에 유지된다. 따라서 불필요한 메모리가 낭비된다. 만약 if 조건안에 temp를 선언했다면 더 효율적으로 메모리를 사용할 수 있다.
코드 복잡성 증가
좋은 코드는 군더더기가 없는 코드이다. temp변수는 if 조건 안에서만 필요하고 여기서만 사용하면 된다. 만약 if 조건안에서 temp 변수를 선언했다면 if 가 끝나고 temp를 전혀 생가하지 않아도 된다. 현재 위 코드는 간단한 코드이기에 복잡성이 증가한다는 말에 동의하기 어렵겠지만 실무환경에서는 하나라도 복잡성을 줄이는게 개발 생산성에 도움을 준다.
while문 vs for문 - 스코프 관점
아래 코드의 변수 스코프 관점에서 카운터 변수 i를 살펴보자. while문 예쩨에서는 i가 main 메소드 안에 선언되어 있고, for문 예제에서는 for문안에 선언되어 있다. 이런경우는 스코프의 제한이 for문이 더 제한적이기에 메모리 효올과 유지보수 관점에서 더 좋은점을 가지고 갈 수 있다.
// while문 예제
public class While2_3 {
public static void main(String[] args) {
int sum = 0;
int i = 1;
int endNum = 3;
while (i <= endNum) {
sum = sum + i;
System.out.println("i=" + i + " sum=" + sum);
i++;
}
//... 아래에 더 많은 코드들이 있다고 가정
}
}
// for문 예제
public class For2 {
public static void main(String[] args) {
int sum = 0;
int endNum = 3;
for (int i = 1; i <= endNum; i++) {
sum = sum + i;
System.out.println("i=" + i + " sum=" + sum);
}
//... 아래에 더 많은 코드들이 있다고 가정
}
}
형변환1 - 자동 형변환
작은 범위에서 큰 범위로는 당연히 값을 넣을 수 있다.(int 👉 long 👉 double) 큰 범위에서 작은 범위는 다음과 같은 문제가 발생할 수 있다. (소수점버림, 오버플로우)
작음 범위에서 큰 범위로 대입은 허용한다.
자바에서 숫자를 표현할수 있는 범위는 다음과 같다. int < long < double int 보다는 long 이, long 보다는 double 이 더 큰 범위를 표현할 수 있다. 작은 범위에서 큰 범위에 값을 대입하는 코드는 실행하면 특별한 문제없이 잘 수행된다. 자바는 기본적으로 같은 타입에 값을 대입할 수 있다. 그런데 다른 타입에 값을 대입하면 어떻게 될까? int long 을 비교해보면 long 이 int 보다 더 큰 숫자 범위를 표현한다. 작은 범위 숫자 타입에서 큰 범위 숫자 타입에 대입을 하면 문제가 되지 않는다. 만약 이런 경우까지 오류가 발생한다면 개발이 너무 불편할 것이다. long double 의 경우에도 double 은 부동 소수점을 사용하기 때문에 더 큰 숫자 범위를 표현한다. 따라서 대입할 수 있다. 정리하면 작은 범위에서 큰 범위로의 대입은 자바 언어에서 허용한다. 쉽게 이야기하면 큰 그릇은 작은 그릇에 담긴 내용물을 담을 수 있다.
public class Casting1 {
public static void main(String[] args) {
int intValue = 10;
long longValue;
double doubleValue;
longValue = intValue; // int -> long
System.out.println("longValue = " + longValue); //longValue = 10
doubleValue = intValue; // int -> double
System.out.println("doubleValue1 = " + doubleValue); //doubleValue1 = 10.0
doubleValue = 20L; // long -> double
System.out.println("doubleValue2 = " + doubleValue); //doubleValue2 = 20.0
}
}
자동형변환 (묵시적 형변환)
하지만 결국 대입하는 형(타입)을 맞추어야 하기 때문에 개념적으로는 다음과 같이 동작한다.
doubleValue = intValue
doubleValue = (double) intValue //형 맞추기
doubleValue = (double) 10 //변수 값 읽기
doubleValue = 10.0 //형변환
형변환2 - 명시적 형변환
큰 범위에서 작은 범위 대입은 명시적 형변환이 필요하다 만약 실수형 데이터를 정수형 타입에 담으면 어떻게 될까? double 타입의 데이터를 int에 담아보겠다. 명시걱으로 타입을 지정해서 형변환을 해주지 않으면 컴파일 오류가 발생한다.
public class Casting2 {
public static void main(String[] args) {
double doubleValue = 1.5;
int intValue = 0;
//intValue = doubleValue; //컴파일 오류 발생
intValue = (int) doubleValue; //형변환
System.out.println(intValue); //출력:1
}
}
형변환
하지만 만약 이런 위험을 개발자가 직접 감수하고도 값을 대입하고 싶다면 데이터 타입을 강제로 변경할 수 있다. 예를들어서 대략적인 결과를 보고싶은데 이때 소수점을 버리고 정수로만 보고 싶을 수 있다. 우리는 아래 코드와 같이 개발자가 직접 타입을 변환하는 것을 명시적 형변환 이라고 한다.
double doubleValue = 1.5;
intValue = (int) doubleValue; //형변환, intValue에 1이 할당 됨
형변환과 오버플로우
형변환을 할때 만약 작은 숫자가 표현할 수 있는 범위를 넘어서면 어떻게 될까? 아래코드에서 변수 maxIntOver 값을 intValue에 int 타입으로 변환하게되면 오버플로우가 발생한다. 정수형에서의 오버플로우는 int 타입으로 담을수 없는 큰 값이 들어오는경우 발생한다. 그렇기에 오버플로우가 발생하지 않도록 변수의 타입을 적절하게 잘 지정해 주어야 한다.
public class Casting3 {
public static void main(String[] args) {
long maxIntValue = 2147483647; //int 최고값
long maxIntOver = 2147483648L; //int 최고값 + 1(초과)
int intValue = 0;
intValue = (int) maxIntValue; //형변환
System.out.println("maxIntValue casting=" + intValue); //출력:2147483647
intValue = (int) maxIntOver; //형변환
System.out.println("maxIntOver casting=" + intValue); //출력:-2147483648
}
}
오버플로우, 언더플로우 조금만 더 알아보자!
정수 (시계열이라고 생각하자)
오버플로우 : 최댓값을 넘으면 최솟값으로 되돌아갑니다.
언더플로우 : 최솟값을 넘으면 최댓값으로 되돌아갑니다.
실수 (표현 못하는 숫자가 되니까 무한대 혹은 0으로 표현한다고 생각하자)
오버플로우 : 값이 너무 커지면 Inf(무한대)가 됩니다.
언더플로우 : 값이 너무 작아지면 서브노멀 값으로 표현되거나 0에 가까워집니다.
계산과 형변환
형변환은 대입 뿐만 아니라, 계산을 할 때도 발생한다. 알고리즘 문제 풀이시 오버플로우가 발생한다면 해당 개념이 부족해서 많이 발생하는거라고 볼 수 있다. (사실 내 얘기다…) 자바에서 계산은 다음과 같은 2가지를 기억하면 된다. 같은 타입끼리의 계산은 같은 타입의 결과를 낸다, 서로다른 타입의 계산은 큰 범위로 자동형변환이 일어난다.
public class Casting4 {
public static void main(String[] args) {
int div1 = 3 / 2;
System.out.println("div1 = " + div1); //1
double div2 = 3 / 2; // 정수끼리의 연산결과를 실수형 double에 담을 뿐이기에 결과는 1.0 이다.
System.out.println("div2 = " + div2); //1.0
double div3 = 3.0 / 2; // 실수형과, 정수형의 연산은 실수형의 결과로 반환된다.
System.out.println("div3 = " + div3); //1.5
double div4 = (double) 3 / 2;
System.out.println("div4 = " + div4); //1.5
int a = 3;
int b = 2;
double result = (double) a / b;
System.out.println("result = " + result); //1.5
}
}
-
[java] 반복문
intro : java 반복문에 대한 개념을 알아보자.
반복문 시작
반복문은 이름 그대로 특정 코드를 반복해서 실행할 떄 사용한다. 자바는 다음 3가지 종류의 반복문을 제공한다.
while , do-while , for
위와 같은 반복문들을 어떤 상황에서 어떻게 사용 할 수 있는지 차근차근 알아보자.
while문 1
while 문은 조건에 따라 코드를 반복해서 실행할 때 사용한다. 조건식을 확인 하였을 때 참이면 코드 블럭을 실행하고 거짓이면 while문을 벗어난다. 만약 조건식이 참 인경우 코드 블록을 실행한 이후에 다시 조건식 검사로 들어가서 조건식을 검사한다.무한반복
while (조건식) {
// 코드
}
좀 더 실제 개발 환경에서 만나볼 수 있을 것 같은 예제를 보면 다음과 같은 코드를 참고 할 수 있다.
public class While1_2 {
public static void main(String[] args) {
int count = 0;
while (count < 3) {
count++;
System.out.println("현재 숫자는:" + count);
}
}
}
while문 2
while 문을 좀더 다양한 상황에 적용해보자, 만약 1부터 3까지 값을 더해야 하는 상황이 있다고 가정해보겠다 while문으로 어떻게 코드를 작성하면 좋을까 ?
public class While2_3 {
public static void main(String[] args) {
int sum = 0;
int startNum = 1;
int endNum = 3;
while (startNum <= endNum) { // startNum이 endNum(3) 이 될때까지 while문 반복
sum = sum + startNum;
System.out.println("startNum=" + startNum + " sum=" + sum);
startNum++;
}
}
}
do-while문
do-while문은 while문과 비슷하지만, 조건에 상관없이 무조건 한 번은 코드를 실행한다.
do {
// 코드 (무조건 한번은 실행된다, 이후에 while문의 조건식이 참인 경우 do 문장을 다시 실행하게 된다.)
} while (조건식);
예를 들어서 조건에 만족하지 않아도 한번은 현재 값을 출력하고 싶다고 하자. 먼저 while 문을 사용한 예제를 보겠다.
public class DoWhile1 {
public static void main(String[] args) {
int i = 10;
while (i < 3) {
System.out.println("현재 숫자는:" + i);
i++;
}
}
}
while 문의 조건에 부합하지 않기때문에 false 가 나오게 되고, 아무것도 출력되지 않는 실행결과를 볼 수 있다. 이번에는 do-while문을 사용해 보겠다. 아래와 같이 코드를 작성한다면, do-while은 do 블록의 코드를 먼저 실행하고 while문의 조건을 검사 후, 참 이면 do 블록의 코드를 실행하고 거짓 이면 do 블록의 코드를 실행하지 않는다. 그렇기에 아래 코드는 현재 숫자는: 10 이라는 결과를 출력하게 된다.
public class DoWhile2 {
public static void main(String[] args) {
int i = 10;
do {
System.out.println("현재 숫자는:" + i);
i++;
} while (i < 3);
}
}
결론적으로 do-while문은 최초 한번은 코드 블럭을 꼭 실행해야 하는 경우에 사용하면 된다.
break, continue
break와 continue는 반복문에서 사용할 수 있는 키워드다. break문은 반복문을 즉시 종료하고 나간다 (가장 가까운 반복문을 탈출한다) continue는 반복문의 나머지 부분을 건너뛰고 다음 반복문으로 진행하는데 사용한다. 해당 키워드 들은 while , do-while , for 와 같은 모든 반복문에서 사용할 수 있다.
break
아래 코드에서 코드1 실행후 break 를 만나면 코드2는 실행하지 않고 while문이 종료된다.
while (조건식) {
코드1;
break; //즉시 while문 종료로 이동한다.
코드2;
} //while문 종료
아래 코드는 sum이 10보다 크면 break문을 통해 반복문을 탈출하는 코드이다.
public class Break1 {
public static void main(String[] args) {
int sum = 0;
int i = 1;
while (true) {
sum += i;
if (sum > 10) {
break;
System.out.println("합이 10보다 크면 종료: i=" + i + " sum=" + sum);
}
i++;
}
}
}
continue
continue를 만나면 코드2 가 실행되지 않고 다시 조건식으로 이동한다. 조건식이 참이면 while 문을 실행한다.
while (조건식) {
코드1;
continue; //즉시 조건식으로 이동한다.
코드2;
}
아래 코드는 i가 3일 때 continue을 통해 반복문의 조건식으로 이동하는 코드이다.
public class Continue1 {
public static void main(String[] args) {
int i = 1;
while (i <= 5) {
if (i == 3) {
i++;
continue;
}
System.out.println(i);
i++;
}
}
}
for문1
for문도 while문과 같은 반복문이고, 코드를 반복 실행하는 역할을 한다. for문은 주로 반복 횟수가 정해져 있을 때 사용한다. for문은 다음과 같은 순서대로 실행된다.
step 1
초기식이 실행된다. 주로 반복 횟수와 관련된 변수를 선언하고 초기화 할 때 사용한다.
초기식은 딱 1번 사용된다.
step 2
조건식을 검증한다. 참이면 코드를 실행하고, 거짓이면 for문을 빠져나간다.
step 3
코드를 실행한다.
step 4
코드가 종료되면 증감식을 실행한다. 주로 초기식에 넣은 반복 횟수와 관련된 변수의 값을 증가할 때 사용한다.
step 5
다시 2. 조건식 부터 시작한다. 무한 반복
for (1.초기식; 2.조건식; 4.증감식) {
// 3.코드
}
for문은 while문을 조금 더 편하게 다룰 수 있도록 구조화 한거라고 볼 수 있는데 다음과 같은 예제를 보면 조금 더 for문 사용법에 대해서 알 수 있다. 1부터 10까지의 값을 출력하는 반복문인데 for문의 구조 순서대로 따라가면 순차적으로 1부터 10까지의 값을 출력하는 것을 알 수 있다.
public class For1 {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
System.out.println(i);
}
}
}
for문2
for문에서 초기식, 조건식, 증감식은 선택이다.
for (초기식; 조건식; 증감식) {
// 코드
}
다음과 같이 모두 생략해도 된다. 단 생략해도 각 영역을 구분하는 세미콜론(;)은 유지해야한다
for (;;) {
// 코드
}
결국 위 반복문은 다음과 같은 코드가 된다.
while (true) {
// 코드
}
위와같은 초기식 조건식 증감식을 전부 생략하고 사용하는 코드는 어떤 상황에서 사용할까 ? 솔직히 좀 억지스럽지만 이렇게도 사용할 수 있다는 문법적인 내용으로만 이해하는게 좋은거 같다. 실제로는 거의 사용을 안한다.
아래 코드는 1부터 시작해서 숫자를 계속 누적해서 더하다가 10보다 큰 시점이 되었을떄의 i 값을 구하는 문제이다. 쉽게 얘기해서 i = 1일때 sum = 1, i = 2일때 sum = 3, i = 3일때 sum = 6, i = 4일때 sum = 10, i = 5일때는 sum = 15 가 되기에 10보다 큰 값이 처음으로 나오는 i 값인 5를 출력하면 되는 것이다. 다만 이것을 초기식 조건식 증감식을 생략한 for문으로 코드를 구현 해 보는 것이다.
public class Break2 {
public static void main(String[] args) {
int sum = 0;
int i = 1;
for (; ; ) { // 초기식 조건식 증감식 생략
sum += i;
if (sum > 10) {
break; // if 조건이 만족하였을때 반복문 탈출
System.out.println("합이 10보다 크면 종료: i=" + i + " sum=" + sum);
}
i++;
}
}
}
중첩 반복문
반복문은 내부에 또 반복문을 만들 수 있다. for, while 모두 가능하다.
public class Nested1 {
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
System.out.println("외부 for 시작 i:" + i);
for (int j = 0; j < 3; j++) {
System.out.println("-> 내부 for " + i + "-" + j);
}
System.out.println("외부 for 종료 i:" + i);
System.out.println(); //라인 구분을 위해 실행
}
}
}
다음은 위 코드의 실행 결과이며, 외부 for는 2번, 내부 for는 3번 실행된다. 그런데 외부 for 1번당 내부 for가 3번 실행되기 때문에 외부(2) * 내부(3) 해서 총 6번의 내부 for 코드가 수행된다. 이러한 중첩 반복문은 평소에도 자주 사용되고 실제 개발 환경 및 알고리즘 문제에서도 굉장히 자주 사용이 된다. 정말 많이 사용한다.
외부 for 시작 i:0
-> 내부 for 0-0
-> 내부 for 0-1
-> 내부 for 0-2
외부 for 종료 i:0
외부 for 시작 i:1
-> 내부 for 1-0
-> 내부 for 1-1
-> 내부 for 1-2
외부 for 종료 i:1
-
[java] 조건문
intro : java 조건문에 대한 개념을 알아보자.
if문1 - if else
조건문 시작
특정 조건에 따라서 코드를 실행하려면 어떻게 해야할까? 예를들어서 만약 18살 이상이면 “성인입니다.” 를 출력하고, 만약 18살 미만이라면 “미성년자입니다.”를 출력해야 한다면? 아마도 다음과 같이 코딩을 해야 할 것이다.
// 한글
만약 (나이 >= 18)면 "성인입니다"
만약 (나이 < 18)면 "미성년자입니다"
// 영어
if (age >= 18) "성인입니다"
if (age < 18) "미성년자입니다"
이렇게 특정 조건에 따라서 코드를 실행하는 것을 조건문 이라고 한다. 조건문에는 if문 switch문이 있다. 둘다 특정 조건에 따라서 다른 코드를 실행하는 것이라 생각하면 된다.
if 문
if문은 특정 조건이 참인지 확인하고 그 조건이 참(true)일 경우 특정 코드 블록을 실행한다. 아래 코드에서는 첫번째 조건문인 if문은 참 이기에 실행이되고, 두번째 조건문에서는 거짓 이기에 실행되지 않는다.
public class If1 {
public static void main(String[] args) {
int age = 20; // 사용자 나이
if (age >= 18) { // 참
System.out.println("성인입니다.");
}
if (age < 18) { // 거짓
System.out.println("미성년자입니다.");
}
}
}
else 문
else 문은 if문에서 만족하는 조건이 없을 때 실행하는 코드를 제공한다.
if (condition) {
// 조건이 참일 때 실행되는 코드
} else {
// 만족하는 조건이 없을 때 실행되는 코드
}
아래 코드에서 사용자의 나이가 10이라면, 첫번째 if문을 만족하지 않기에, else문의 “미성년자입니다.” 문구가 출력된다.
public class If2 {
public static void main(String[] args) {
int age = 10; // 사용자의 나이
if (age >= 18) {
System.out.println("성인입니다."); //참일 때 실행
} else {
System.out.println("미성년자입니다.");//만족하는 조건이 없을 때 실행
}
}
}
if문2 - else if
else if 문은 앞선 if문의 조건이 거짓일 때 다음 조건을 검사한다. 만약 앞선 if문이 참이라면 else if 문을 실행하지 않는다. 여러개의 if문을 하나로 묶을때 이렇게 if-else문을 사용할 수 있다. 이렇게 하면 특정 조건이 만족하면 해당 코드를 실행하고 if문 전체를 빠져나온다. 특정 조건을 만족하지 않으면 다음 조건을 검사한다. 여기서 핵심은 순서대로 맞는 조건을 찾아보고 맞는 조건이 있으면 딱1개만 실행이 되는 것이다.
if (condition1) {
// 조건1이 참일 때 실행되는 코드
} else if (condition2) {
// 조건1이 거짓이고, 조건2가 참일 때 실행되는 코드
} else if (condition3) {
// 조건2이 거짓이고, 조건3이 참일 때 실행되는 코드
} else {
// 모든 조건이 거짓일 때 실행되는 코드
}
아래 코드를 보면 더 와닿게 else-if 문을 이해할 수 있다. age = 7인 경우 if(age <= 7) 의 조건이 참이다. “미취학”을 출력하고 전체 if 문 밖으로 나간다. age = 13인 경우 if(age <= 7) 의 조건이 거짓이다. 다음 조건으로 넘어간다. else if(age <= 13) 의 조건이 참이다. “초등학생”을 출력하고 전체 if 문 밖으로 나간다. **age = 50인 경우 if(age <= 7) 의 조건이 거짓이다. 다음 조건으로 넘어간다. else if(age <= 13) 의 조건이 거짓이다. 다음 조건으로 넘어간다.else if(age <= 16) 의 조건이 거짓이다. 다음 조건으로 넘어간다. else if(age <= 19) 의 조건이 거짓이다. 다음 조건으로 넘어간다. else 만족하는 조건 없이 else 까지 왔다. else 에 있는 “성인”을 출력하고 전체 if 문 밖으로 나간다.
public class If4 {
public static void main(String[] args) {
int age = 14;
if(age <= 7) { //~7: 미취학
System.out.println("미취학");
} else if(age <= 13) { //8~13: 초등학생
System.out.println("초등학생");
} else if(age <= 16) { //14~16: 중학생
System.out.println("중학생");
} else if(age <= 19) { //17~19: 고등학생
System.out.println("고등학생");
} else { //20~: 성인
System.out.println("성인");
}
}
}
if문3 - if 문과 else if문
if문에 else-if문을 함께 사용하는 것은 서로 연관된 조건일 때 사용한다. 그런데 서로 관련이 없는 독립 조건이면, else-if를 사용하지 않고 if문을 각각 따로 사용해야 한다.
아래와 같은 상황에서 if문을 독립적으로 사용한다. (else-if X)
if문을 독립적으로 적용하는 상황
온라인 쇼핑몰의 할인 시스템을 개발해야 한다. 한 사용자가 어떤 상품을 구매할 때, 다양한 할인 조건에 따라 총 할인 금액이 달라질 수 있다. 각각의 할인 조건은 다음과 같다. 아이템 가격이 10000원 이상일 때, 1000원 할인 나이가 10살 이하일 때 1000원 할인 이 할인 시스템의 핵심은 한 사용자가 동시에 여러 할인을 받을 수 있다는 점이다. 예를 들어, 10000원짜리 아이템을 구매할 때 1000원 할인을 받고, 동시에 나이가 10살 이하이면 추가로 1000원 더 할인을 받는다. 그래서 총 2000원 까지 할인을 받을 수 있다.
public class If5 {
public static void main(String[] args) {
int price = 10000;// 아이템 가격
int age = 10;//나이
int discount = 0;
if (price >= 10000) {
discount = discount + 1000;
System.out.println("10000원 이상 구매, 1000원 할인");
}
if (age <= 10) {
discount = discount + 1000;
System.out.println("어린이 1000원 할인");
}
System.out.println("총 할인 금액: " + discount + "원");
}
}
if문 - switch
switch 문은 앞서 배운 if문을 조금 더 편리하게 사용할 수 있는 기능이다. 참고로 if문은 비교연산자를 사용할 수 있지만, switch문은 단순히 값이 같은지만 비교할 수 있다. switch문은 조건식에 해딩하는 특정 값으로 실행할 코드를 선택한다. 조건식의 결과 값이 어떤 case 의 값과 일치하면 해당 case 의 코드를 실행한다. break 문은 현재 실행 중인 코드를 끝내고 switch 문을 빠져나가게 하는 역할을 한다. 만약 break 문이 없으면, 일치하는 case 이후의 모든 case 코드들이 순서대로 실행된다. default 는 조건식의 결과값이 모든 case 의 값과 일치하지 않을 때 실행된다. if 문의 else 와 같다. default 구문은 선택이다. if , else-if , else 구조와 동일하다.
public class Main {
public static void main(String[] args) {
switch (조건식) {
case value1:
// 조건식의 결과 값이 value1일 때 실행되는 코드
break;
case value2:
// 조건식의 결과 값이 value2일 때 실행되는 코드
break;
default:
// 조건식의 결과 값이 위의 어떤 값에도 해당하지 않을 때 실행되는 코드
}
}
}
실제 switch 문을 사용한 예제 코드를 살펴보자 변수 grade 값에 따라 실행되는 case문이 달라진다.
public class Switch2 {
public static void main(String[] args) {
//grade 1:1000, 2:2000, 3:3000, 나머지: 500
int grade = 2;
int coupon;
switch (grade) {
case 1:
coupon = 1000;
break;
case 2:
coupon = 2000;
break;
case 3:
coupon = 3000;
break;
default:
coupon = 500;
}
System.out.println("발급받은 쿠폰 " + coupon);
}
}
case문에 break 문이 없으면?
만약 break문이 없으면 어떻게 되는지 확인하기 위해 다음과 같이 조건을 변경해보자. 2등급과 3등급이 같이 3000원 쿠폰을 발급한다고 가정해보겠다. case2에는 break문이 없다. 그러면 중단하지 않고, 바로 다음에 있는 case3의 코드를 실행한다. 여기서 coupon = 3000을 수행하고, break문을 만나서 switch문 밖으로 빠져나간다. 발급받은 쿠폰 3000이 출력된다.
public class Switch3 {
public static void main(String[] args) {
//grade 1:1000, 2:3000(변경), 3:3000, 나머지: 500
int grade = 2;
int coupon;
switch (grade) {
case 1:
coupon = 1000;
break;
case 2:
case 3:
coupon = 3000;
break;
default:
coupon = 500;
break;
}
System.out.println("발급받은 쿠폰 " + coupon);
}
}
if문 - 삼항 연산자
if문을 사용할 때 다음과 같이 단순히 참과 거짓에 따라 특정 값을 구하는 경우가 있다. 삼항 연산자 없이 if 문만 사용해도 된다. 하지만 단순히 참과 거짓에 따라서 특정 값을 구하는 삼항 연산자를 사용하면 if 문 보다 간결한 코드를 작성할 수 있다
public class CondOp2 {
public static void main(String[] args) {
int age = 18;
String status = (age >= 18) ? "성인" : "미성년자"; // if문을 사용할 때 보다 간결한 코드 구성 가능
System.out.println("age = " + age + " status = " + status);
}
}
-
[java] 연산자
intro : java 연산자에 대한 개념을 알아보자.
연산자
자바에는 산술연산자, 증감 연산자, 비교 연산자, 논리 연산자, 대입 연산자, 삼항 연산자 등과 같은 다양한 연산자가 존재한다. 기본적으로 연산자와 피연산자의 개념은 다음과 같다.
3 + 4 // 연산자(operator): 연산 기호 - `+`, `-`
a + b // 피연산자(operand): 연산 대상 - `3`, `4`, `a`, `b`
산술 연산자
산술 연산자는 주로 숫자를 계산하는 데 사용된다. 우리가 이미 잘 알고 있는 수학 연산을 수행한다. 산술연산자의 종류는 더하기 (+) 빼기 (-) 곱하기(*) 나누기(/) 나머지(%) 가 있다.
public class Operator1 {
public static void main(String[] args) {
// 변수 초기화
int a = 5;
int b = 2;
// 덧셈
int sum = a + b;
System.out.println("a + b = " + sum); // 출력: a + b = 7
// 뺄셈
int diff = a - b;
System.out.println("a - b = " + diff); // 출력: a - b = 3
// 곱셈
int multi = a * b;
System.out.println("a * b = " + multi); // 출력: a * b = 10
// 나눗셈
int div = a / b;
System.out.println("a / b = " + div); // 출력: a / b = 2
// 나머지
int mod = a % b;
System.out.println("a % b = " + mod); // 출력: a % b = 1
}
}
주의! 0 으로 나누기
10 / 0 과 같이 숫자는 0으로 나눌 수 없다. 이 경우 프로그램에 다음과 같은 오류가 발생한다. (Exception in thread "main" java.lang.ArithmeticException: / by zero)
문자열 더하기
자바는 특별하게도 문자열에도 + 연산자를 사용할 수 있다. 문자열에 + 연산자를 사용하면 두 문자를 연결 할 수 있다.
public class Operator2 {
public static void main(String[] args) {
//문자열과 문자열 더하기1
String result1 = "hello " + "world";
System.out.println(result1);
//문자열과 문자열 더하기2
String s1 = "string1";
String s2 = "string2";
String result2 = s1 + s2;
System.out.println(result2);
//문자열과 숫자 더하기1
String result3 = "a + b = " + 10;
System.out.println(result3);
//문자열과 숫자 더하기2
int num = 20;
String str = "a + b = ";
String result4 = str + num;
System.out.println(result4);
}
}
주의! 문자열 + 숫자
자바에서 문자와 숫자를 더하면 숫자를 문자열로 변경한 다음에 서로 더한다. 아래 코드의 결과는 20을 예상할 수도 있지만, 실제로는 1010 값이 출력된다. 쉽게 얘기해서 문자열과 더하는 모든 것들은 전부 문자열이 된다.
public class Main {
public static void main(String[] args) {
//문자열과 문자열 더하기1
String result1 = "hello " + "world";
System.out.println(result1);
String str = "10";
int a = 10;
System.out.println(str + a); // 1010 출력
}
}
연산자 우선순위
자바는 다음과 같은 연산자 우선순위가 있다. 높은 것에서 낮은 순으로 적용된다. 처음에 나오는 괄호가 우선순위가 가장 높고, 대입 연산자가 우선순위가 가장 낮다.
우선순위
연산자 유형
연산자
1
괄호
()
2
단항 연산자
++,--,!,~,new,(type)
3
산술 연산자
*, /, %, +, -
4
Shift 연산자
<<, >>, >>>
5
비교 연산자
<,<=,>,>=,instanceof
6
등식 연산자
==, !=
7
비트 연산자
&, ^, |
8
논리 연산자
&&, ||
9
삼항 연산자
? :
10
대입 연산자
=, +=, -=, *=, /=, %= 등
잘 모르는 ~ 연산자
자바에서 ~ 연산자는 비트 반전 연산자(bitwise NOT)입니다. 이 연산자는 피연산자의 모든 비트를 반전시키는 데 사용됩니다. 즉, 0을 1로, 1을 0으로 바꿉니다. 이걸 응용하면, 음수를 비트로 표현하는 방법에 대해서도 알 수 있습니다. -5를 표현하는 방법은 5의 보수 즉 ~5 을 한뒤 +1 을 해주는 것으로 음수를 2진법으로 표현할 수 있습니다.
public class Main {
public static void main(String[] args) {
int a = 5; // 이진수: 00000000 00000000 00000000 00000101
int result = ~a;
System.out.println(result); // 출력: -6
}
}
잘 모르는 Shift 연산자
1. << 왼쪽 쉬프트 연산자
비트를 왼쪽으로 이동시키고, 오른쪽에 0을 채웁니다.
예시: a << n은 a를 왼쪽으로 n비트만큼 이동시킵니다.
int a = 1; // 이진수: 00000001
int result = a << 1; // 왼쪽으로 1비트 이동
System.out.println(result); // 출력: 2 (이진수: 00000010)
2. >> 오른쪽 쉬프트 연산자
비트를 오른쪽으로 이동시키고, 왼쪽에 부호 비트를 채웁니다. (부호 비트는 양수인 경우 0, 음수인 경우 1)
a >> n은 a를 오른쪽으로 n비트만큼 이동시키며, 부호 비트(1 또는 0)로 채웁니다.
int a = 4; // 이진수: 00000100
int result = a >> 1; // 오른쪽으로 1비트 이동
System.out.println(result); // 출력: 2 (이진수: 00000010)
3. >>> 무조건 오른쪽 쉬프트 연산자 (<<< 무조건 왼쪽 쉬프트 연산자는 없습니다.)
비트를 오른쪽으로 이동시키고, 왼쪽에 항상 0을 채웁니다. 부호 비트와 상관없이 0으로 채워집니다.
예시: a >>> n은 a를 오른쪽으로 n비트만큼 이동시키며, 빈 자리는 항상 0으로 채웁니다.
int a = -5; // 이진수: 11111111111111111111111111111011
int result = a >>> 1; // 오른쪽으로 1비트 이동
System.out.println(result); // 출력: 2147483642
잘 모르는 비트 연산자
1. & 연산자
&는 비트 단위 AND 연산자로, 두 비트가 모두 1일 때만 결과가 1이 됩니다. 그 외의 경우에는 결과가 0이 됩니다.
public class Main {
public static void main(String[] args) {
int a = 5; // 이진수: 0101
int b = 3; // 이진수: 0011
int result = a & b;
System.out.println(result); // 출력: 1
}
}
2. ^ (비트 XOR) 연산자
^는 비트 단위 XOR 연산자로, 두 비트가 서로 다를 때만 결과가 1이 됩니다. 같은 비트는 0이 됩니다.
public class Main {
public static void main(String[] args) {
int a = 5; // 이진수: 0101
int b = 3; // 이진수: 0011
int result = a ^ b;
System.out.println(result); // 출력: 6
}
}
3. | (비트 OR) 연산자
|는 비트 단위 OR 연산자로, 두 비트 중 하나라도 1이면 결과가 1이 됩니다. 두 비트가 모두 0일 때만 결과가 0입니다.
public class Main {
public static void main(String[] args) {
int a = 5; // 이진수: 0101
int b = 3; // 이진수: 0011
int result = a | b;
System.out.println(result); // 출력: 7
}
}
증감 연산자
증가 및 감소 연산자를 줄여서 증감 연산자라 한다. 증감 연산자는 ++ 와 -- 로 표현되며, 이들은 변수의 값을 1만큼 증가시키거나 감소시킨다. 프로그래밍에서는 값을 1씩 증가하거나 1씩 감소할 때가 아주 많기 때문에 이런 편의 기능을 제공한다.
public class OperatorAdd1 {
public static void main(String[] args) {
int a = 0;
a = a + 1;
System.out.println("a = " + a); //1
a = a + 1;
System.out.println("a = " + a); //2
//증감 연산자
++a; //a = a + 1
System.out.println("a = " + a); //3
++a; //a = a + 1
System.out.println("a = " + a); //4
}
}
전위, 후위 증감연산자
증감 연산자는 피연산자 앞에 두거나 뒤에 둘 수 있으며, 연산자의 위치에 따라 연산이 수행되는 시점이 달라진다. ++a : 증감 연산자를 피연산자 앞에 둘 수 있다. 이것을 앞에 있다고 해서 전위(Prefix) 증감 연산자라 한다. a++ : 증감 연산자를 피연산자 뒤에 둘 수 있다. 이것을 뒤에 있다고 해서 후위(Postfix) 증감 연산자라 한다.
public class OperatorAdd2 {
public static void main(String[] args) {
// 전위 증감 연산자 사용 예
int a = 1;
int b = 0;
b = ++a; // a의 값을 먼저 증가시키고, 그 결과를 b에 대입
System.out.println("a = " + a + ", b = " + b); // 결과: a = 2, b = 2
// 후위 증감 연산자 사용 예
a = 1; // a 값을 다시 1로 지정
b = 0; // b 값을 다시 0으로 지정
b = a++; // a의 현재 값을 b에 먼저 대입하고, 그 후 a 값을 증가시킴
System.out.println("a = " + a + ", b = " + b); // 결과: a = 2, b = 1
}
}
비교 연산자
비교 연산자는 두 값을 비교하는 데 사용한다. 비교 연산자는 주로 뒤에서 설명하는 조건문과 함께 사용한다. 비교 연산자를 사용하면 참(true) 또는 거짓(false)이라는 결과가 나온다. 참 거짓은 boolean 형을 사용한다. 여기서 주의할 점은 = 와 == (= x2)이 다르다는 점이다.= : 대입 연산자, 변수에 값을 대입한다. == : 동등한지 확인하는 비교 연산자
public class Comp1 {
public static void main(String[] args) {
int a = 2;
int b = 3;
System.out.println(a == b); // false, a와 b는 같지 않다
System.out.println(a != b); // true, a와 b는 다르다
System.out.println(a > b); // false, a는 b보다 크지 않다
System.out.println(a < b); // true, a는 b보다 작다
System.out.println(a >= b); // false, a는 b보다 크거나 같지 않다
System.out.println(a <= b); // true, a는 b보다 작거나 같다
//결과를 boolean 변수에 담기
boolean result = a == b; //a == b: false
System.out.println(result); //false
}
}
문자열 비교
문자열 비교는 객체이기 때문에 == 으로 비교할수 없다. 문자열 String 클래스가 제공하는 equals 메소드를 통해 비교해야한다.
논리 연산자
논리 연산자는 boolean 형인 true , false 를 비교하는데 사용한다. && (그리고) : 두 피연산자가 모두 참이면 참을 반환, 둘중 하나라도 거짓이면 거짓을 반환 || (또는) : 두 피연산자 중 하나라도 참이면 참을 반환, 둘다 거짓이면 거짓을 반환 ! (부정) : 피연산자의 논리적 부정을 반환. 즉, 참이면 거짓을, 거짓이면 참을 반환
public class Logical1 {
public static void main(String[] args) {
System.out.println("&&: AND 연산");
System.out.println(true && true); //true
System.out.println(true && false);//false
System.out.println(false && false);//false
System.out.println("||: OR 연산");
System.out.println(true || true); //true
System.out.println(true || false);//true
System.out.println(false || false);//false
System.out.println("! 연산");
System.out.println(!true); //false
System.out.println(!false); //true
System.out.println("변수 활용");
boolean a = true;
boolean b = false;
System.out.println(a && b); // false
System.out.println(a || b); // true
System.out.println(!a); // false
System.out.println(!b); // true
}
}
대입 연산자
대입 연산자(=)는 값을 변수에 할당하는 연산자다. 이 연산자를 사용하면 변수에 값을 할당할 수 있다. 예를 들어, int a = 1 는 a 라는 변수에 1 이라는 값을 할당한다. 산술 연산자와 대입 연산자를 한번에 축약해서 사용할 수 있는데, 이것을 축약(복합) 대입 연산자라 한다. (연산자 종류: +=,-=,*=,/=,%=)
public class Assign1 {
public static void main(String[] args) {
int a = 5; // 5
a += 3; // 8 (5 + 3): a = a + 3
a -= 2; // 6 (8 - 2): a = a - 2
a *= 4; // 24 (6 * 4): a = a * 4
a /= 3; // 8 (24 / 3): a = a / 3
a %= 5; // 3 (8 % 5) : a = a % 5
System.out.println(a);
}
}
-
[java] 변수
intro : java 변수의 대한 개념을 알아보자.
변수 시작
변수란 무엇일까 ?
변수는 이름 그대로 변할 수 있는 값을 뜻한다. 숫자 정수를 보관할 수 있는 이름이 a라는 데이터 저장소를 만든다. 이것을 변수라고 한다. 이렇게 변수를 만드는 것을 변수 선언이라고 한다. 이제 변수 a에는 숫자 정수를 보관 할 수 있다. 숫자 정수 뿐만 아니라 문자, 소수와 같이 다양한 종류 값을 저장할 수 있는 변수들이 있다.
public class Main {
public static void main(String[] args) {
int a; //변수 선언
a = 10; //변수 a에 10 저장 및 초기화
System.out.println(a);
System.out.println(a);
System.out.println(a);
}
}
자바에서 = 은 오른쪽에 있는 값을 왼쪽으로 저장한다는 뜻이다. 수학에서 이야기하는 두 값이 같다 (equal) 와는 다른뜻이다. 숫자를 보관할 수 있는 데이터 저장소인 변수 a에 값 10을 저장한다. 이처럼 선언한 변수에 처음으로 값을 대입해서 저장하는 것을 변수 초기화 라고 한다.
변수 값 변경
변수는 이름 그대로 변할 수 있는 수이다. 쉽게 이야기해서 변수 a에 저장된 값을 언제든지 바꿀 수 있다는 뜼이다. 이번에는 중간에 변수의 값을 변경해보자.
public class Main {
public static void main(String[] args) {
int a; //변수 선언
a = 10; //변수 초기화: a(10)
System.out.println(a); //10 출력
a = 50; //변수 값 변경: a(10 -> 50)
System.out.println(a); //50 출력
}
}
변수 선언과 초기화
변수 선언
변수를 선언하면 컴퓨터의 메모리 공간을 확보해서 그곳에 데이터를 저장할 수 있다. 그리고 변수의 이름을 통해서 해당 메모리 공간에 접근 할 수 잇다. 정리하자면, 데이터를 보관할 수 있는 공간을 만들고, 그곳에 이름을 부여한다 라고 정리 할 수 있다. 변수는 다음과 같이 하나씩 선언할 수 있고, 한번에 여러 변수를 선언 할 수도 있다.
public class Main {
public static void main(String[] args) {
int a;
int b;
int c, d;
}
}
변수 초기화
변수를 선언하고, 선언한 변수에 처음으로 값을 저장하는 것을 변수 초기화 라고 한다. 변수를 초기화 하지 않고 사용하면 오류가 발생한다. 지역변수는 꼭 개발자가 직접 초기화를 해주어야한다. (나중에 배울 클래스 변수와 인스턴스 변수는 자바가 자동으로 초기화를 진행해준다)
public class Main {
public static void main(String[] args) {
//1. 변수 선언, 초기화 각각 따로, 지역변수이기 때문에 반드시 초기화 해주어야 함
int a;
a = 1;
System.out.println(a);
int b = 2; //2. 변수 선언과 초기화를 한번에
System.out.println(b);
int c = 3, d = 4; //3. 여러 변수 선언과 초기화를 한번에
System.out.println(c);
System.out.println(d);
}
}
변수 타입1
변수는 데이터를 다루는 종류에 따라 다양한 형식이 존재한다. 이러한 형식으로는 타입이라고 하고, 우리말로는 형식 또는 형 이라고 한다. 예를들어서 int 타입, int 형, int 형식 등으로 부른다. int는 정수를 다루며, double은 실수를 다룬다. boolean 불리언 타입은 true false 값만 사용할 수 있으며 거짓 참만 판단하는 곳에서 사용한다. char는 문자 하나를 다룰때 사용하며 작은 따옴표를 사용해서 감싸야한다. String은 문자열을 다루며 큰 따옴표를 사용하여 감싸야한다. (String은 첫글자가 대문자로 시작하는 특별한 타입이다.)
public class Main {
public static void main(String[] args) {
int a = 100; //정수
double b = 10.5; //실수
boolean c = true; //불리언(boolean) true, false 입력 가능
char d = 'A'; //문자 하나
String e = "Hello Java"; //문자열, 문자열을 다루기 위한 특별한 타입
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(e);
}
}
리터럴
코드에서 개발자가 직접적은 100, 10.5, true, 'A', "Hello Java"와 같은 고정된 값을 프로그래밍 용어 리터럴 이라고 한다. 변수의 값은 변할 수 있지만 리터럴은 개발자가 직접 입력한 고정된 값이다. 따라서 리터럴 자체는 변하지 않는다.
public class Main {
public static void main(String[] args) {
int a = 100; //정수 리터럴
double b = 10.5; //실수 리터럴
boolean c = true; //불리언 리터럴
char d = 'A'; //문자 하나 리터럴
String e = "Hello Java"; //문자열 리터럴
}
}
변수 타입2
메모리를 적게 사용하면 적은 숫자를 표현 할 수 있고, 메모리를 많이 사용하면 큰 숫자를 표현할 수 있다. 변수를 선언하면 표현범위에 따라 메모리 공간을 차지한다. 그래서 필요에 맞도록 다양한 타입을 제공한다.
정수형
byte : -128 ~ 127 (1byte, 2⁸)
short : -32,768 ~ 32,767 (2byte, 2¹⁶)
int : -2,147,483,648 ~ 2,147,483,647 (약 20억) (4byte, 2³²)
long : -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 (8byte, 2⁶⁴)
실수형
float : 대략 -3.4E38 ~ 3.4E38, 7자리 정밀도 (4byte, 2³²)
double : 대략 -1.7E308 ~ 1.7E308, 15자리 정밀도 (8byte, 2⁶⁴)
기타
boolean : true , false (1byte)
char : 문자 하나(2byte)
리터럴 타입 지정
정수 리터럴은 int을 기본으로 사용한다. 따라서 int 범위까지 표현 할 수 있다. 숫자가 int 범위인 약 20억을 넘어가면 L을 붙여서 정수 리터럴을 long으로 변경해야 한다. 실수 리터럴은 기본이 double 형을 사용한다. float형을 사용하려면 f을 붙여서 float 형으로 지정해야 한다.
자주 사용하는 변수 타입
정수 - int , long : 자바는 정수에 기본으로 int 를 사용한다. 만약 20억이 넘을 것 같으면 long 을 쓰면 된다. 파일을 다룰 때는 byte 를 사용한다.
실수 - double : 실수는 고민하지 말고 double 을 쓰면 된다.
불린형 - boolean : true , false 참 거짓을 표현한다. 이후 조건문에서 자주 사용된다.
문자열 - String : 문자를 다룰 때는 문자 하나든 문자열이든 모두 String 을 사용하는 것이 편리하다.
변수 범위를 구하는 공식
2^(n-1) ~ 2^(n-1) -1
char 타입은 예외로 0 ~ 2^n -1
변수 명명 규칙
자바에서 변수의 이름을 짓는데는 규칙과 관례가 있다. 규칙은 필수이다. 규칙을 지키지 않으면 컴파일 오류가 발생한다. 관례는 필수가 아니지만 전세계 개발자가 해당 관례를 따르기 때문에 사실상 규칙이라고 생각해도 된다.
규칙
변수 이름은 숫자로 시작할 수 없다. 그러나 숫자를 이름에 포함하는 것은 가능하다. 이름에는 공백이 들어갈 수 없다. 자바의 예약어를 변수 이름으로 사용할 수 없다. 변수 이름에는 영문자(a-z , A-Z), 숫자(0-9), 달러 기호($) 또는 밑줄(_)만 사용할 수 있다.
관례
소문자로 시작하는 낙타 표기법. 변수이름은 소문자로 시작하는 것이 일반적이다. 여러 단어로 이루어진 변수 이름의 경우, 첫 번째 단어는 소문자로 시작하고 그 이후의 각 단어는 대문자로 시작하는 낙타 표기법을 사용한다.
변수 명명 규칙 정리
클래스는 대문자로 시작, 나머지는 소문자로 시작
자바에서 클래스는 이름의 첫 글자는 대문자로 시작한다. 그리고 나머지는 모두 첫 글자를 소문자로 시작한다. 여기에 예외가 딱 2가지 있는데, 상수는 모두 대문자를 사용하고 언더바로 구분한다. 패키지는 모두 소문자를 사용한다.
Touch background to close