class Color{
public static final int RED = 1;
public static final int YELLOW = 2;
}
enum Color{
RED, YELLOW
}
class
대신 enum 사용컴파일 시 타입 체크를 하기 때문에 객체 안정성이 높아진다.
형변환이 용이해진다.
제네릭의 T와 E
List<E>
E의 경우엔 배열처럼 사용되는 것들에 E가 사용되는 것이 적합
public class ClassName<T> { ... }
: T의 경우엔 E를 사용하는 경우 예외의 모든 경우
/* DTO[Data Transfer Object]
* 1. 기본 구조
* - 멤버변수/기본생성자/생성자/getXxx/setXxx/toString()
* 2. 참고
* - 객체 생성시 다수의 멤버 변수가 존재하면 선별해서 변수값 초기화를 효율적으로 하기 위해서는
* builder pattern을 사용하면 효율적으로 사용 가능하다.
* */
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class People {
private String name;
private int age;
}
package step01;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import model.domain.People;
public class DoubleColonTest {
@Test
public void test() {
People p1 = new People("재석", 20);
People p2 = new People("영자", 10);
People p3 = new People("동엽", 30);
System.out.println(p1);
// step01 - API로 List<People> 객체로 자동 변환
List<People> all = Arrays.asList(p1, p2, p3);
/*
* [People(name=재석, age=20), People(name=영자, age=10), People(name=동엽, age=30)]
* List 객체가 보유한 toString()이 호출됐음을 알수 있다. 각각의 요소(데이터-객체)값을 출력할 때 각 요소별
* toString()가 호출이 됨
*
* 즉, 리스트 객체의 toString()이 호출되고 또 각각의 리스트 안에 들어간 값을 호출할 때 해당 객체의 toString()이 호출된
* 형태
*/
System.out.println(all);
/*step02 - 반복문으로 데이터를 출력
* People(name=재석, age=20)
* People(name=영자, age=10)
* People(name=동엽, age=30)
*/
System.out.println("step02: 반복문으로 데이터를 출력");
for (People p : all) {
System.out.println(p);
}
/*step03 - 반복문과 람다를 사용해서 데이터를 출력
* People(name=재석, age=20)
* People(name=영자, age=10)
* People(name=동엽, age=30)
*/
System.out.println("step03: 반복문과 람다를 사용해서 데이터를 출력");
all.forEach(p -> System.out.println(p));
/*step04 - 람다와 double colon으로 데이터 출력
* People(name=재석, age=20)
* People(name=영자, age=10)
* People(name=동엽, age=30)
*/
System.out.println("step04: 람다와 double colon으로 데이터 출력");
all.forEach(System.out::println);
}
}
*.java 종류
1. 순수 자바 클래스
2. enum - 데이터 자체를 상수화해서 명확성을 부여한 설정
3. interface
ㅤ3-1. 스펙
ㅤ3-2. 구조
ㅤㅤ- 상수 / 주석 / 메서드 선언구
ㅤ3-3. 강제사항
ㅤㅤ- 해당 인터페이스에 정의한 메서드가 있다면 이를 구현하는 클래스에서는 스펙에 맞게 메서드를 재정의해야 한다.
ㅤ3-4. 대표적인 구조
ㅤㅤDB 벤더사에서 db 판매를 위한 지원
ㅤㅤㅤ- db driver
ㅤㅤdb 접속 객체 사용 관점(API 사용자 관점)
ㅤㅤㅤ- 연결을 위한 메서드인 getConnection()의 구현 코드를 알 필요가 없음
ㅤㅤgetConnection() 제공자 관점(API 제공자 관점)
ㅤㅤㅤ- db 벤더사가 getConnection()을 제공할 때 구현을 하지 않은 채로 미완성 메서드로 이를 제공하고 있다. (= 스펙 제시)
ㅤㅤㅤ- 이렇게 메서드 껍데기만 제공하는 이유는 특정지어서 메서드를 구현하면 달라지는 데이터베이스 종류마다 해당 메서드의 내용을 변경해서 제공해야하기 때문이다 그렇기 때문에 사용하고자하는 데이터베이스에 상관 없이 껍데기만 제공해서 구현부에서 이를 채워서 사용자가 사용할 수 있게 했다.
ㅤㅤㅤ- 또한 하위 클래스에서 해당 메서드를 재정의를 꼭 해야 한다.
ㅤpublic abstract Connection getConnection(String url, String id, String );
ㅤㅤㅤ- 구현부 없이 스펙만 제시하고 있다.
ㅤ- 특별한 기능을 보유한 마킹 interface
4. servlet
public interface PeopleInfo {
//상수, 주석과 함께 메서드 선언부가 필요
public final String COMPANY_NAME ="fisa";
/* "회사명 본인이름"을 결합해서 반환
* 미완성 메서드로 하위클래스에서 재정의를 해야 한다.
* */
public abstract String getPeopleInfo();
}
public class MyPeople implements PeopleInfo {
@Override
public String getPeopleInfo() {
return COMPANY_NAME + " 이름";
}
@Test
public void test() {
PeopleInfo myPeopleInfo = new MyPeople();
System.out.println(getPeopleInfo());
}
}
import org.junit.Test;
/* 인터페이스
* 1. 상수와 미완성 메서드로 구성
* 2. 인터페이스는 미완성 코드이기 때문에 객체 생성이 불가
* 3. 타입으로는 사용이 가능하다.
*
* 즉, 타입으로는 사용이 가능하지만 생성자가 없기 때문에 객체 생성은 불가하다.
*
* */
public class MyPeople2 {
// interface를 완벽하게 구현하는 이름없는 클래스 개발 = 익명 inner class
@Test
public void step01() {
// PeopleInfo peopelInfo = new People(); 은 불가!
PeopleInfo p1 = new PeopleInfo() {
@Override
public String getPeopleInfo() {
return null;
}
}; // 세미콜론 생략 불가
PeopleInfo p2 = new PeopleInfo() {
@Override
public String getPeopleInfo() {
return null;
}
}; // 세미콜론 생략 불가
System.out.println(p1);
System.out.println(p2);
}
}
출력 결과
step01.MyPeople2$1@799d4f69
step01.MyPeople2$2@49c43f4e
*.class
이 생성된다. 객체이름$익명이너클래스명.class
로 바이트 코드가 생성된다.// 연산 + 람다식을 사용할 인터페이스
@FunctionalInterface
public interface Calc {
/* 두개의 데이터를 받아서 연산로직후 반환 로직으로 재정의를 해라 */
int calculation(int v1, int v2); // public abstract 자동 적용
}
@FunctionalInterface
애너테이션을 이용해 기능적 인터페이스로 사용할 것을 선언한다.public class CalcClass {
@Test
public void step01() {
// 익명 클래스 기반의 개발
Calc c1 = new Calc() {
@Override
public int calculation(int v1, int v2) {
return v1 + v2;
}
};
System.out.println(c1);
System.out.println(c1.calculation(1, 2));
}
@Test
public void step02() {
System.out.println("-- 1. 더하기 --");
Calc addCalc = (int v1, int v2) -> v1 + v2; // 중괄호가 없어서 return 생략
System.out.println(addCalc.calculation(20, 21));
System.out.println("-- 1. 더하기(중괄호 사용과 return) --");
Calc addCalc2 = (a, b) -> {
return a + b;
};
System.out.println(addCalc2.calculation(2, 3));
System.out.println("-- 2. 빼기 --");
Calc calc2 = (int v1, int v2) -> v1 > v2 ? v1 - v2 : v2 - v1;
System.out.println(calc2.calculation(2, 1));
System.out.println(calc2.calculation(1, 3));
System.out.println("-- 3. 곱하기(타입 없이) --");
Calc calc3 = (a, b) -> a * b;
System.out.println(calc3.calculation(2, 2));
}
}
Calc addCalc = (int v1, int v2) -> v1 + v2;
: step02()의 경우엔 람다를 이용해서 미완성 메서드를 재정의하고 있다.System.out.println(calc3.calculation(2, 2));
: 재정의한 메서드를 사용하고 있다.
- Stream 생성 collectionName.stream()
- 스트림은 최종 연산 수 사라지기 때문에 다시 사용하기 위해서는 스트림을 재생성 해주어야 한다.
- Stream 중간 연산
- 중간 연산은 여러번 가능하다.
- Stream 최종 연산
- 최종 연산 후 Stream은 삭제
public class StreamAPI1 {
@Test
public void step01() {
List<String> datas = Arrays.asList("a", "b", "c", "d", "e");
System.out.println(datas);
System.out.println(datas.get(0));
datas.forEach(data -> System.out.println(data));
System.out.println("-- lab2 : 더블 연산자로 출력");
datas.forEach(System.out::println);
System.out.println("-- lab3 : b를 제외한 출력(=조건 기능 추가)");
datas.forEach(data -> {
if (!data.equals("b")) {
System.out.println(data);
}
});
/*
* data들을 stream 객체화해서 필터링 후 필터링된 데이터를 반복해서 출력 . : 접근 연산자, dot 연산자 접근 연산자가 지속적으로
* 나오는 문법을 체이닝이라고 한다. 메서드를 지속적으로 호출시에는 체이닝 메서드 호출
*/
System.out.println("-- lab4 : Stream API를 활용한 조건 기능 추가");
datas.stream().filter(data -> !data.equals("b")).forEach(System.out::println);
// 기본 타입과 객체 타입 다름 - java.util.List는 객체들만 저장 및 관리한다.
// 1~5까지 데이터 저장
// 3을 제외한 데이터만 람다식 스트림으로 출력
/*
* 1,2,3,4,5: 기본타입 값으로 코딩, 컴파일 후 실행시 Integer 자동변화 autoboxing int -> Integer이 1:1
* 지원 클래스
*/
List<Integer> data2 = Arrays.asList(1, 2, 3, 4, 5);// autoboxing
data2.stream().filter(data -> !data.equals(3)).forEach(System.out::println);
/*
* 해당 작업은 String 3이랑 같은 경우이기 때문에 3이 출력이 된다.
*
* 하위 클래스들이 객체의 내용값 비교로 재정의된다. - 객체 타입 먼저 확인하고 동일한 타입인 경우에만 동일 타입의 객체들간의 내용을
* 비교한다. - public boolean equals(Object value){ }
*/
System.out.println(" String과 Integer은 다른 타입으로 비교가 부적합하다. (에러는 아님)");
data2.stream().filter(data -> !data.equals("3")).forEach(System.out::println);
/*
* autoboxing : 기본 타입을 객체 타입으로 변경 시키는 작업 Integer i = 3; -> Integer i = new
* Integer(3);
*
* unboxing : 객체 타입을 기본 타입으로 빼오는 작업 Integer, ... = wrapper class int i = new
* Integer(3); -> int i = (new Integer(3)).intValue();
*
*/
System.out.println("autoboxing & unboxing");
data2.stream().filter(data -> data != 3).forEach(System.out::println);
}
}
package step02.stream.api;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
public class StreamAPI2 {
// @Test
public void mapTest() {
Map<String, String> datas = new HashMap<String, String>();
datas.put("a", "재석");
datas.put("b", "연어");
datas.put("c", "종원");
datas.put("d", "동엽");
// key 를 모르는 상태로 value값 확인 가능
datas.forEach((k, v) -> System.out.println("key: " + k + " value: " + v));
}
@Test
public void streamTest() {
List<String> datas = Arrays.asList("1", "2", "3", "4", "5");
datas.stream().forEach(System.out::println);
datas.stream().forEach(a -> System.out.println(a + 1));
/*
* <? super T>: T를 기준으로 T의 상위타입 문자열을 숫자로 변환(int) : parseInt
*/
int r = datas.stream().mapToInt(data -> Integer.parseInt(data)).sum();
System.out.println(r);
int r2 = datas.stream().mapToInt(Integer::parseInt).sum();
System.out.println(r2);
double d1 = datas.stream().mapToDouble(Double::parseDouble).sum();
System.out.println(d1);
}
}
Optional.empty()
: 빈 Optional 객체 생성시에 사용한다.Optional.of()
: 값이 null이 아닌 경우에 사용한다.Optional.ofNullable(Value)
: 해당 값이 null인지 아닌지 확실하지 않은 경우에 사용한다.