33일차 람다
추상메소드가 하나인 인터페이스의 익명구현객체를 만드는 람다식
특별한경우 더 줄여서 사용할 수 있다. 그것이 참조이다.
특별한경우라는 것은 람다식의 메소드 몸통이 한줄이면 중괄호가 생략이 가능하다.
그런데 파라미터의 타입과 순서 개수가 일치한다면 바로 넘길 수 잇다.
16.5 메소드참조
16.5.3 매개변수 인스턴스메소드 참조 - 2
Reference to an insatnce method
of an arbitaray object of a particular type
첫번째 파라미터가 가지고 있는 메소드에 두번째 파라미터가 들어갈때 사용하는 것
생긴것은 스태틱 메소드 참조 같은데 인스턴스 메소드를 참조하는 것이다.
첫번째 파라미터가 객체고 두번째 파라미터가 첫번째 파라미터 객체의 메소드의 파라미터가 될때
람다식에서 한개 이상일때 앞의 인스턴스 메소드에 다음 파라미터가 파라미터로 들어갈때
인스턴스의 타입명::인스턴스메소드
class MyClass04 {
void method(int a) {
}
}interface MyInterface05 {
void action(MyClass04 a, int b);
}public class C04MethodReference {
public static void main(String[] args) {
MyInterface05 o1 = (a,b) -> a.method(b);
MyInterface05 o2 = MyClass04::method;
}
}16.5.4 인스턴스 메소드 참조 - 3
String의 compareToIgnoreCase메소드를 사용한 것이다.
@FunctionalInterface
public interface Compareable {
int compare(String a, String b);
}public class Person {
public void ordering(Compareable compareable) {
String a = "홍길동";
String b = "김길동";
int result = compareable.compare(a, b);
if (result < 0) {
System.out.println(a + "은 " + b + "보다 앞에 옵니다.");
} else if (result == 0) {
System.out.println(a + "은 " + b + "과 같습니다.");
} else {
System.out.println(a + "은 " + b + "보다 뒤에 옵니다.");
}
}
}public class MethodReferenceExample {
public static void main(String[] args) {
Person person = new Person();
person.ordering(new Compareable() {
@Override
public int compare(String a, String b) {
int result = a.compareToIgnoreCase(b);
return result;
}
});
person.ordering((a, b) -> a.compareToIgnoreCase(b));
person.ordering(String::compareToIgnoreCase);
}
}16.5.5 확인문제 9번
public static void main(String[] args) {
avg(new Function<Student>() {
@Override
public double apply(Student t) {
double result = t.getEngScore();
return result;
}
});
//double engAvg = avg(s -> s.getEngScore());
double engAvg = avg(Student::getEngScore);
System.out.println("영어 평균 점수: " + engAvg);
//double mathAvg = avg(s -> s.getMathScore());
double mathAvg = avg(Student::getMathScore);
System.out.println("수학 평균 점수: " + mathAvg);
}16.5.6 확인문제 7번
public static void main(String[] args) {
//int max = maxOrMin((x, y)->Math.max(x, y));
int max = maxOrMin(Math::max);
System.out.println("최대값: " + max);
//int min = maxOrMin((x, y)->Math.min(x, y));
int min = maxOrMin(Math::min);
System.out.println("최소값: " + min);
}16.6 생성자 참조
추상메소드가 객체를 리턴할때 구현객체가 단순히 객체만 리턴하면 참조를 사용할 수 있다.
생성할객체명::new 하면된다. 파라미터가 일치하기만 하면된다.
public interface Createable1 {
public Member create(String id);
}public interface Createable2 {
public Member create(String id, String name);
}public class Member {
private String id;
private String name;
public Member(String id) {
this.id = id;
System.out.println("Member(String id)");
}
public Member(String id, String name) {
this.id = id;
this.name = name;
System.out.println("Member(String id, String name)");
}public class Person {
public Member getMember1(Createable1 creatable) {
String id = "winter";
Member member = creatable.create(id);
return member;
}
public Member getMember2(Createable2 creatable) {
String id = "winter";
String name = "한겨울";
Member member = creatable.create(id, name);
return member;
}
}public class ConstructorReferenceExample {
public static void main(String[] args) {
person.getMember1(id -> new Member(id));
person.getMember1(Member::new);
person.getMember2((id, name) -> new Member(id, name));
person.getMember2(Member::new);
}
}1. 타입추론
자바 전체를 관통하는 이야기이다.
자바는 참조변수 타입으로 인스턴스의 타입을 추론할 수 있다.
또한 람다식에서는 파라미터의 타입으로 인해서 타입을 추론할 수 있다.
제네릭에서의 타입추론
Box<String> box1 = new Box<String>();
Box<String> box2 = new Box<>();
List<List<Integer>> list1 = new ArrayList<List<Integer>>();
List<List<Integer>> list2 = new ArrayList<>();람다식 타입추론
MyInterface01 o1 = (int a, String b) -> b;
MyInterface01 o2 = (a, b) -> b;2. 지역변수 타입추론
변수에 값을 넣을 때 값의 타입으로 인해서 변수의 타입을 알 수 있다.
그래서 var이라는 타입에 값을 넣을 수 있다.
필드에서는 일어나지 않는다.
var 사용은 들어가는 값에 의해서 타입이 추론되기 때문에 선언과 동시에 초기화할때만 사용가능하다.
int a = 3;
String b = "java";
var c = 5;
var d = "hello";그래서 이것을 응용하면 앞의 타입에 의해서 뒤의 타입을 정할 수 있고
뒤의 타입을 이용해서 앞의 타입을 정할 수 있다.
Box<String> box1 = new Box<>();
var box3 = new Box<String>();var에 재할당시 같은 타입만 가능하다.
처음 들어갈때 타입이 추론이 되기때문이다.
var f = 10; //int 로 추론
f = 11;
//f = 12.0; 불가능결론은 종합적으로 var사용시 읽기 쉬운 코드인가를 고민해야한다.
멀지 않아서 변수의 타입이 눈으로 읽는데 뭔지 알 수있다면 써도된다.
그러넫 너무 멀리 있어서 이 타입이 뭔지 모르겟다면 사용하지 말자.
var list2 = new ArrayList<String>();
//긴코드..
// ok
for (String item : list2) {
}
// 권장하지 않음
for (var item : list2) {
}var는 좀 이후에 나왔다.
그래서 키워드가 아니라서 사용할 수 있지만 변수명으로 사용하지말자.
int var = 3; // 사용가능하지만 사용하지 말자
15. 컬렉션자료구조
15.1 컬렉션 프레임워크이란
앞으로 많이 사용하게 될 것이다.
컬렉션이란 다른 객체를 담고 있는 객체
클래스와 인터페이스들 짜여진 구조 이미 만들어놓은 것이 프레임워크이다.
자료구조 :
자료를 어떻게 구조화시켜서 문제를 해결해 나갈것인가이다.
예시 :
배열 : 순서로 나열되서 저장된 구조
튜플 : 리스트와 비슷함.
연결 리스트 : linkedlist각 자료들이 연결되어 있는것
해시 테이벌 : 자바스크립트 객체 프로퍼티:밸류 프로퍼티:밸류로 저장된 구조, 자바 맵
등등이 있다.
자료를 어떻게 저장해야하는지 이것을 클래스로 만든다면 시간이 오래걸릴것이다.
이것을 사용하는 방법을 정리 해둔게 컬렉션 프레임워크이다.
대표적인 인터페이스가 Collection이다.
Collection은 하나의 객체를 여러개 저장하는 타입이다.
이 인터페이스 특징에 따라 List와 Set으로 나뉜다.
List는 객체를 저장할때 순서가 있는 방법이다.
Set은 순서가 없다.
Map은 key, val쌍으로 저장이 된 것이다.
실제 인스턴스를 만드려면 이것을 구현한 클래스가 필요하다.
각각 대표로 ArrayList HashSet HashMap이 있다.
15.2 List 컬렉션
java.util.List에 있고 순서가 있는 컬렉션이다.
List<E> 담고있는 아이템의 타입이 이 제네릭에서 결정된다.
순서가 있기 때문에 각 원소를 인덱스를 통해서 접근 할 수 잇다.
순서가 있어서 중복된 원소도 넣을 수 있다.
사용되는 메소드는 다음과 같다.
element 추가 : add(값) 메소드
element 얻기 : get(index) 메소드
list의 크기 : size() 메소드
특정 index의 element 지우기 : remove(index) 메소드
지우면 오른쪽의 값이 왼쪽에 채워진다. 한칸씩 당겨진다.
특정 index 값 바꾸기 : set(index, 값) 메소드
15.2.1 arrayList
public class C01List {
public static void main(String[] args) {
// 새 리스트 만들기
List<String> list = new ArrayList<String>();
// element 추가
list.add("java");
list.add("css");
list.add("spring");
list.add("java");
// element 얻기
String e1 = list.get(0);
String e2 = list.get(1);
String e3 = list.get(2);
String e4 = list.get(3);
// list의 크기
int size = list.size(); //4
// 특정 index의 element 지우기
list.remove(2);
System.out.println("지운 후 크기 : " + list.size()); //3
System.out.println("지운 후 2번 index의 값 : " + list.get(2)); //java
//특정 index 값 바꾸기
list.set(2, "react");
}
}15.2.2 전체 탐색
list를 탐색하는 방법은 3가지가 있다.
1.고전for문
2.향상된 for문
3.Iterator
Iterator는 탐색하기 위해 만들어진 객체이다.
list와 궁합이 맞지는 않지만 set이나 map과 자주사용한다.
4.forEach메소드
매개변수로 Consumer타입이 들어가는데 list가 가지고 있는 아이템을 건네준다.
for문을 돌려서 하나씩 건네준다.
함수형인터페이스이기때문에 람다로 구현해줘야한다.
값을 하나만 전달해서 메소드를 실행하기 때문에 참조도 가능하다.
스트림의 내부반복자이야기에서 foreach가 나오는데 이것을 활용한 것 같다.
public class C02List {
public static void main(String[] args) {
// list 전체 탐색
List<String> list = new ArrayList<>();
list.add("java");
list.add("css");
list.add("html");
list.add("spring");
list.add("react");
// for
System.out.println("for###########");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 향상된 for
System.out.println("향상된 for@@@@@@@@@");
for (String e : list) {
System.out.println(e);
}
// Iterator 반복자
System.out.println("Iterator &&&&&&&&&&&");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
// forEach 메소드
System.out.println("forEach 메소드 $$$$$$$$$");
list.forEach(e -> System.out.println(e));
// forEach 메소드 참조
System.out.println("forEach 메소드 참조");
list.forEach(System.out::println);
}
}15.2.3 확인문제 7번
BoardDao객체의 getBoardList()메소를 호출하면 list를 리턴한다.
이때 BoardDao작성하기
public class ListExample {
public static void main(String[] args) {
BoardDao dao = new BoardDao();
List<Board> list = dao.getBoardList();
for (Board board : list) {
System.out.println(board.getTitle() + "-" + board.getContent());
}
}
}public class BoardDao {
public List<Board> getBoardList() {
List<Board> list = new ArrayList<>();
list.add(new Board("제목1", "내용1"));
list.add(new Board("제목2", "내용2"));
list.add(new Board("제목3", "내용3"));
return list;
}
}15.2.4 5장 확인문제 7번
배열 최대값 구하는 문제 list로 풀어보기
public class Exam0507 {
public static void main(String[] args) {
// List of() 메소드 : 수정불가 리스트 리턴
List<Integer> list = List.of(1, 5, 3, 8, 2);
int max = Integer.MIN_VALUE;
for (Integer i : list) {
if (i > max) {
max = i;
}
}
System.out.println(max);
}
}15.2.5 5장 확인문제 9번
scores를 배열로 받은 것을 list로 만들기
public class ex0509 {
public static void main(String[] args) {
int stNum = 0;
// int[] scores = null;
boolean run = true;
List<Integer> scores = new ArrayList<>();
while (run) {
int menu = mainMenu();
switch (menu) {
case 1:
stNum = inputNum();
break;
case 2:
input(scores, stNum);
break;
case 3:
list(scores);
break;
case 4:
analyse(scores);
break;
case 5:
run = quit();
break;
}
}
}
public static int mainMenu() {
Scanner sc = new Scanner(System.in);
System.out.println("-------------------------------------------------------");
System.out.println("1.학생수 | 2.점수입력 | 3. 점수리스트 | 4.분석 | 5.종료");
System.out.println("-------------------------------------------------------");
System.out.print("선택> ");
int memuNum = Integer.parseInt(sc.nextLine());
return memuNum;
}
public static int inputNum() {
Scanner sc = new Scanner(System.in);
System.out.print("학생수> ");
int stNum = Integer.parseInt(sc.nextLine());
return stNum;
}
public static void input(List<Integer> scores, int stNum) {
Scanner sc = new Scanner(System.in);
for (int i = 0; i < stNum; i++) {
System.out.printf("scores[%d]> ", i);
scores.add(Integer.parseInt(sc.nextLine()));
}
}
public static void list(List<Integer> scores) {
for (int i = 0; i < scores.size(); i++) {
System.out.printf("scores[%d]: %d\n", i, scores.get(i));
}
}
public static void analyse(List<Integer> scores) {
int total = 0;
double avg = 0;
int max = 0;
for (int i = 0; i < scores.size(); i++) {
if (scores.get(i) > max) {
max = scores.get(i);
}
total += scores.get(i);
}
avg = (double) total / scores.size();
System.out.println("최고 점수: " + max);
System.out.println("평균 점수: " + avg);
}
public static boolean quit() {
System.out.println("프로그램 종료");
return false;
}
}15.2.6 6장 확인문제 20번
account문제 list로 다시 풀기
자잘하게 유효성을 체크하는 것들을 추가해보았다.
public class BankApplication {
private static List<Account> accountList = new ArrayList<>();
public static void main(String[] args) {
while (true) {
int menu = mainmenu();
switch (menu) {
case 1:
createAccount();
break;
case 2:
AccountList();
break;
case 3:
depoist();
break;
case 4:
withdraw();
break;
case 5:
quit();
break;
}
}
}
public static int mainmenu() {
Scanner sc = new Scanner(System.in);
System.out.println("--------------------------------------------------");
System.out.println("1.계좌생성 | 2.계좌목록 | 3.예금 | 4.출금 | 5.종료");
System.out.println("--------------------------------------------------");
System.out.print("선택> ");
int menu = Integer.parseInt(sc.nextLine());
return menu;
}
public static void createAccount() {
Scanner sc = new Scanner(System.in);
System.out.println("--------");
System.out.println("계좌생성");
System.out.println("--------");
System.out.print("계좌번호: ");
String ano = sc.nextLine();
if(!ano.matches("\\d{3}-\\d{3}")) {
System.out.println("계좌번호는 000-000형식입니다.");
return;
}
System.out.print("계좌주: ");
String owner = sc.nextLine();
System.out.print("초기입금액: ");
int balance = Integer.parseInt(sc.nextLine());
Account newAccount = new Account(ano, owner, balance);
accountList.add(newAccount);
System.out.println("결과: 계좌가 생성되었습니다.");
}
public static void AccountList() {
System.out.println("--------");
System.out.println("계좌목록");
System.out.println("--------");
for (int i = 0; i < accountList.size(); i++) {
Account account = accountList.get(i);
String ano = account.getAno();
String owner = account.getOwner();
int balance = account.getBalance();
System.out.printf("%s %s %d\n", ano, owner, balance);
}
}
public static void depoist() {
Scanner sc = new Scanner(System.in);
System.out.println("--------");
System.out.println("예금");
System.out.println("--------");
System.out.print("계좌번호: ");
String ano = sc.nextLine();
// 입력된 계좌번호를 가진 Account 객체 찾아서
for (int i = 0; i < accountList.size(); i++) {
Account cur = accountList.get(i);
if (cur.getAno().equals(ano)) {
System.out.print("예금액: ");
int balance = Integer.parseInt(sc.nextLine());
// 입력 받은 금액을 더해서 다시 넣어준다(set)
int money = cur.getBalance() + balance;
cur.setBalance(money);
System.out.println("예금이 성공했습니다.");
} else {
System.out.println("계좌가 존재하지 않습니다.");
}
}
}
public static void withdraw() {
Scanner sc = new Scanner(System.in);
System.out.println("--------");
System.out.println("출금");
System.out.println("--------");
System.out.print("계좌번호: ");
String ano = sc.nextLine();
// 입력된 계좌번호를 가진 Account 객체 찾아서
for (int i = 0; i < accountList.size(); i++) {
Account cur = accountList.get(i);
if (cur.getAno().equals(ano)) {
System.out.print("출금액: ");
int money = Integer.parseInt(sc.nextLine());
if (cur.getBalance() < money) {
System.out.println("잔액이 부족합니다.");
return;
} else {
// 입력 받은 금액을 빼고 돌려주기(set)
int balance = cur.getBalance() - money;
cur.setBalance(balance);
System.out.println("츌금이 성공했습니다.");
}
} else {
System.out.println("계좌가 존재하지 않습니다.");
}
}
}
public static void quit() {
System.out.println("프로그램 종료");
System.exit(0);
}
}15.2.7 199쪽 확인문제 6번
2차원배열의 길이를 출력하는 코드
리스트에 배열을 담아서 사용하기
public class ex0506 {
public static void main(String[] args) {
List<int[]> list = new ArrayList<>();
list.add(new int[] { 95, 86 });
list.add(new int[] { 83, 92, 96 });
list.add(new int[] { 78, 83, 93, 87, 88 });
System.out.println(list.size());
System.out.println(list.get(2).length);
}
}15.2.8 linkedList
ArrayList보다는 아니지만 꽤 많이 사용되는 list이다.
같은 List안에 있어서 같은 메소드를 사용하지만 동작하는 방식이 아예 다르다.
기존 List는 추가할때마다 고정이 되어 있다.
그래서 중간을 한개 지우면 하나씩 앞으로 당겨진다.
LinkedList는 바로 옆에 있는 것이 아니라 떨어져있다.
어디 있다는 정보만 가지고 있다. 즉 다음 인덱스의 참조값을 가지게 되는 것이다.
그래서 서로 연결되어있다고 linked라고 하기도 한다.
ArrayList는 같은 간격으로 있어서 중간에 들어가려면 중간에 그냥 들어가면된다.
LinkedList은 같은 간격이아니라 타고 타고 들어가야한다.
중간을 탐색하고 싶다면 중간에서 하나씩 타고 들어가야한다.
그래서 중간을 탐색하고 싶다면 ArrayList가 더 빠르다.
LinkedList는 맨앞이나 맨끝에 아이템을 추가하고 지우는것은 속도가 같다.
ArrayList는 맨앞에 추가하려면 하나씩 다 뒤로 밀고 하느라 더 오래걸린다.
맨앞에 반복적으로 추가된다면 LinkedList가 좋은 선택이다.
그래서 돌문제 풀어봤는데 LinkedList가 더오래걸렸다.
public class LinkedListExample {
public static void main(String[] args) {
//ArrayList생성
List<String> list1 = new ArrayList<>();
//LinkedList생성
List<String> list2 = new LinkedList<>();
//시작시간 끝시간
long startTime;
long endTime;
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
list1.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.println("ArrayList걸린시간: " + (endTime - startTime));
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
list2.add(0, String.valueOf(i));
}
endTime = System.nanoTime();
System.out.println("LinkedList걸린시간: " + (endTime - startTime));
}
}ArrayList걸린시간: 10342400
LinkedList걸린시간: 5856000
add메소드가 list거이지만 실제 인스턴스에 재정의된 add메소드가 실행되는 것이다.
'다형성'
vector는 스레드 배우고 와서 볼 예정이다.
15.2.9 List안의 List
List도 객체이기때문에 List안에 List를 담을 수 있다.
public class C03List {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
// List의 List
List<List<String>> list2 = new ArrayList<>();
list2.add(new ArrayList<>());
list2.add(new ArrayList<>());
System.out.println(list2.get(0).size());//0
System.out.println(list2.get(1).size());//0
list2.get(0).add("java");
list2.get(0).add("spring");
list2.get(1).add("css");
list2.get(1).add("html");
list2.get(1).add("js");
//전체 탐색
System.out.println("for#######");
for (int i = 0; i < list2.size(); i++) {
for (int j = 0; j < list2.get(i).size(); j++) {
System.out.println(list2.get(i).get(j));
}
}
System.out.println("향상된 for $$$$$$");
for (List<String> list : list2) {
for (String item: list) {
System.out.println(item);
}
}
System.out.println("forEach %%%%%%%%%%");
list2.forEach(list -> list.forEach(e-> System.out.println(e)));
}
}꺼낼때는 2차원배열을 꺼내듯이 for문을 중첩하여서 보면된다.
15.2.10 119 확인문제 8번
2차원 리스트 내용물의 총합과 평균구하기
public class exam0508 {
public static void main(String[] args) {
List<List<Integer>> list = List.of(
List.of(95, 86),
List.of(83, 92, 96),
List.of(78, 83, 93, 87, 88)
);
int sum = 0;
int count = 0;
for (List<Integer> list2 : list) {
for (Integer i : list2) {
sum += i;
count++;
}
}
double avg = (double) sum / count;
System.out.println(sum); //881
System.out.println(avg); //88.1
}
}2023.03.14 후기
강사님이 list set map는 지금 익숙해지지 않아도 평생 볼 인터페이스라고 한다. 그래서 언젠간 익숙해질 것이라고 조언해주셨다.
자바 안배워도 대응되는 타입이 다른 언어에도 각각있다고한다.
람다식을 잘못이해하고잇엇다.
풀어서 해석해보면 안에있는 메소드를 재정의해서 사용하는 것이다.
함수형 인터페이스에 대한 정의를 다시 한번 생각해볼필요가 있다.
람다식 사용이 가능한 함수형인터페이스는 데이터를 값을받아 어떻게 연산할지 식이 들어있는 것이고
Person이런애들의 메소드는 이 값을 전달하는 역할만 하는 메소드인것이다.
실제 연산하는 내용은 익명구현객체에서 재정의해서 실제 연산방법을 만드는것이다.
객체를 뱉어내는 메소드 그런걸 아직 잘 이해하지 못하는 것 같다.
객체를 리턴하는 것을 만들어낼 생각을 별로 하지 못한다.
'국비 > Java' 카테고리의 다른 글
| 2023.03.16 35일차 Java (0) | 2023.03.16 |
|---|---|
| 2023.03.15 34일차 Java (0) | 2023.03.15 |
| 2023.03.13 32일차 Java (0) | 2023.03.13 |
| 2023.03.10 31일차 Java (0) | 2023.03.10 |
| 2023.03.09 30일차 Java (0) | 2023.03.09 |