반응형

jdk 8

Function 인터페이스

  • 파라미터와 리턴이 존재하는 메소드 표현
/*Function<String, Integer> toInt = new Function<String, Integer>() {
    @Override
    public Integer apply(String value) {
        return Integer.parseInt(value);
    }
};*/

Function<String, Integer> toInt = (value) -> Integer.parseInt(value);
System.out.println(toInt.apply("100"));

Predicate 인터페이스

  • 파라미터와 리턴이 존재하는 메소드 표현
  • Function과의 차이는 boolean만 반환함
Predicate<Integer> isPositive = (value) -> value > 0;
System.out.println(isPositive.test(5));

Supplier 인터페이스

  • 리턴만 존재하는 메소드를 표현
Supplier<String> supplier = () -> "Hello World";
System.out.println(supplier.get());

Consumer 인터페이스

  • 리턴이 필요없는 메소드를 표현
Consumer<String> print = (value) -> System.out.println(value);
print.accept("Hello World");

사용자 지정 인터페이스

@FunctionalInterface
public interface CustomFunction<P1, P2, P3, R> {
    R apply(P1 param1, P2 param2, P3 param3);
}
CustomFunction<Integer, Integer, Integer, Integer> function = (param1, param2, param3) -> param1 + param2 + param3;
System.out.println(function.apply(1, 2, 3));

range()

// 0 ~ 9
IntStream.range(0, 10).forEach(i -> System.out.print(i + " "));

// 0 ~ 10
IntStream.rangeClosed(0, 10).forEach(i -> System.out.print(i + " "));

of()

// 1 ~ 5
Stream.of(1, 2, 3, 4, 5).forEach(i -> System.out.print(i + " "));

iterate()

// 무한으로 증가
//IntStream.iterate(0, i -> i + 1).forEach(i -> System.out.print(i + " "));
Stream.iterate(BigInteger.ZERO, i -> i.add(BigInteger.ONE)).forEach(i -> System.out.print(i + " "));

filter(), map()

// 아래 예제에서는 filter1에서 numbers를 모두 루프, filter2에서 numbers를 모두 루프하는 방식이 아님 (효율적으로 처리)
// 전체 numbers를 루프 돌리는 도중 filter1, filter2, map, filter3을 체크하는 구조
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Optional<Integer> result = numbers.stream()
        .filter(number -> number > 3)
        .filter(number -> number < 9)
        .map(number -> number * 2)
        .filter(number -> number > 10)
        .findFirst();

System.out.println(result);

collect()

List<String> resultList = Stream.of(1, 2, 3, 4, 5)
    .filter(i -> i > 2)
    .map(i -> i * 2)
    .map(i -> "#" + i)
    .collect(Collectors.toList());

Set<String> resultSet = Stream.of(1, 3, 3, 5, 5)
    .filter(i -> i > 2)
    .map(i -> i * 2)
    .map(i -> "#" + i)
    .collect(Collectors.toSet());

System.out.println(resultList);
System.out.println(resultSet);

joining()

String result1 = Stream.of("1", "2", "3").collect(Collectors.joining());
System.out.println(result1);

String result2 = Stream.of("1", "2", "3").collect(Collectors.joining(", "));
System.out.println(result2);

String result3 = Stream.of("1", "2", "3").collect(Collectors.joining(", ", "[", "]"));
System.out.println(result3);

distinct()

List<Integer> result = Stream.of(1, 2, 2, 3).distinct().collect(Collectors.toList());
System.out.println(result);

count()

long count = Stream.of(1, 2, 3).count();
System.out.println(count);

sum()

// IntStream의 경우 sum() 사용 가능
int sum = IntStream.of(1, 2, 3, 4, 5).sum();
System.out.println(sum);

reduce()

int sum = Stream.of(1, 2, 3, 4, 5).reduce(0, (total, current) -> total + current);

assertEquals(15, sum);

groupBy()

