변수
변수초기화
변수를 선언하고, 선언한 변수에 처음으로 값을 저장하는 것을 변수 초기화라고 한다. 자바는 변수를 초기화 하도록 강제한다.(초기화 하지 않으면 에러가 발생) -> 지역변수
String
문자열을 다룬다. 큰따옴표를 사용해야 한다. 예) "hello java"
- String은 첫글자가 대문자로 시작하는 특별한 타입이다.
리터럴
코드에서 개발자가 직접 적은 100, 10.5, true, 'A', "Hello Java"와 같은 고정된 값을 프로그래밍 용어로 리터럴(literal)이라 한다.
변수의 값은 변할 수 있지만 리터럴은 개발자가 직접 입력한 고정된 값이다. 따라서 리터럴 자체는 변하지 않는다.
변수 타입 정리
아래 타입은 실무에서 거의 사용하지 않는다.
- byte : 표현 길이가 너무 작다. 또 자바는 기본으로 4byte(int)를 효율적으로 계산하도록 설계되어 있다. int를 사용하자
- byte 타입을 직접 선언하고 여기에 숫자값을 대입해서 계산하는 일은 거의 없다
- 대신에 파일을 바이트 단위로 다루기 때문에 파일 전송, 파일 복사 등에 주로 사용된다
- short : 표현길이가 너무 작다. 또 자바는 기본으로 4byte(int)를 효율적으로 계산하도록 설계되어 있다. int 사용하자.
- float : 표현 길이와 정밀도가 낮다. 실수형은 double을 사용하자.
- char : 문자 하나를 표현하는 일은 거의 없다. 문자하나를 표현할 때도 문자열을 사용할 수 있다.
- 예를 들어 String a = "b"와 같이 사용하면 된다.
실무에서 자주 사용하는 타입은 아래와 같다.
- 정수 int, long : 자바는 정수에 기본으로 int를 사용한다. 만약 20억이 넘을 것 같으면 long을 쓰면 된다.
- 파일을 다룰 때는 byte를 사용한다.
- 숫자가 어느정도 크다고 생각되면 뒤에 'L'을 붙이자.
long num1 = 10000000000L;
- 실수 double : 실수는 고민하지 말고 double을 쓰면된다.
- 불린형 boolean : true, false 참 거짓말을 표현한다. 이후 조건문에서 자주 사용된다.
- 문자열 String : 문자를 다룰 때는 문자 하나든 문자열이든 모두 String을 사용하는 것이 편리하다.
변수 명명 규칙
자바에서 변수의 이름을 짓는데는 규칙과 관례가 있다. 규칙은 필수이다. 규칙을 지키지 않으면 컴파일 오류가 발생한다. 관례는 필수가 아니지만 전세계 개발자가 해당 관례를 따르기 때문에 사실상 규칙이라고 생각해도 된다.
규칙
- 변수 이름은 숫자로 시작할 수 없다.(ex. 1num, 1st)
- 그러나 숫자를 이름에 포함하는 것은 가능하다. (ex. myVar1, num1)
- 이름에는 공백이 들어갈 수 없다.
- 자바의 예약어를 변수 이름으로 사용할 수 없다.
- 변수 이름에는 영문자(a-z, A-Z), 숫자(0~9),달러기호($) 또는 밑줄(_)만 사용할 수 있다.
관례
- 소문자로 시작하는 낙타 표기법
- 변수 이름은 소문자로 시작하는 것이 일반적이다. 여러 단어로 이루어진 변수 이름의 경우, 첫번째 단어는 소문자로 시작하고 그 이후의 단어는 대문자로 시작하는 낙타 표기법(camel case)를 사용한다. (ex. orderDetal, myAccount)
- 클래스는 대문자로 시작, 나머지는 소문자로 시작
- 자바에서 클래스 이름의 첫 글자는 대문자로 시작한다. 그리고 나머지 모두 첫 글자를 소문자로 시작한다.
- 클래스 : Person, OrderDetail
- 변수를 포함한 나머지 : firstName, userAccount
- 여기에 딱 예외가 2개 있다.
- 상수는 모두 대문자를 사용하고 언더바로 구분한다. (ex. USER_LIMIT )
- 패키지는 모두 소문자를 사용한다.(ex. org.spring.boot )
- 자바에서 클래스 이름의 첫 글자는 대문자로 시작한다. 그리고 나머지 모두 첫 글자를 소문자로 시작한다.
참고 : 변수 이름은 의미있고, 그 용도를 명확하게 설명해야 한다.
- a,b : 이런 변수는 용도를 설명하지 않는다.
- studentCount, maxScore, userAccount, orderCount : 용도를 명확하게 설명한다.
연산자
문자열 더하기
아래 식은 문자열과 숫자를 더한다. 자바에서 문자와 숫자를 더하면 숫자를 문자열로 변경한 다음에 서로 더한다. 쉽게 말해서 문자열에 더하는 것은 다 문자열이 된다.
String result3 = "a + b = "+10;
연산자 우선순위 정리
- 연산자 우선순위는 상식선에서 생각하고, 애매하면 괄호를 사용하자
- 누구나 코드를 보고 쉽고 명확하게 이해할 수 있어야 한다. 개발자들이 연산자 우선순위를 외우고 개발하는 것이 아니다! 복잡하면 명확하게 괄호를 넣어라!
- 개발에서 가장 중요한 것은 단순함과 명확함이다! 애매하거나 복잡하면 안된다.
비교연산자 문자열비교
문자열이 같은지 비교할 때는 ==이 아니라 .equals() 메서드를 사용해야 한다. ==를 사용하면 성공할 때도 있지만 실패할 때도 있다. 지금은 이 부분을 이해하기 어려우므로 지금은 단순히 문자열의 비교는 .equals() 메서드를 사용해야 한다 정도로 알고 있자.
String str1 = "문자열1";
String str2 = "문자열2";
boolean result1 = "hello".equals("hello");
boolean result2 = str1.equals("문자열1");
boolean result3 = str1.equals(str2);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
System.out.println("hello"=="hello");
반복문(while vs for)
정해진 횟수만큼 반복을 수행해야 하면 for문을 사용
그렇지 않으면 while문 사용 항상 정답은 아님.
스코프
스코프존재이유
package scope;
public class Scope1 {
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);
}
}
- 비효율적인 메모리 사용 : temp는 if코드 블록에서만 필요한데 main()이 종료될때까지 메모리에 유지된다. 따라서 불필요한 메모리가 낭비된다. -> if문안에 temp선언하면 효율적인 메모리 사용 가능
- 코드 복잡성 증가 : 좋은 코드는 단순한 코드이다. temp는 if코드 블록에서만 필요하고 여기서만 사용하면 된다. 만약 if블록안에 temp를 선언했다면 if가 끝나고 나면 temp를 전혀 생각할 필요가 없다. 머리속에서 생각할 변수를 하나 줄일 수 있다. 누군가 이 코드를 유지보수 할 때 m은 물론이고 temp까지 계속 신경써야 한다.
while vs for문 - 스코프관점
while
package loop;
public class While1 {
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
package loop;
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);
}
//..아래에 더 많은 코드들이 있다고 가정
}
}
- while문의 경우 변수 i의 스코프가 main() 메서드 전체가 된다. 반면에 for문의 경우 변수 i의 스코프가 for문 안으로 한정된다.
- 따라서 변수 i와 같이 for문안에서만 사용되는 카운터 변수가 있다면 while문 보다는 for문을 사용해서 스코프의 범위를 제한하는 것이 메모리 사용과 유지보수 관점에서 더 좋다.
정리
- 변수는 꼭 필요한 범위로 한정해서 사용하는 것이 좋다. 변수의 스코프는 꼭 필요한 곳으로 한정해서 사용하자. 메모리를 효율적으로 사용하고더 유지보수하기 좋은 코드를 만들 수 있다.
- 좋은 프로그램은 무한한 자유가 있는 프로그램이 아니라 적절한 제약이 있는 프로그램이다.
형변환
자바에서 숫자를 표현할 수 있는 범위는 다음과 같다.
int < long < double
int -> long -> double
작은 범위에서 큰 범위로는 대입할 수 있다. ( 이것을 묵시적 형변환 또는 자동 형변환이라 한다.)
큰 범위에서 작은 범위의 대입은 다음과 같은 문제가 발생할 수 있다. 이때는 명시적 형변환을 사용해야 한다.
- 소수점 버림
- 오버플로우 ( long -> int로 변경한경우 전혀 다른 숫자가 표현된다. 중요한 것은 오버플로우가 발생하는 것 자체가 문제라는 점이다. 오버플로우가 발생했을 때 결과가 어떻게 되는지 계산하는데 시간을 낭비하면 안된다! 오버플로우 자체가 발생하지 않도록 막아야 한다. 대입하는 변수(intValue)의 타입을 int -> long으로 변경해서 사이즈를 늘리면 해결)
캐스팅 : 영어단어 "cast"에서 유래되었다. "cast"는 금속이나 다른 물질을 녹여서 특정한 형태나 모양으로 만드는 과정을 의미한다.
자바에서 계산은 다음 2가지를 기억하자
- 같은 타입끼리의 계산은 같은 타입의 결과를 낸다.
- int + int는 int를, double + double은 double의 결과가 나온다.
- 서로 다른 타입의 계산은 큰 범위로 자동 형변환이 일어난다.
- int + long은 long + long으로 자동 형변환이 일어난다.
- int + double은 double + double로 자동 형변환이 일언난다.
연산과 형변환
- 같은 타입은 같은 결과를 낸다
- 서로 다른 타입의 계산은 큰 범위로 자동 형변환이 일어난다.
Scanner
System.out을 통해서 출력을 했듯이, Systems.in을 통해서 사용자의 입력을 받을 수 있다. 그런데 자바가 제공하는 System.in을 통해서 사용자 입력을 받으려면 여러 과정을 거쳐야해서 복잡하고 어렵다.
자바는 이런 문제를 해결하기 위해 Scanner라는 클래스를 제공한다.
package scanner;
import java.util.Scanner;
public class Scanner1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("문자열을 입력하세요:");
String str = scanner.nextLine();
System.out.println("입력한 문자열: "+str);
System.out.print("정수를 입력하세요:");
int intValue = scanner.nextInt();
System.out.println("입력한 정수: "+intValue);
System.out.print("실수를 입력하세요:");
double doubleValue = scanner.nextDouble();
System.out.print("입력한 실수: "+doubleValue);
}
}
- scanner.nextLine() : 엔터(\n)을 입력할 때까지 문자를 가져온다.
- scanner.nextInt() : 입력을 int형으로 가져온다. 정수 입력에 사용한다.
- scanner.nextDouble() : 입력을 double형으로 가져온다. 실수 입력에 사용한다.
주의해야 할점은 입력받는 타입과 입력하는 타입이 다르면 오류가 발생한다.
정수값을 입력받고 문자를 입력받을때 10\n 처럼 공백값이 들어갈 수 있다. 그래서 input.nextLine()을 사용해서 값을 비워준다.
배열
배열선언과 생성
int[] students; // 1. 배열 변수 선언
students = new int[5]; // 2. 배열 생성
- 배열 변수 선언
- 배열을 사용하려면 int[] students;와 같이 배열 변수를 선언해야 한다.
- 배열 변수를 선언한다고 해서 아직 사용할 수 있는 배열이 만들어진 것은 아니다.
- int a 에는 정수를, double b 에는 실수를 담을 수 있다. int[] students와 같은 배열 변수에는 배열을 담을 수 있다.( 배열 변수에는 10,20같은 값이 아니라 배열이라는 것을 담을 수 있다)
- 배열 생성
- 배열을 사용하려면 배열을 생성해야 한다.
- new int[5] 라고 입력하면 5개의 int형 변수가 만들어진다.
- new는 새로 생성한다는 뜻이고, int[5]는 int 형 변수 5개라는 뜻이다.
- 배열 초기화 : 자바는 배열을 생성할 때 그 내부값을 자동으로 초기화한다.
- 배열 참조값 보관
- new int[5]로 배열을 생성하면 배열의 크기만큼 메모리를 확보한다.(int형 5개 -> 20byte)
- x001은 참조값이다.
- 앞서 선언한 배열 변수인 int[] students에 생성된 배열의 참조값(x001)을 보관한다.
- int[] students 변수는 new int [5]로 생성한 배열의 참조값을 가지고 있다.
참조값을 확인하고 싶다면 배열의 변수를 출력해보면 된다.
System.out.println(students); // [I@6acbcfc0 @앞의 [I는 int형 배열을 뜻한다. @뒤에 16진수는 참조값을 뜻한다.
기본형 vs 참조형
자바의 변수 데이터 타입을 가장 크게보면 기본형과 참조형으로 분류할 수 있다.
- 기본형(Primitive Type) : int, long, double, boolean 처럼 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입
- 참조형(Reference Type) : int[] students와 같이 데이터에 접근하기 위한 참조(주소)를 저장하는 데이터타입
배열은 왜 참조형을 사용할까? 단순히 그 안에 값을 넣고 사용하면 되는 것 아닐까? 기본형은 모두 사이즈가 명확하게 정해져있다.
int i; // 4byte
long l; // 8byte
double d; //8byte
그런데 배열은 동적으로 사이즈를 변경할 수 있다.
int size = 10000; // 사용자가 입력한 값을 넣었다고 가정
new int[size]; // 이 코드가 실행되는 시점에 배열의 크기가 정해진다.
기본형은 선언과 동시에 크기가 정해진다. 따라서 크기를 동적으로 바꾸거나 할 수 없다. 반면에 앞서본 배열과 같은 참조형은 크기를 동적으로 할당할 수 있다. 이런 것을 동적메모리 할당이라 한다. 기본형은 선언과 동시에 사이즈가 정적으로 정해지지만, 참조형을 사용하면 이처럼 동적으로 크기가 변해서 유연성을 제공할 수 있다.
- 참조형은 더 복잡한 데이터구조를 만들고 관리, 기본형은 더 빠르고 메모리를 효율적으 로 처리
배열 생성 및 초기화
int[] students;
students = new int[]{90.80,70,60,50}; // 배열 생성과 초기화
------
int[] students = new int[]{90,80,70,60,50}; // 배열 변수 선언, 배열 생성과 초기화
----
int[] students = {90,80,70.60,50}; // 자바내부에서 배열 요소의 크기를 보고 new int[5]를 사용해서 생성
2차원배열
2차원 배열은 행과 열로 구성된다.
int[][] arr = new int[2][3];
향상된 for문
for( 변수 : 배열 또는 컬렉션 ) {
// 배열 또는 컬렉션의 요소를 순회하면서 수행할 작업
}
아래의 일반 for문에서는 int i 와 같은 인덱스를 탐색할 수 있는 변수와 배열의 끝 조건을 지정해주는 i<numbers.length와 마지막으로 배열의 값을 하나 읽을 때 마다 인덱스를 하나씩 증가시켜줘야한다. 개발자 입장에서는 단순히 배열을 순서대로 끝까지 탐색하고 싶은데, 너무 번잡한 일 일수도 있다. 그래서 향상된 for문이 등장했다.
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문을 사용하지 못하는 경우가 있다. 향상된 for문에서는 증가하는 인덱스 값이 감추어져 있다. 따라서 int i와 같은 증가하는 인덱스 값을 직접 사용해야 하는 경우에는 향상된 for문을 사용할 수 없다.
메서드
메서드 호출과 용어정리
메서드를 호출할 때는 다음과 같이 메서드에 넘기는 값과 매개변수(파라미터)의 타입이 맞아야 한다. 물론 넘기는 값과 매개변수(파라미터)의 순서와 갯수도 맞아야 한다.
호출 : call("hello" , 20 )
메서드 정의 : int call(String str, int age)
- 인수(Argument) : "hello", 20처럼 넘기는 값을 영어로 Argument(아규먼트), 한글로 인수 또는 인자라 한다
- 매개변수(Parameter) : 메스드를 정의할때 선언한 변수인 String str, int age를 매개변수,파라미터라 한다. 메서드를 호출할 때 인수를 넘기면, 그 인수가 매개변수에 대입된다.
용어정리
- 인수(인자) : 메스더 내부로 들어가는 값
- 매개변수(파라미터) : 매개 + 변수의 합성어로 '중간에서 전달하는 변수'라는 의미를 가진다. 즉, 메서드 호출부와 메서드 내부 사이에서 값을 전달하는 역할을 하는 변수
참고자료