Skip to content

Latest commit

ย 

History

History
416 lines (289 loc) ยท 14.5 KB

File metadata and controls

416 lines (289 loc) ยท 14.5 KB

Java 8 Tuturial (ko)

https://winterbe.com/posts/2014/03/16/java-8-tutorial/ ๋ฅผ ๋ฒˆ์—ญํ•˜์˜€์Šต๋‹ˆ๋‹ค.

INDEX

Default Methods for Interfaces

Java 8์€ default ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•ด interface์— non-abstract ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ Extension Methods๋ผ๊ณ ๋„ ํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์‹œ๋ฅผ ๋ณด๋ฉด, Formula์ธํ„ฐํŽ˜์ด์Šค์—์„œ abstract๋ฉ”์†Œ๋“œ calculate๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

interface Formula {
    double calculate(int a);
 
    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}
Formula formula = new Formula() {
    @Override
    public double calculate(int a) {
        return sqrt(a * 100);
    }
};
 
formula.calculate(100);     // 100.0
formula.sqrt(16);           // 4.0

Lambda Expressions

Java 8์—๋Š” anonymous objects๋ฅผ ๋งŒ๋“œ๋Š” ๋Œ€์‹ , ํ›จ์”ฌ ๋” ์งง์€ syntax๋ฅผ ๊ฐ€์ง„ Lambda expression์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์˜ ์™ผ์ชฝ๊ณผ ๊ฐ™์€ code๋ฅผ Lambda๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์˜ค๋ฅธ์ชฝ๊ณผ ๊ฐ™์ด ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Java ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ parameter type์„ ์•Œ๊ณ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž‘์„ฑ์„ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Java8 ์ด์ „ ์ฝ”๋“œ

List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
 
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});

Lambda ex 1

Collections.sort(names, (String a, String b) -> {
    return b.compareTo(a);
});

์ด code๋ฅผ ๋” ์งง๊ฒŒ ์ค„์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Lambda ex 2

Collections.sort(names, (String a, String b) -> b.compareTo(a));

์—ฌ๊ธฐ์„œ ๋” ์ค„์ธ๋‹ค๋ฉด

Lambda ex 3

Collections.sort(names, (a, b) -> b.compareTo(a));

Functional Interfaces

์–ด๋–ป๊ฒŒ Lambda๊ฐ€ type์„ ์•Œ๊นŒ์š”? ๊ฐ Lambda๋Š” interface๋กœ ์ง€์ •๋œ type์— ๋Œ€์‘์ด ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฑธ Functional Interface๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๋ฐ, ์ •ํ™•ํ•˜๊ฒŒ ํ•˜๋‚˜์˜ abstract ๋ฉ”์†Œ๋“œ ์„ ์–ธ์„ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ type์˜ Lambda๋Š” ์•ž์„œ ๋งํ•œ abstract ๋ฉ”์†Œ๋“œ์™€ ๋งค์นญ์ด ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ default ๋ฉ”์†Œ๋“œ๋Š” ์ถ”์ƒ์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— functional interface์— ์ž์œ ๋กญ๊ฒŒ ์ถ”๊ฐ€ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ abstract ๋ฉ”์†Œ๋“œ๋งŒ์„ ํฌํ•จํ•œ ์ž„์˜์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ Lambda๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ธํ„ฐํŽ˜์ด์Šค์— @FunctionalInterface ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์–ด๋…ธํ…Œ์ด์…˜์„ ์•Œ์•„์ฐจ๋ ค์„œ ๋‘๋ฒˆ์งธ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค ๋•Œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

Method and Constructor References

functional interfaces์—์„œ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ code๋Š” static ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๋” ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Java8์—์„œ๋Š” :: ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฉ”์„œ๋“œ๋‚˜ ์ƒ์„ฑ์ž์˜ ์ฐธ์กฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ๊ฐ€ static method๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

Converter<String, Integer> converter = (from) -> Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

object ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

class Something {
    String startsWith(String s) {
        return String.valueOf(s.charAt(0));
    }
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);    // "J"

:: ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ƒ์„ฑ์ž์— ๋Œ€ํ•œ ์ž‘์—…๋„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด Person ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๊ณ  PersonFactory ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์—ˆ์„ ๋•Œ, ์ƒ์„ฑ์ž ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ค๋‹ˆ๋‹ค.

