JAVA
27.Java Stream/Immutable
네스이
2022. 9. 21. 17:48
2022.09.20~21.화~수
1.Stream
package dev.syntax.step01;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
public class Apple {
private int weight = 0;
private String color = "";
@Override
public String toString() {
return String.format("Apple {color='%s', weight='%d'}", color, weight);
}
}
package dev.syntax.step01;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Basic {
public static void main(String[] args) {
List<Apple> inventory = Arrays.asList(
new Apple(80, "green"),
new Apple(155, "green"),
new Apple(120, "red"),
new Apple(75, "brown"),
new Apple(70, "red")
);
//Color가 green인 사과만 필터링
//Java 8 이전 방식
List<Apple> greenApples = filterGreenApples(inventory);
System.out.println(greenApples);
List<Apple> heavyApples = filterHeavyApples(inventory);
System.out.println(heavyApples);
//Java 8 이후 방식 - 메서드 참조를 통한 해결 방식
List<Apple> greenApples2 = filterApples(inventory, Basic::isGreenApples);
System.out.println(greenApples2);
List<Apple> heavyApples2 = filterApples(inventory, Basic::isHeavyApples);
System.out.println(heavyApples2);
//Java 8 이후 방식 - 람다 : 익명 함수를 통한 해결 방식
List<Apple> greenApples3 = filterApples(inventory, (Apple apple) -> "green".equals(apple.getColor()));
System.out.println(greenApples3);
List<Apple> heavyApples3 = filterApples(inventory, (Apple apple) -> apple.getWeight() > 150);
System.out.println(heavyApples3);
//무게가 80 미만이고, 색이 갈색인 사과 필터링
List<Apple> weiredApples = filterApples(inventory, (Apple apple) -> apple.getWeight() < 80 && "brown".equals(apple.getColor()));
System.out.println(weiredApples);
}
//filter : 특정 항목을 선택, 반환하는 동작
//Java 8 이전 방식
//모든 녹색 사과만 필터링해서 새로운 리스트로 반환
public static List<Apple> filterGreenApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory) {
if("green".equals(apple.getColor())) result.add(apple);
}
return result;
}
//150g 초과 사과만 필터링해서 새로운 리스트로 반환
public static List<Apple> filterHeavyApples(List<Apple> inventory) {
List<Apple> result = new ArrayList<>();
for(Apple apple : inventory) {
if(apple.getWeight() > 150) result.add(apple); //이 줄의 코드만 제외하고 나머지는 filterGreenApples와 다르지 않음
}
return result;
}
//Java 8 이후 방식 - 메서드 참조를 통한 해결 방식
public static boolean isGreenApples(Apple apple) {
return "green".equals(apple.getColor());
}
public static boolean isHeavyApples(Apple apple) {
return apple.getWeight() > 150;
}
public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> predictor) {
List<Apple> result = new ArrayList<>();
for (Apple apple : inventory) {
if(predictor.test(apple)) result.add(apple);
}
return result;
}
}
2.Immutable
-primitive
package dev.syntax.step01primitive;
//원시 타입(기본 자료형, Primitive type)만 필드로 가지고 있는 클래스
public class Cookie {
private int salt;
private String butter;
public Cookie(int salt, String butter) {
this.salt = salt;
this.butter = butter;
}
public int getSalt() {
return salt;
}
public void setSalt(int salt) {
this.salt = salt;
}
public String getButter() {
return butter;
}
public void setButter(String butter) {
this.butter = butter;
}
}
package dev.syntax.step01primitive;
public class ImmutableCookie {
private final int salt;
private final String butter;
public ImmutableCookie(int salt, String butter) {
this.salt = salt;
this.butter = butter;
}
public int getSalt() {
return salt;
}
public String getButter() {
return butter;
}
}
package dev.syntax.step01primitive;
public class CookieTest {
public static void main(String[] args) {
//원시 타입을 필드로 가지고 있는 가변 객체(인스턴스) coo
Cookie coo = new Cookie(2, "기본 버터");
coo.setSalt(10); //객체 내부의 값을 변경 가능
System.out.println(coo.getSalt()); //소금맛 쿠기 완성
//원시 타입을 필드로 가지고 있는 불변 객체 kie
ImmutableCookie kie = new ImmutableCookie(3, "진한 버터");
// kie.setSalt(20); //객체 내부의 필드값(salt)을 새로운 값으로 변경 불가
//불변 객체는 값의 조회만 가능, 기존의 객체 내부의 값(필드)의 상태는 변경불가
System.out.println(kie.getButter());
System.out.println(kie.getSalt());
}
}
-reference
package dev.syntax.step02reference;
public class Orange {
private int sugarLevel; //당도
private String country; //원산지
public Orange(int sugarLevel, String country) {
this.sugarLevel = sugarLevel;
this.country = country;
}
public int getSugarLevel() {
return sugarLevel;
}
public void setSugarLevel(int sugarLevel) {
this.sugarLevel = sugarLevel;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return "Orange [sugarLevel=" + sugarLevel + ", country=" + country + "]";
}
}
package dev.syntax.step02reference;
//참조 타입(Orange)
//참조 타입(Orange class)을 필드로 가지고 있는 OrangeCookie 클래스
public class OrangeCookie {
private final Orange orange;
private final int salt;
public OrangeCookie(Orange orange, int salt) {
this.orange = orange;
this.salt = salt;
}
public Orange getOrange() {
return orange;
}
public int getSalt() {
return salt;
}
}
package dev.syntax.step02reference;
public class Lemon {
final private int vitaminLevel; //당도
final private String country; //원산지
public Lemon(int vitaminLevel, String country) {
this.vitaminLevel = vitaminLevel;
this.country = country;
}
public int getvitaminLevel() {
return vitaminLevel;
}
public String getCountry() {
return country;
}
@Override
public String toString() {
return "Lemon [vitaminLevel=" + vitaminLevel + ", country=" + country + "]";
}
}
package dev.syntax.step02reference;
public class LemonCookie {
private final Lemon lemon;
private final int salt;
public LemonCookie(Lemon lemon, int salt) {
this.lemon = lemon;
this.salt = salt;
}
public Lemon getLemon() {
return lemon;
}
public int getSalt() {
return salt;
}
}
package dev.syntax.step02reference;
public class CookieTest {
public static void main(String[] args) {
Orange orange = new Orange(500, "Japan");
//일본산 오렌지로 만든 오렌지 쿠키 oCoo
OrangeCookie oCoo = new OrangeCookie(orange, 2);
// oCoo.setSalt(10); // ??
System.out.println("oCoo의 orange 정보 : " + oCoo.getOrange());
//Orange 클래스가 가지고 있는 setXxx()를 통해 미국산 오렌지로 변경
oCoo.getOrange().setCountry("USA");
System.out.println("oCoo의 orange 정보 : " + oCoo.getOrange());
//OrangeCookie의 객체 내부의 값이 변경됨
//-> 불변 클래스(OrangeCookie)가 가지고 있는 멤버 필드로 참조 타입인 Orange를
//가지고 있다면, 해당 참조 타입의 클래스(Orange)도 불변으로 작성해야 함
//불변 클래스 Lemon, LemonCookie
Lemon lemon = new Lemon(200, "Italy");
LemonCookie lemonCookie = new LemonCookie(lemon, 3);
Lemon lemonOfCookie = lemonCookie.getLemon();
// lemonOfCookie.setVitaminLevel(); //값 변경 불가
}
}
-array
package dev.syntax.step03array;
import java.util.Arrays;
//문자열 배열 타입으로 초콜릿 종류를 필드로 가지고 있는 가변(mutable)클래스
public class Cookie {
private final String[] chocolates;
public Cookie(String[] chocolates) {
this.chocolates = chocolates;
}
public String[] getChocolates() {
return chocolates;
}
@Override
public String toString() {
return "Cookie [chocolates=" + Arrays.toString(chocolates) + "]";
}
}
package dev.syntax.step03array;
public class CookieTest {
public static void main(String[] args) {
String[] chocolatesArray = { "dark", "milk", "white" };
Cookie coo = new Cookie(chocolatesArray);
System.out.println("coo의 초콜릿 성분 : " + coo);
chocolatesArray[0] = "ruby";
System.out.println("coo의 초콜릿 성분 : " + coo);
/*
* -> new Cookie(chocolatesArray);가 실행 되는 과정에서
* chocolatesArray의 참조값을 복사하여 넘겨주었기 때문(shallow copy, 얕은 복사)
* Cookie클래스에서 chocolates 필드를 final로 지정하여 setXxx() 없더라도,
* CookieTest라는 외부에서 생성자를 통해 넘겨준 chocolatesArray의 값을 통해
* coo 객체 내부의 필드인 chocolates의 값 변경이 가능한 상태
*/
//chocolates의 값을 병경하는 다른 방법
String[] chocolatesFromCoo = coo.getChocolates();
chocolatesFromCoo[0] = "ganache";
System.out.println(coo);
}
}
package dev.syntax.step03array;
import java.util.Arrays;
public class Biscuit {
private final String[] sugars;
public Biscuit(String[] sugars) {
// this.sugars = sugars; //전달받은 sugars의 참조값이 복사되어 외부에서도 변경 가능한 상태가 됨
this.sugars = Arrays.copyOf(sugars, sugars.length);
}
public String[] getSugars() {
//Biscuit 객체가 가진 참조값을 그대로 전달해버리기 때문에
//외부에서 변경 가능한 상태가 됨
// return sugars;
// if(sugars == null) return null;
// else sugars.clone();
//clone() 배열만 deep copy 나머지 shallow copy
return (sugars == null) ? null : sugars.clone();
}
@Override
public String toString() {
return "Biscuit [sugars=" + Arrays.toString(sugars) + "]";
}
}
package dev.syntax.step03array;
public class BiscuitTest {
public static void main(String[] args) {
String[] sugarArray = { "White", "Brown", "Dark" };
Biscuit bsc = new Biscuit(sugarArray);
//bsc 객체 내 sugar element값 변경 여부 테스트
sugarArray[0] = "Crystal";
System.out.println(bsc);
//->Arrays.copyOf()를 통해 주소값을 복사하였기 때문에
//서로 다른 인스턴스를 가리킴
String[] sugarsFromBsc = bsc.getSugars();
sugarsFromBsc[0] = "Cube";
System.out.println(bsc);
// Biscuit b = new Biscuit(null);
// System.out.println(b);
}
}
-list
package dev.syntax.step04list;
public class Chocolate {
private final String cacaoBean;
private final String cocoButter;
public Chocolate(String cacaoBean, String cocoButter) {
this.cacaoBean = cacaoBean;
this.cocoButter = cocoButter;
}
public String getCacaoBean() {
return cacaoBean;
}
public String getCocoButter() {
return cocoButter;
}
@Override
public String toString() {
return "Chocolate [cacaoBean=" + cacaoBean + ", cocoButter=" + cocoButter + "]";
}
}
package dev.syntax.step04list;
import java.util.ArrayList;
import java.util.List;
public class ChocoCookie {
private final List<Chocolate> chocolates;
public ChocoCookie(List<Chocolate> chocolates) {
// this.chocolates = chocolates;
this.chocolates = new ArrayList<Chocolate>(chocolates);
//넘겨받은 인수 chocolates를 그대로 사용하지 않고, 새로운 list로 생성하여 초기화
}
public List<Chocolate> getChocolates() {
// return chocolates;
//Java 9 이전, 값의 추가 / 수정이 불가한 리스트
// return Collections.unmodifiableList(chocolates);
//Java 9 이후 정적(static) 팩토리 메서드
return List.of(chocolates.toArray(new Chocolate[] {}));
}
@Override
public String toString() {
return "ChocoCookie [chocolates=" + chocolates + "]";
}
}
package dev.syntax.step04list;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CookieTest {
public static void main(String[] args) {
Chocolate abc = new Chocolate("아프리카산 카카오콩", "아프리카산 버터");
Chocolate hershey = new Chocolate("태국산 카카오콩", "태국산 버터");
List<Chocolate> chocolates = new ArrayList<>(Arrays.asList(abc, hershey));
ChocoCookie chikchok = new ChocoCookie(chocolates);
}
}