@RequiredArgsConstructor
@Getter
public class User {
    private final String type;
    private final String name;
    private final int age;
}
List<User> users = List.of(
    new User("google", "john", 25),
    new User("google", "tom", 30),
    new User("kakao", "jane", 28)
);
Map<String, List<User>> typeUsersMap = users.stream()
    .collect(Collectors.groupingBy(
        User::getType
    ));

assertEquals(2, typeUsersMap.get("google").size());
assertEquals(1, typeUsersMap.get("kakao").size());
Map<String, Long> typeCountMap = users.stream()
    .collect(Collectors.groupingBy(
        User::getType,
        Collectors.counting()
    ));

assertEquals(2, typeCountMap.get("google"));
assertEquals(1, typeCountMap.get("kakao"));
Map<String, Double> typeAgeMap = users.stream()
    .collect(Collectors.groupingBy(
        User::getType,
        Collectors.averagingDouble(User::getAge)
    ));

assertEquals(27.5, typeAgeMap.get("google"));
assertEquals(28.0, typeAgeMap.get("kakao"));

parallel()

  • 멀티 코어 프로세싱 처리로 속도가 빠름
  • 동기화 문제가 발생할 수 있음
long start = System.currentTimeMillis();

Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8)
        .stream()
        .parallel()
        .map(i -> {
            try { Thread.sleep(1); } catch (InterruptedException e) { }
            return i;
        })
        .forEach(i -> System.out.print(i + " "));

System.out.println();
System.out.println(System.currentTimeMillis() - start);

parallelStream()

  • stream() + parallel()
long start = System.currentTimeMillis();

Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8)
        .parallelStream()
        .map(i -> {
            try { Thread.sleep(1); } catch (InterruptedException e) { }
            return i;
        })
        .forEach(i -> System.out.print(i + " "));

System.out.println();
System.out.println(System.currentTimeMillis() - start);

참고

jdk 9

불변 Collection 생성 메서드 제공

List<String> immutableList = List.of("1", "2", "3");
Map<String, Integer> immutableMap = Map.of("1", 1, "2", 2, "3", 3);

try-with-resources 개선

void tryWithResourcesByJava7() throws IOException {
    BufferedReader reader1 = new BufferedReader(new FileReader("test.txt"));
    try (BufferedReader reader2 = reader1) {
        // do something
    }
}

// final or effectively final이 적용되어 reader 참조를 사용할 수 있음
void tryWithResourcesByJava9() throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader("test.txt"));
    try (reader) {
        // do something
    }
}

인터페이스 내에서 private 메서드 사용 가능

interface Calculator {
    int plus(int a, int b);

    default int minus(int a, int b) {
        print();
        return a - b;
    }

    private void print() {
        System.out.println("Hello Minus");
    }
}

class BasicCalculator implements Calculator {
    @Override
    public int plus(int a, int b) {
        return a + b;
    }
}

Calculator calculator = new BasicCalculator();

System.out.println(calculator.plus(1, 2));
System.out.println(calculator.minus(1, 2));

Reactive Stream 도입

@RequiredArgsConstructor
@Data
public class Student {
    private final int id;
    private final String name;
}
public class StudentSubscriber implements Flow.Subscriber<Student> {
    public static int count = 0;
    private Flow.Subscription subscription;

    @Override
    public void onSubscribe(Flow.Subscription subscription) {
        this.subscription = subscription;
        this.subscription.request(1);
    }

    @Override
    public void onNext(Student student) {
        System.out.println("process : " + student);
        count++;
        this.subscription.request(1);
    }

    @Override
    public void onError(Throwable e) {
        e.printStackTrace();
    }

    @Override
    public void onComplete() {
        System.out.println("complete when publisher closed");
    }
}
List<Student> students = List.of(
    new Student(1, "john"),
    new Student(2, "tom"),
    new Student(3, "jane")
);

SubmissionPublisher<Student> publisher = new SubmissionPublisher<>();
publisher.subscribe(new StudentSubscriber());

students.forEach(publisher::submit);

while (StudentSubscriber.count != students.size()) {
    System.out.println("wait");
    Thread.sleep(1000);
}