Person::new๋ฅผ ํ†ตํ•ด Person ์ƒ์„ฑ์ž์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ Java ์ปดํŒŒ์ผ๋Ÿฌ๋Š” PersonFactory.create์™€ ๋งค์นญํ•˜์—ฌ ์˜ฌ๋ฐ”๋ฅธ ์ƒ์„ฑ์ž๋ฅผ ์ž๋™์œผ๋กœ ๋งค์นญํ•ด์ค๋‹ˆ๋‹ค.

class Person {
    String firstName;
    String lastName;
 
    Person() {}
 
    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");

Lambda Scopes

lambda ์‹์—์„œ ์™ธ๋ถ€ ๋ฒ”์œ„(outer scope)๋ฅผ ๊ฐ€์ง„ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์€ anonymous object์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋กœ์ปฌ ์™ธ๋ถ€ ์Šค์ฝ”ํ”„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ instance ํ•„๋“œ, static ๋ณ€์ˆ˜์—์„œ final ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Accessing local variables

๋‹ค์Œ๊ณผ ๊ฐ™์ด lambda ํ‘œํ˜„์‹์˜ ์™ธ๋ถ€ ๋ฒ”์œ„์—์„œ final ๋กœ์ปฌ ๋ณ€์ˆ˜๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ final์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ๋ณ€์ˆ˜๋„ ์ปดํŒŒ์ผ ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ์•”๋ฌต์ ์œผ๋กœ final์œผ๋กœ ์ธ์‹ํ•˜๊ณ  ์ฝ”๋“œ๊ฐ€ ์ปดํŒŒ์ผ๋œ๋‹ค๋Š” ์ ์„ ์ธ์ง€ํ•˜๊ณ  ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

int num = 1;   //final int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num); //implicitly final
 
stringConverter.convert(2);     // 3
num = 3                //COMPILE ERROR!!

Accessing fields and static variables

์ธ์Šคํ„ด์Šค ํ•„๋“œ์™€ static ๋ณ€์ˆ˜๋Š” ๋กœ์ปฌ ๋ณ€์ˆ˜์™€ ๋ฐ˜๋Œ€๋กœ lambda ์‹ ๋‚ด์—์„œ์˜ ์ฝ๊ณ  ์“ฐ๊ธฐ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

class Lambda4 {
    static int outerStaticNum; //static variable
    int outerNum;                             //instance field
 
