[Java] Collection, Enum, Lambda

JH·2023년 3월 24일

Java

목록 보기
5/21

1. TIL

A. Collection

여러 객체(데이터)를 모아 놓은 것
List, Set, Map은 Collection interface가 타입임

자주 쓰는 Collection 메소드로 add(), remove(), contains(), size(), iterator()가 있음

Generic <T> (제네릭)

  • 컴파일시 타입을 체크해 주는 기능

  • 타입 체크와 형변환을 생략해줄 수 있음

  • static멤버에는 타입 변수 T를 사용할 수 없음

  • 제네릭 타입의 배열 T[ ]를 생성하는 것은 허용되지 않음

ArrayList<String> arr1 = new ArrayList();

1. List

  • List의 Interface에는 ArrayList, LinkedList, Stack , Vector가 있음

  • 순서가 있는 데이터 집합, 중복을 허용함

  • 읽기 속도는 ArrayList가 추가/삭제는 LinkedList 빠름

List Method

  • add() , get(idx) ,set() , remove(idx) ,size() 등이 있음

a. ArrayList

  • 장점 : toString이 이미 재정의 됨, 객체 출력시 바로 나옴 (주소가 나오지 않음)

  • ArrayList에서는 중간에 index의 value가 비는 경우가 없
    음, 배열과 다름

  • 초기 몇개의 데이터를 사용해야 하는지 반드시 지정할 필요가 없음

  • ArrayList의 크기는 동적으로 변한다.


b. LinkedList

  • 데이터를 나열은 하되 포인터를 이용하여 주소를 참조

2. Set

  • HashSet, TreeSet이 있음
  • 순서가 없는 데이터 집합, 중복을 허용하지 않음

Iterator

  • 컬렉션에 저장된 요소들을 읽어오는 방법을 표준화한 것
  • hasNext, next를 이용하여 데이터를 가져옴
Iterator<String> iter = set1.iterator();
		while (iter.hasNext()) {
			System.out.println(iter.next());
		}

3. Map

  • HashMap, TreeMap 등이 있음
  • HashMap은 < Key, Value > 형태를 가짐
  • 순서를 보장하지 않음
  • 제네릭에는 참조타입만 지정할 수 있음

Map 메소드

put(), get(key), remove(), values(), keySet(), entrySet() 등이 있음

Hashmap

  • entrySet() : HashMap에 저장된 키와 값을 Entry의 형태로 Set에 저장해서 반환
  • get() : 지정된 key의 value를 반환

Entry 타입 이용하기

// hm1 = ("one, 1")
for(Entry<String, Integer> entry : hm1.entrySet()) {
			System.out.println(entry.getValue());
			
			if("one".equals(entry.getKey())) {
				System.out.println(hm1.get(entry.getKey()));
			}
		}

인터페이스 타입으로 객체가 만들어진 경우

Map<String, Student> hm2 = new HashMap<String, Student>();
hm2.put("k1", new Student("java", 1, "Junior"));		

HashMap<String, ArrayList<String>>

// arr3 = {1,2,3,4,5}
HashMap<String, ArrayList<String>> hm3 = new HashMap<>();
hm3.put("arr3", arr3);

HashMap<String, HashMap>

// arr3 = {1,2,3,4,5}

HashMap<String, HashMap<String, ArrayList<String>>> hm4 = new HashMap<>();
hm4.put("hm3", hm3);

// b값 출력 : 객체이므로 ArrayList로 형변환을 해야함
System.out.println( ((ArrayList)hm4.get("hm3").get("arr3")).get(1) );
		
// 위와 다르게 제네릭에서 데이터 타입을 지정하면 형변환을 안해도 된다.
		System.out.println(hm4.get("hm3").get("arr3").get(1));
}


4. Inout

  • 스택(Stack) : LIFO구조, 마지막에 저장된 것을 제일 먼저 꺼냄
  • 큐(Queue) : FIFO구조, 제일 먼저 저장한 것을 제일 먼저 꺼냄

Stack