publisher.close();
System.out.println("finish");
wait
process : Student(id=1, name=john)
process : Student(id=2, name=tom)
process : Student(id=3, name=jane)
finish
complete when publisher closed

Stream Method 추가

  • iterate()
    IntStream
        .iterate(0, i -> i < 5, i -> i + 1)
        .forEach(i -> System.out.print(i + " ")); //  1 2 3 4
    
  • takeWhile()
    Stream
        .of(1, 2, 3, 4, 5, 6)
        .takeWhile(i -> i <= 3)
        .forEach(i -> System.out.print(i + " ")); //  1 2 3
    
  • dropWhile()
    Stream
        .of(1, 2, 3, 4, 5, 6)
        .dropWhile(i -> i <= 3)
        .forEach(i -> System.out.print(i + " ")); //  4 5 6
    

참고

jdk 10

Local-variable type inference

var numbers = List.of(1, 2, 3);

for (var number : numbers) {
    System.out.println(number);
}

타입 추론이 안되는 경우

var x = null; // null assign 불가
var x; // 초기화 없이 사용 불가
public var x = 10; // local 변수가 아닌 경우
var x = {1, 2, 3}; // array initializer 불가
public void add(var a, var b) {} // 메소드 인자로 사용 불가

참고

jdk 11

(JEP 321) HTTP Client (Standard)

  • jdk9에서 인큐베이터 패키지로 추가, jdk11에서 정식 패키지로 추가
  • Non-Blocking request and response 지원 (with CompletableFuture)
  • Backpressure 지원(java.util.concurrent.Flow 패키지를 통해 RX Flow를 구현체에 적용)
  • HTTP/2 지원
  • Factory method 형태로 지원
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("http://localhost:8080/api/tests"))
    .timeout(Duration.ofMinutes(1))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"name\" : \"john\"}"))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

System.out.println(response.statusCode());
System.out.println(response.headers());
System.out.println(response.body());
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("http://localhost:8080/api/tests"))
    .timeout(Duration.ofMinutes(1))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString("{\"name\" : \"john\"}"))
    .build();

client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
    .thenApply(response -> {
        System.out.println(response.statusCode());
        System.out.println(response.headers());
        return response;
    })
    .thenApply(HttpResponse::body)
    .thenAccept(System.out::println);

참고

jdk 12

(JEP325) Switch Expressions (Preview)

  • jdk13에서 제공될 예정
  • 예시
    switch (alphabet) {
        case "a", "b" -> System.out.println("a, b");
        case "c" -> System.out.println("c");
    }
    
    int number = switch (alphabet) {
        case "a", "b" -> 1;
        case "c" -> 2;
        default -> throw new IllegalStateException("others");
    };
    

String 클래스

System.out.println("Hello\nWorld".indent(4));
System.out.println("Hello world".transform(s -> s.replace("Hello", "Bye")).toString());

참고

jdk 13

Text Blocks

String json = """
    {
        "name": "john",
        "age": 25
    }
    """;

System.out.println(json);

Switch Expressions

  • 반환문이 break에서 yield로 변경됨
String result = switch (number) {
    case 1:
    case 2:
        yield "number1 or 2";
    default:
        yield "default";
};

참고

jdk 14

JEP 305: Pattern Matching for instanceof (Preview)

  • instanceof 체크 후 캐스팅 과정 필요없어짐
// before
if (obj instanceof String) {
    String text = (String) obj;
}

// after
if (obj instanceof String s) {
    if (s.length() > 2) {
        // ...
    }
}

JEP 359: Records (Preview)

public record Student(
    String name,
    int age
) {}

Student student = new Student("john", 24);

System.out.println(student.name());
System.out.println(student.age());

참고

반응형

'Development > Java' 카테고리의 다른 글

[Java] Markdown 파싱  (0) 2020.12.28
[Java] VisualVM 사용하기  (0) 2019.09.30
[Java] XML 파싱  (0) 2019.03.20
[Java] Json Handling(with Jackson)  (0) 2019.03.20
[Java] HTML 파싱  (0) 2019.03.20

+ Recent posts