    void testScopes() {
        Converter<Integer, String> stringConverter1 = (from) -> {
            outerNum = 23;
            return String.valueOf(from);
        };
 
        Converter<Integer, String> stringConverter2 = (from) -> {
            outerStaticNum = 72;
            return String.valueOf(from);
        };
    }
}

Accessing Default Interface Methods

deafult ๋ฉ”์„œ๋“œ๋Š” lambda ์‹์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์ œ๋Š” ์ปดํŒŒ์ผ์ด ์•ˆ๋˜๋ฉฐ, Formula๋Š” Deafult Method์—์„œ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

Formula formula = (a) -> sqrt( a * 100); //COMPILE ERROR!!

Built-in Functional Interfaces

JDK 1.8 API๋Š” ๋งŽ์€ ๋‚ด์žฅ functional interface๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. Comparator ๋‚˜ Runnable ์™€ ๊ฐ™์€ ์ผ๋ถ€๋Š” Java์˜ ๊ตฌ ๋ฒ„์ „์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋˜ ๊ฒƒ๋“ค์ž…๋‹ˆ๋‹ค. ์ด ๊ธฐ์กด์˜ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ™•์žฅ๋˜์–ด @FunctionalInterface ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด Lambda๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ JAVA 8 API๋Š” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒˆ๋กœ์šด functional interface๋“ค์ด ๋งŽ๊ณ , ์ด๋Ÿฌํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋“ค ์ค‘ ์ผ๋ถ€๋Š” Google Guava ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ž˜ ์†Œ๊ฐœ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋“ค์ด ์–ด๋–ป๊ฒŒ ์œ ์šฉํ•˜๊ฒŒ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ™•์žฅ๋˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์ž˜ ์•Œ๊ณ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

Predicates (๋งค๊ฐœ๋ณ€์ˆ˜ O, ๋ฐ˜ํ™˜๊ฐ’ O, ๋…ผ๋ฆฌ๊ฐ’ ๋ฐ˜ํ™˜)

Predicate๋Š” ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ boolean์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ์ž…๋‹ˆ๋‹ค. ์ด ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ด ๊ฐ€๋Šฅํ•œ default ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. (and, or, negate)

Predicate<String> predicate = (s) -> s.length() > 0;
 
predicate.test("foo");              // true
predicate.negate().test("foo");     // false
 
Predicate<Boolean> nonNull = Objects::nonNull;
nonNull.test(null); //false

Functions (๋งค๊ฐœ๋ณ€์ˆ˜ O, ๋ฐ˜ํ™˜๊ฐ’ O, ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ˜ํ™˜)

Function์€ ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. Function <๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…, ๋ฐ˜ํ™˜๊ฐ’ ํƒ€์ž…>๊ณผ ์‚ฌ์šฉํ•˜๋ฉฐ, apply ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. deafault ๋งค์„œ๋“œ๋“ค์„ chain multiple functions๋กœ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (compose, andThen)

Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
 
backToString.apply("123");     // "123"

Suppliers (๋งค๊ฐœ๋ณ€์ˆ˜ X, ๋ฐ˜ํ™˜๊ฐ’ O)

Supplier๋Š” ์ฃผ์–ด์ง„ generic ํƒ€์ž…์˜ ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, get ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. Functions์™€๋Š” ๋‹ฌ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒƒ์ด ํŠน์ง•์ž…๋‹ˆ๋‹ค.

Supplier<Person> personSupplier = Person::new;
personSupplier.get();   // new Person

Consumers (๋งค๊ฐœ๋ณ€์ˆ˜ O, ๋ฐ˜ํ™˜๊ฐ’ X)

Consumer๋Š” ํ•˜๋‚˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ํ•ฉ๋‹ˆ๋‹ค. Lambda ์‹์„ ํšจ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker")); //Hello, Luke ์ถœ๋ ฅ

Comparators

Comparator๋Š” ๋น„๊ต ๊ทœ์น™์„ ์ •ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ, ์ •๋ ฌ ๊ทœ์น™์„ ์ •ํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ตฌ๋ฒ„์ „์˜ Java์—์„œ๋„ ์‚ฌ์šฉ๋˜์—ˆ๊ณ , Java8์—์„œ ์ธํ„ฐํŽ˜์ด์Šค์— ๋‹ค์–‘ํ•œ default method๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);
 
Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");
 
comparator.compare(p1, p2);             // > 0
comparator.reversed().compare(p1, p2);  // < 0

Optionals

Optional์€ functional interface๊ฐ€ ์•„๋‹ˆ๋ผ NullPointerException์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ niffy ์œ ํ‹ธ๋ฆฌํ‹ฐ์ž…๋‹ˆ๋‹ค. null์ด ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฐ’์„ ๊ฐ์‹ธ๋Š” Wrapper ํด๋ž˜์Šค๋กœ, NPE๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

Optional<String> optional = Optional.of("bam");       //of():null์ด ์•„๋‹Œ ๋ช…์‹œ๋œ ๊ฐ’์„ ๊ฐ€์ง€๋Š” Optional ๊ฐ์ฒด ๋ฐ˜ํ™˜
 
optional.isPresent();           // true               //Optional ๊ฐ์ฒด์— ์ €์žฅ๋œ ๊ฐ’์ด null์ธ์ง€ ํ™•์ธ
optional.get();                 // "bam"      //Optional ๊ฐ์ฒด์— ์ €์žฅ๋œ ๊ฐ’ ์ ‘๊ทผ
optional.orElse("fallback");    // "bam"      //์ €์žฅ๋œ ๊ฐ’์ด ์กด์žฌ-> ๊ฐ’๋ฐ˜ํ™˜, ์—†์œผ๋ฉด-> ์ธ์ˆ˜ ๊ฐ’ ๋ฐ˜ํ™˜
 
optional.ifPresent((s) -> System.out.println(s.charAt(0)));     // "b"

Streams

java.util.Stream์€ ํ•˜๋‚˜ ์ด์ƒ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” elements๋“ค์˜ sequence(์ˆœ์„œ๊ฐ€ ์žˆ๋Š” ์—ฐ๊ฒฐ?)์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. Stream ์—ฐ์‚ฐ์€์€ intermediate์ด๊ฑฐ๋‚˜ terminal ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