public static void main(String[] args) {
		Stack<String> card = new Stack<String>();
		
		// push() : 저장
		card.push("Lotte");
		card.push("Hana");
		
        // peek() : 반환 
		System.out.println(card.peek()); // Hana
		System.out.println(card); // Lotte, Hana
		
		// pop() : 반환 + 삭제
		System.out.println(card.pop()); // Hana
		System.out.println(card); // Lotte

Queue

인터페이스 이므로 객체 생성 안됨

Queue<String> drinkBox = new LinkedList<String>();
		
		// add() : 저장
		drinkBox.add("Coke");
		drinkBox.add("Sprite");
		drinkBox.add("PepsiZero");
		
		// peek() : 반환
		System.out.println(drinkBox.peek());
		System.out.println(drinkBox);
		
		// poll() : 반환 + 삭제
		System.out.println(drinkBox.poll());
		System.out.println(drinkBox);


B. Java 8 Syntax

1. Eunm (열거형) : 관련된 상수들을 같이 묶어 놓은 것

  • 조상 클래스로 Enum이 있음
  • name(), valueOf() 메소드 등이 있음
  • name 자체가 값이 될 수 있음

Ex) Color

public enum Color { // Color 라고 하는 enum타입의 객체
	
	// 파라미터를 이용하려면 사용자 정의 생성자를 만들어야 함
	RED("c01"),
	BLUE("c02"),
	GREEN("c03");
	
	private String colorCode; // 캡슐화
	
	Color() {};
    
	Color (String colorCode) {
		this.colorCode = colorCode;
	};
	
	public String getColorCode() {
		return this.colorCode;
	}
}

Ex) Color Test

package step01.enumtype;

public class ColorTest {
	public static void main(String[] args) {
		for(Color color : Color.values()) {
			System.out.println(color.getColorCode());
		} // c01, c02, c03
	}
}

2. Lambda

람다식 : 함수(메서드)를 간단한 식으로 표현하는 방법

함수와 메서드의 차이

  • 근본적으로 동일, 함수는 일반적 용어, 메서드는 객체지향개념 용어
  • 함수는 클래스에 독립적, 메서드는 클래스에 종속적

함수형 인터페이스 : 추상 메소드가 단 1개인 인터페이스


Ex1) Interface

// 추상 메소드가 1개 만 있어서 함수형 인터페이스로 사용할 수 있음
public interface Astermark {
	public void addAstermark(String str1, String str2);
}

Ex1) class impl

public class AstermarkImpl implements Astermark{
	@Override
	public void addAstermark(String str1, String str2) {
		System.out.println(str1 + "*" + str2);
	}
}

Ex1) main

public class AstermarkTest{

	public static void main(String[] args) {
		// 두 문장을 * 를 기점으로 합쳐서 출력하는 기능
		String str1 = "Hello";
		String str2 = "Java";
		
		// interface + class
		AstermarkImpl astermarkImpl = new AstermarkImpl();
		astermarkImpl.addAstermark(str1, str2);
		
		// lambda
		Astermark astermark = 
        (String s1,String s2) -> System.out.println(s1 + "*" + s2); 
        // 람다식은 익명의 객체이므로 세미콜론 필수!
		
        astermark.addAstermark(str1, str2);
	}
}


Ex2) 심화

public class LambdaTest {
	
	// 람다 1, lombok을 이용하여 annotation
	@FunctionalInterface
	interface Lambda1 {
		void method1();
	}
	
	// 람다 2
	@FunctionalInterface
	interface Lambda2 {
		void method2(int i);
	}
	
	// 람다 3
	@FunctionalInterface
	interface Lambda3 {
		int method3(int x, int y);
	}
	
	// * 적용 (심화 계산기)
	@FunctionalInterface
	interface Calculation {
		int operation(int x, int y);
	}
	
	static int operate(int x, int y, Calculation calculation) {
		return calculation.operation(x, y);
	}
	