terminal ์—ฐ์‚ฐ์€ ํŠน์ • ํƒ€์ž…์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ˜๋ฉด, intermediate ์—ฐ์‚ฐ์€ Stream ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ์—ฐ์†์ ์œผ๋กœ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Stream์€ list๋‚˜ set (map์€ ์•ˆ๋จ)๊ณผ ๊ฐ™์€ java.util.Collection๋ฅผ source๋กœ ํ•ด์„œ ๋งŒ๋“ค์–ด์ง€๋ฉฐ, sequential ํ•˜๊ฑฐ๋‚˜ parallelํ•˜๊ฒŒ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์œ ๋ช…ํ•œ stream ์—ฐ์‚ฐ๋“ค์ž…๋‹ˆ๋‹ค. Filter, Sorted, Map์€ intermediate ์—ฐ์‚ฐ์ด๊ณ , Match, Count, Reduce๋Š” terminal ์—ฐ์‚ฐ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋กœ ์‰ฝ๊ฒŒ ์ดํ•ด๊ฐ€ ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์—, ์ž์„ธํ•œ ์„ค๋ช…์€ ์ƒ๋žตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

//stringCollection ์€ List๋กœ, {"ddd2", "aaa2", "bbb1", "aaa1", "bbb3", "ccc", "bbb2", "ddd1"}์˜ ์›์†Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ

Filter (ํ•„ํ„ฐ)

stringCollection
    .stream()
    .filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
 
// "aaa2", "aaa1"

Sorted (์ •๋ ฌ)

stringCollection
    .stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);
 
// "aaa1", "aaa2"

sorted๋Š” ์ •๋ ฌ๋œ view๋งŒ ๋ณด์—ฌ์ค„ ๋ฟ, ์›์†Œ๊ฐ€ ์ •๋ ฌ๋œ ์ƒํƒœ๋กœ ์ €์žฅ๋˜์ง€๋Š” ์•Š์Œ

Map (๋ณ€ํ™˜?)

stringCollection
    .stream()
    .map(String::toUpperCase)
    .sorted((a, b) -> b.compareTo(a))
    .forEach(System.out::println);
 
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"

_____Match (์ผ์น˜ ์—ฌ๋ถ€ ํ™•์ธ)

boolean allStartsWithA =
    stringCollection
        .stream()
        .allMatch((s) -> s.startsWith("a"));
 
System.out.println(allStartsWithA);      // false
  • anyMatch ์‚ฌ์šฉ: true
  • nonMatch ์‚ฌ์šฉ: true

Count (์š”์†Œ ๊ฐœ์ˆ˜ longํ˜• ๋ฐ˜ํ™˜)

long startsWithB =
    stringCollection
        .stream()
        .filter((s) -> s.startsWith("b"))
        .count();
 
System.out.println(startsWithB);    // 3

Reduce (์š”์†Œ๋“ค์„ ์ค„์ด๋Š” ์—ฐ์‚ฐ)

Optional<String> reduced =
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);
 
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"

Parallel Streams

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด Stream์€ Sequentialํ•˜๊ฑฐ๋‚˜ Parallelํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Sequential Stream์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์€ ๋‹จ์ผ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋˜๋Š” ๋ฐ˜๋ฉด, Parallel Stream์€ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ์— ์ˆ˜ํ–‰ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ๋Š” Parallel Stream์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์–ผ๋งˆ๋‚˜ ์‰ฝ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

large list ์ƒ์„ฑ

int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
    UUID uuid = UUID.randomUUID();
    values.add(uuid.toString());
}

Sequential Sort

long t0 = System.nanoTime();
 
long count = values.stream().sorted().count();
System.out.println(count);
 
long t1 = System.nanoTime();
 
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));
 
// sequential sort took: 899 ms

Parallel Sort

long t0 = System.nanoTime();
 
long count = values.parallelStream().sorted().count(); //stream์„ parallelStream์œผ๋กœ ๋ฐ”๊ฟˆ
System.out.println(count);
 
long t1 = System.nanoTime();
 
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("parallel sort took: %d ms", millis));
 
// parallel sort took: 472 ms

Stream ๊ด€๋ จํ•ด์„œ ์•„๋ž˜ ๋งํฌ์— ๋” ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

https://futurecreator.github.io/2018/08/26/java-8-streams/

์ถ”๊ฐ€๋กœ ๋ณด๊ธฐ ์ข‹์€ ๊ธ€

๋žŒ๋‹ค๊ฐ€ ์ด๋Œ์–ด ๊ฐˆ ๋ชจ๋˜ Java