	public static void main(String[] args) {
		Calculation add = (x, y) -> x + y;
		Calculation sub = (x, y) -> x - y;

		
		System.out.println(operate(50, 13, add));
		System.out.println(operate(50, 13, sub));
		
		// 람다 1 : 매개 변수가 없는 람다식
		// 인터페이스에서 람다식 함수(객체) 만들기
		Lambda1 lambda1;
        
		// 기본적인 람다식, 객체이므로 코드블럭 뒤에 ;
		lambda1 = () -> {
			System.out.println("람다 1");
		};
//		
		// 코드 블럭이 없는 람다식
		lambda1 = () -> System.out.println("람다 1");
		System.out.println(lambda1);
		
		// 람다 2 : 매개 변수가 있는 람다식, 1개(자료형, 코드블럭 생략 가능)
		Lambda2 lambda2;
		lambda2 = (int i) -> {
			System.out.println(i + 10);;
		};
		
		// 매개 변수의 자료형과 코드 블럭이 없는 람다식
		lambda2 = i -> System.out.println(i + 10);;
		lambda2.method2(1);
		
		// 람다 3 : 매개 변수가 2개 이상
		Lambda3 lambda3;
		lambda3 = (int x, int y) -> {
			return x + y;
		};
		
		// 자료형, return + 코드 블럭 생략 가능
		lambda3 = (x, y) -> x + y;
		
		// 리턴을 사용하면 sysout을 해야 함
		System.out.println(lambda3.method3(3, 5));
	}
}

3. Stream

  • 다양한 데이터 소스를 표준화된 방법으로 다루기 위한 것

  • 중간 연산과 최종 연산으로 나뉨

  • 스트림은 Iterator처럼 일회용임(필요하면 다시 스트림을 생성해야 함)

  • 최종 연산 전까지 중간연산이 수행되지 않음

Ex)

// package, import 는 생략

public class StreamTest {
	public static void main(String[] args) {
		// Optional : null을 처리할 수 있음
		// empty() : 빈 Optional 객체 생성
		Optional<String> opt1 = Optional.empty();
        
		System.out.println(opt1); // Optional.empty
		
		// of(value / null) : null 이 아닌 데이터 생성 / *NPE 발생
		// Optional 안에 null
		Optional<String> opt2 = Optional.of(null);

//		System.out.println(opt2);	// NPE 발생
		
		// ofNullable(value / null) : null 일 수도 있는 값이 들어가는 경우
		Optional<String> opt3 = Optional.ofNullable(null);
		Optional<String> opt4 = Optional.ofNullable("java");
		
		// null 이 들어가게 되면 Optional 빈 객체 생성
		System.out.println(opt3); // Optional.empty
		System.out.println(opt4); // Optional[java]
		
		// ifPresent() : Optional 객체 내부에 데이터가 존재하는 경우만 해당 결과값을 반환
		opt3.ifPresent(v -> System.out.println(v)); // null이라 실행 안함
		opt4.ifPresent(v -> System.out.println(v)); // java
		
		// orElse : 빈 Optional 이라면 orElse 내부 파라미터로 받은 값이 반환
		// 값을 내부에 갖고 있는 Optional 이라면 해당 보유 값을 반환
		
		System.out.println(opt3.orElse("orElse")); // orElse
		System.out.println(opt4.orElse("orElse")); // java
        
		// orElseThrow : 파라미터로 Exception 객체 전달, 만약 null 아닐경우 해당 보유 객체값을 반환
		try {
			System.out.println(opt3.orElseThrow(NoSuchElementException::new));
		} catch (Exception e) {
//			e.printStackTrace(); // NoSuchElementException 발생
		}
		
		// orElseGet
//		System.out.println(opt3.orElseGet(null));	// NPE 발생
		
		
		
		// 스트림 Stream
		// step01 : 스트림 생성, 컬렉션, 길이가 있어야 함
		ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
		System.out.println(list1);
		
		Stream<Integer> stream1 = list1.stream();
		stream1.forEach( num -> System.out.println(num) );
		
		// 배열을 이용한 스트림
		int[] intArray = {1, 2, 3};
		IntStream intStream = Arrays.stream(intArray);
		System.out.println(intStream);
		
		// step02 : 중개 연산
		// filter() : 스트림 내 요소중 조건애 맞는 것을 필터 -> 반환
		List<String> fruitList = Arrays.asList("mango", "watermelon", "kiwi");
		// "m" 문자열이 포함되어 있는 것만 출력
		fruitList.stream()
				.filter(fruit -> fruit.contains("m"))
				.forEach(fruit -> System.out.println(fruit));
		
		// map() : 스트림 내 요소들이 특정 로직 수행 한 후, 새로운 스트림을 반환
		List<Integer> integerList = Arrays.asList(2, 1, 3);
		integerList.stream()
					.map(i -> i + 10)
					.forEach(i -> System.out.println(i));
		
		// sorted() : 정렬
		integerList.stream()
					.sorted()
					.forEach(v -> System.out.println(v));
		
		// step03 : 최종 연산
		// count, min, max, sum
		// collect : toList, toSet, toMap
		List<Integer> integerList2 = Arrays.asList(1, 3, 5, 2, 1, 5, 26, 3, 2, 1);
		System.out.println(integerList2.stream()
										.count());
		System.out.println(integerList2.stream()
										.collect(Collectors.toSet()));
		
		// 중계 연산
		Stream<Integer> numbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
	    
		//reduce : 누적된 값을 계산
		System.out.println(numbers.reduce((x, y) -> x + y ));
		// x에 누적값이 오고 y에 다음 차례 값이 대입됨
		
		// forEach : 요소 출력
		System.out.println();
		Arrays.asList(1, 2, 3).stream()	
								.forEach(System.out::println);
		
		// map : 지정 연산 이후 반환
		System.out.println();
		Arrays.asList(1, 2, 3).stream()
								.map(v -> v * v)
								.forEach(System.out::println);
		
		// skip : 이전 요소 잘라냄
		System.out.println();
		Arrays.asList(1, 2, 3).stream()
								.skip(2) // n : 스킵할 원소 갯수
								.forEach(System.out::println);
		
		// limit : 이후 요소 잘라냄
		System.out.println();
		Arrays.asList(1, 2, 3).stream()
								.limit(2) // n : 출력할 원소 갯수
								.forEach(System.out::println);
		
		// filter : 1~10까지의 자연수중 홀수만 출력
		System.out.println(); //asList로 배열부터 만듦
		Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
				.stream()
				.filter(i -> i % 2 != 0)
				.forEach(System.out::println);
		
		// sorted : 기본적으로 오름차순
		System.out.println();
		Arrays.asList(3, 1, 2)
				.stream()
				.sorted()
				.forEach(System.out::println);
	
		// 내림차순
		System.out.println();
		Arrays.asList(3, 1, 2)
				.stream()
				.sorted(Comparator.reverseOrder())
				.forEach(System.out::println);
		
		// distinct : 중복된 값은 삭제
		System.out.println();
		Arrays.asList(3, 1, 2, 4, 2, 5, 1, 1)
				.stream()
				.distinct()
				.forEach(System.out::println);
		
		// 최종 연산
		//count, sum // min, max, average : Optinal이라 get으로 가져와야 함
		// range로 100개 값 배열로 만들기
		System.out.println();
		int[] numList = IntStream.range(0, 100).toArray();
		System.out.println(numList.length);
		
		long sum22;
		sum22 = IntStream.of(1, 2, 3, 4, 12).count();
		System.out.println(sum22);
		
		OptionalInt min;
		min = IntStream.of(1, 2, 3, 4, 12).min();
		System.out.println(min.getAsInt());
		
		// reduce
		OptionalInt red;
		red = IntStream.range(0, 100).reduce((x, y) -> x + y);
		System.out.println(red.getAsInt());
	}
}


2. 에러

List와 ArrayList 를 혼동하여 예외를 발생 시킴


3. 보완 해야 할 것

asList, List, ArrayList, [ ] 가 헷갈림
Stream의 메소드는 쓰임이 다양하므로 꾸준한 사용으로 익혀야 함


4. 느낀점

개발일지를 쓰면서 내용이 많을 뿐더러 짧은 요약보다 코드 블럭 자체를 올리면서 다시 복기하는 방법이 좋은 것 같다.
map, filter 처럼 JavaScript에서 사용해본 것이 나와서 이번 파트는 이해가 빨라서 좋았다. 프로그래밍언어는 어느 정도 공통점이 있는 것 같다.

profile
잘해볼게요

0개의 댓글