curl 유용한 사용법 몇가지

curl 유용한 사용법 몇가지
curl은 REST API 방식으로 개발하는 경우 필수적인 요소인듯 싶다.
몇가지 간단한 사용법만 알아보자.

1. GET 방식으로 보내기
curl http://host_address:port

2. 헤더정보 받기.
curl -i http://host_address:port

3. 오직 헤더만 받기.
curl -s    -o /dev/null    -w "%{http_code}\n" http://host_address:port

4. Header 추가해서 요청하기.
curl -H "Content-Type: application/json" http://host_address::port

5. POST 방식으로 보내기
curl -X POST http://host_address:port -d '{"key":"value", "key2":"value2"}'

6. 서버의 파일 저장하기. (내가 원하는 이름으로)
curl -o filename.txt http://host_address:port/fileurl

7. 서버의 파일 다운로드 하기 (서버에 있는 이름 그대로)
curl -O http://host_address:port/fileurl

8. 처리 시간 알아보기.
curl http://host_address:port/url -w "%{time_connect} + %{time_starttransfer} = %{time_total}"

%{time_connect} : 서버 접속시간
%{time_starttransfer} : 파일 전송시간
%{time_total} : 총 처리되어서 전송된 시간 (여기에는 서버 내부에서 실행된 시간도 포함이 된다. )

기타 나머지 : 
> curl --manual 


Available --write-out variables

Some of these variables are not available in really old curl versions.
  • %{content_type} shows the Content-Type of the requested document, if there was any.
  • %{filename_effective} shows the ultimate filename that curl writes out to. This is only meaningful if curl is told to write to a file with the --remote-name or --output option. It's most useful in combination with the --remote-header-name option.
  • %{ftp_entry_path} shows the initial path curl ended up in when logging on to the remote FTP server.
  • %{response_code} shows the numerical response code that was found in the last transfer.
  • %{http_connect} shows the numerical code that was found in the last response (from a proxy) to a curl CONNECT request.
  • %{local_ip} shows the IP address of the local end of the most recently done connection—can be either IPv4 or IPv6
  • %{local_port} shows the local port number of the most recently made connection
  • %{num_connects} shows the number of new connects made in the recent transfer.
  • %{num_redirects} shows the number of redirects that were followed in the request.
  • %{redirect_url} shows the actual URL a redirect would take you to when an HTTP request was made without -L to follow redirects.
  • %{remote_ip} shows the remote IP address of the most recently made connection—can be either IPv4 or IPv6.
  • %{remote_port} shows the remote port number of the most recently made connection.
  • %{size_download} shows the total number of bytes that were downloaded.
  • %{size_header} shows the total number of bytes of the downloaded headers.
  • %{size_request} shows the total number of bytes that were sent in the HTTP request.
  • %{size_upload} shows the total number of bytes that were uploaded.
  • %{speed_download} shows the average download speed that curl measured for the complete download in bytes per second.
  • %{speed_upload} shows the average upload speed that curl measured for the complete upload in bytes per second.
  • %{ssl_verify_result} shows the result of the SSL peer certificate verification that was requested. 0 means the verification was successful.
  • %{time_appconnect} shows the time, in seconds, it took from the start until the SSL/SSH/etc connect/handshake to the remote host was completed.
  • %{time_connect} shows the time, in seconds, it took from the start until the TCP connect to the remote host (or proxy) was completed.
  • %{time_namelookup} shows the time, in seconds, it took from the start until the name resolving was completed.
  • %{time_pretransfer} shows the time, in seconds, it took from the start until the file transfer was just about to begin. This includes all pre-transfer commands and negotiations that are specific to the particular protocol(s) involved.
  • %{time_redirect} shows the time, in seconds, it took for all redirection steps including name lookup, connect, pre-transfer and transfer before the final transaction was started. time_redirect shows the complete execution time for multiple redirections.
  • %{time_starttransfer} shows the time, in seconds, it took from the start until the first byte was just about to be transferred. This includes time_pretransfer and also the time the server needed to calculate the result.
  • %{time_total} shows the total time, in seconds, that the full operation lasted. The time will be displayed with millisecond resolution.
  • %{url_effective} shows the URL that was fetched last. This is particularly meaningful if you have told curl to follow Location: headers (with -L).

Java 8 In Action - Design Pattern

Java 8 In Action - Design Pattern

Lambda를 이용하여 기존 디자인패턴을 변경해보기

from Java 8 In Action

1. 전략패턴 


1.1 일반적인 전략패턴 개발방식 

public interface ValidationStrategy {
boolean execute(String s);
}

public class IsAllowerCase implements ValidationStrategy {
public boolean execute(String s) {
return s.match("[a-z]+");
}
}

public class IsNumeric implements ValidationStrategy {
public boolean execute(String s) {
return s.matches("\\d+");
}
}

public class Validator {
private final ValidationStrategy strategy;

public Validator(ValidationStrategy v) {
this.strategy = v;
}

public boolean validate(String s) {
return strategy.execute(s);
}
}

Validator numericValidator = new Validator(new IsNumeric());
boolean b1 = numericValidator.validate("aaa");

Validator lowerCaseValidator = new Validator(new IsAllLowerCase());
boolean b2 = lowerCaseValidator.validate("bbb");


1.2 람다를 이용한 개발 방식

Validator numericValidator = new Validator((String s) -> s.matches("[a-z]+"));
boolean b1 = numericValidator.validate("aaa");

Validator lowerCaseValidator = new Validator((String a) -> s.match("\\d+"));
boolean b2 = lowerCaseValidator.validate("bbb");

2. Template Method


2.1 일반적인 템플릿 메소드 방식
abstract class OnlineBanking {
public void processCustomer(int id) {
Customer c = Database.getCustomerWithId(id);
makeCustomerHappy(c);
}

abstract void makeCustomerHappy(Customer c);
}

2.2 람다를 이용한 개발 방식

public void processCustomer(int id, Consumer<Customer> makeCustomerHappy) {
Customer c = Database.getCustomerWithId(id);
makeCustomerHappy.accept(c);
}

new OnlineBankingLambda().processCustomer(1234, (Customer c) -> System.out.println("Hello " + c.getName()));

3. Observer


3.1 일반적인 옵저버 패턴

interface Observer {
void notify(String tweet);
}

class NYTimes implements Observer {
public void notify(String tweet) {
if (tweet != null && tweet.contains("money")) {
System.out.println("Breaking news in NY! " + tweet);
}
}
}

class Guardian implements Observer {
public void notify(String tweet) {
if (tweet != null && tweet.contain("queen")) {
System.out.println("Yet another news in London... " + tweet);
}
}
}

class LeMonde implements Observer {
public void notify(String tweet) {
if (tweet != null && tweet.contains("wine")) {
System.out.println("Today cheese, wine and news! " + tweet);
}
}
}

interface Subject {
void registerObserver(Observer o);
void notifyObservers(String tweet);
}

class Feed implements Subject {
private final List<Observer> observers = new ArrayList<>();

public void registerObserver(Observer o) {
this.observers.add(o);
}

public void notifyObservers(String tweet) {
observers.forEach(o -> o.notify(tweet));
}
}

Feed f = new Feed();
f.registerObserver(new NYTimes());
f.registerObserver(new Guardian());
f.registerObserver(new LeMonde());
f.notifyObservers("The queen said her favorite book is Java 8 in Action");


3.2 람다 방식의 개발

f.registerObserver((String tweet) -> {
if (tweet != null && tweet.contains("money")) {
System.out.println("Breaking news in NY! " + tweet);
}
});

f.registerObserver((String tweet) -> {
if (tweet != null && tweet.contains("queen")) {
System.out.println("Yet another news in London... " + tweet);
}
});


4. Chain of Responsibility


4.1 일반적인 방식의 COR방식

public abstract class ProcessingObject<T> {

protected ProcessingObject<T> successor;

public void setSucessor(ProcessingObject<T> successor) {
this.successor = successor;
}

public T handle(T input) {
T r = handleWork(input);
if (successor != null) {
return successor.handle(r);
}
return r;
}

abstract protected T handleWork(T input);
}

public class HeaderTextProcessing extends ProcessingObject<String> {
public String handleWork(String text) {
return "From Raoul, Mario and Alan: " + text;
}
}

public class SpellCheckerProcessing extends ProcessingObject<String> {
public String handleWork(String text) {
return text.replaceAll("labda", "lambda");
}
}

ProcessingObject<String> p1 = new HeaderTextProcessing();
ProcessingObject<String> p2 = new SpellCheckerProcessing();

p1.setSuccessor(p2);

String result = p1.handle("Aren't labdas really sexy?!!");
System.out.println(result);

4.2 람다 방식

UnaryOperator<String> headerProcessing = (String text) -> "From Raoul, Mario and Alan: " + text;
UnaryOperator<String> spellCheckerProcessing = (String text) -> text.replaceAll("labda", "lambda");
Function<String, String> pipeline = handleProcessing.andThen(spellCheckerProcessing);

String result = pipeline.apply("Aren't labdas really sexy?!!");

5. Factory


5.1 일반적인 팩토리

public class ProductFactory{
public static Product createProduct(String name) {
switch(name) {
case "loan":
return new Loan();
case "stock":
return new Stock();
case "bond":
return new Bond();
default:
throws new RuntimeException("No such product " + name);
}
}
}

Product p = ProductFactory.createProduct("loan");

5.2 람다 방식

Supplier<Product> loanSupplier = Lona::new;
Loan loan = loanSupplier.get();

final static Map<String, Supplier<Product>> map = new HashMap<>();
static {
map.put("loan", Loan::new);
map.put("stock", Stock::new);
map.put("bond", Bond::new);
}

public static Product createProduct(String name) {
Suppler<Product> p = map.get(name);
if (p != null) return p.get();
throw new IllegalArgumentException("No Such product " + name);
}

ForkJoinPool 예제

ForkJoinPool 예제

ForkJoinPool

ForkJoinPool 은 Java7부터 사용가능한 Java Concurrency 툴이며, 동일한 작업을 여러개의 Sub Task로 분리(Fork)하여 각각 처리하고, 이를 최종적으로 합쳐서(Join) 결과를 만들어내는 방식이다.

ForkJoinPool에는 2가지 인터페이스를 제공한다. 

- RecursiveAction : 

> RecursiveAction은 결과를 반환하지 않는 태스크를 말한다. 특정 작업을 분할하고, 처리를 수행하면서 해당 작업을 내부에서 처리한다. 

예제 : 
package com.company.api_simulation;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class APICallRecursiveAction extends RecursiveAction {

    public static final int DIVIDE_COUNT = 5;

    List<RequestObject> requestObjects = null;

    public APICallRecursiveAction(List<RequestObject> requestObjects) {
        this.requestObjects = requestObjects;
    }

    @Override
    protected void compute() {
        if (requestObjects.size() > DIVIDE_COUNT) {
            ForkJoinTask.invokeAll(divideSubActions());
        }
        else {
            processAPICall(requestObjects);
        }
    }

    private void processAPICall(List<RequestObject> requestObjects) {
        requestObjects.forEach(System.out::println);
    }

    private List<APICallRecursiveAction> divideSubActions() {

        List<RequestObject> preList = requestObjects.subList(0, requestObjects.size() / 2);
        List<RequestObject> postList = requestObjects.subList(requestObjects.size() / 2, requestObjects.size());

        List<APICallRecursiveAction> list = new ArrayList<>();
        list.add(new APICallRecursiveAction(preList));
        list.add(new APICallRecursiveAction(postList));

        return list;

    }

    public static void main(String[] args) {
        List<RequestObject> lists = new ArrayList<>();
        lists.add(new RequestObject(1L, 1L, "First1"));
        lists.add(new RequestObject(2L, 1L, "First2"));
        lists.add(new RequestObject(10L, 5L, "First10"));
        lists.add(new RequestObject(6L, 3L, "First6"));
        lists.add(new RequestObject(3L, 2L, "First3"));
        lists.add(new RequestObject(4L, 2L, "First4"));
        lists.add(new RequestObject(11L, 6L, "First11"));
        lists.add(new RequestObject(8L, 4L, "First8"));
        lists.add(new RequestObject(5L, 3L, "First5"));
        lists.add(new RequestObject(7L, 4L, "First7"));
        lists.add(new RequestObject(9L, 5L, "First9"));
        lists.add(new RequestObject(12L, 6L, "First12"));

        APICallRecursiveAction action = new APICallRecursiveAction(lists);
        ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
        forkJoinPool.invoke(action);
    }
}

- RecursiveTask : 

> 기대하는 바와 같이 이 작업은 결과를 반환하는 태스크를 Fork와 Join으로 처리한다. 

예제 : 
package com.company;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

public class CustomRecursiveTask extends RecursiveTask<Integer> {

    private int[] arr;

    private static final int THRESHOLD = 4;

    public CustomRecursiveTask(int[] arr) {
        this.arr = arr;
    }

    @Override
    protected Integer compute() {
        if (arr.length > THRESHOLD) {
            return ForkJoinTask.invokeAll(createSubtasks())
                    .stream()
                    .mapToInt(ForkJoinTask::join)
                    .sum();
        } else {
            return processing(arr);
        }
    }

    private Collection<CustomRecursiveTask> createSubtasks() {
        List<CustomRecursiveTask> dividedTasks = new ArrayList<>();
        dividedTasks.add(new CustomRecursiveTask(
                Arrays.copyOfRange(arr, 0, arr.length / 2)));
        dividedTasks.add(new CustomRecursiveTask(
                Arrays.copyOfRange(arr, arr.length / 2, arr.length)));
        return dividedTasks;
    }

    private Integer processing(int[] arr) {
        return Arrays.stream(arr)
//                .filter(a -> a > 10 && a < 27)
                .map(a -> a * 10)
                .sum();
    }

    public static void main(String[] args) {
        ForkJoinPool commonPool = ForkJoinPool.commonPool();

        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        CustomRecursiveTask task = new CustomRecursiveTask(arr);

//        commonPool.execute(task);
//        Integer result = task.join();
//        System.out.println(result);

//        System.out.println(commonPool.invoke(task));

        System.out.println(task.compute());
    }
}

결론적으로

Fork Join Pool은 우리가 원하는 작업을 Divided and Conquer 방식으로 처리할 수 있도록 해준다. 

실제 프로그램에서 사용할때에는 외부 API 를 여러번 호출해야하는 상황에서 작업을 분리하여 호출할 수도 있을 것이다. 

Eclipse MAT (Memory Analysis Tool) 사용하기

1. MAT 다운로드 사이트
http://www.eclipse.org/mat/downloads.php

2. 다음 코드를 작성해서 테스트 해보기

import java.util.ArrayList;
import java.util.List;

public class Main {

    List<String> memoryLeakList = new ArrayList<>();

    public static void main(String[] args) {

        Main mainObj = new Main();
        while(true) {
            mainObj.memoryLeakList.add("Memory......");
        }

    }
}


3. JVM Option으로 다음과 같이 설정한다.
-XX:+HeapDumpOnOutOfMemoryError


4. MAT 메모리 설정을 매우 크게 준다. 
Eclipse/MemoryAnalyzer.ini 파일을 다음과 같이 메모리를 올려준다. 

-startup
../Eclipse/plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar
--launcher.library
../Eclipse/plugins/org.eclipse.equinox.launcher.cocoa.macosx.x86_64_1.1.300.v20150602-1417
-vmargs
-Xmx10g
-Dorg.eclipse.swt.internal.carbon.smallFonts
-XstartOnFirstThread




5. 분석화면


내용을 보면 Main.main 프로그램을 실행하다가 OutObMemoryError이 발생했다.

Java9 새로운 기능

Java9 새로운 기능

from : http://www.journaldev.com/13121/java-9-features-with-examples

1. Java9 다운로드 받는곳 

https://jdk9.java.net/download/

2. JAVA9의 주요 기능 

2.1 Java 9 REPL [Read Evaluate Print Loop] : (JShell)

- Java 9 는 REPL이라는 jShell을 제공한다.
- 이를 통해 자바도 인터렉티브한 테스트와 실행을 할 수 있다.
KIDOui-iMac:~ KIDO$ jshell
|  Welcome to JShell -- Version 9-ea
|  For an introduction type: /help intro
jshell> int a = 10
a ==> 10

jshell> System.out.print  <-- tab click..
print(     printf(    println(

jshell> System.out.println(a)
10


2.2 Immutable List, Set, Map, Map.Entity를 위한 Factory 메소드 제공

- Immutable 자료구조를 생성하기 위한 편의 Factory메소드를 제공하고 있다.
- java8 이전 버젼에서는 Collections.unmodifiableXXX라는 기능을 이용하여 이러한 불변 자료구조를 만들었다.
Collections.unmodificableList
- 이제는 Collections객체의 of메소드를 이용하여 이러한 자료구조를 편하게 생성할 수 있다.
jshell> List testImmutableList = List.of()
testImmutableList ==> []

jshell> testImmutableList.add <-- tab click..
add(      addAll(

jshell> testImmutableList.add(10)
|  Warning:
|  unchecked call to add(E) as a member of the raw type java.util.List
|  testImmutableList.add(10)
|  ^-----------------------^
|  java.lang.UnsupportedOperationException thrown:
|        at ImmutableCollections.uoe (ImmutableCollections.java:70)
|        at ImmutableCollections$AbstractImmutableList.add (ImmutableCollections.java:76)
|        at (#4:1)
jshell> List<Long> testLongImmutableList = List.of()
testLongImmutableList ==> []
jshell> testLongImmutableList.add(10L)
|  java.lang.UnsupportedOperationException thrown:
|        at ImmutableCollections.uoe (ImmutableCollections.java:70)
|        at ImmutableCollections$AbstractImmutableList.add (ImmutableCollections.java:76)
|        at (#6:1)

- 위 에제를 보면 불변의 자료구조라 값을 넣을 수 없다는 것을 알 수 있다.
jshell> List testDefaultStringImmutableList = List.of("Kido", "Kirog", "Uncle", "Bob")
testDefaultStringImmutableList ==> [Kido, Kirog, Uncle, Bob]
- Map은 다음과 같이 지정하면된다.
jshell> Map testMap = Map.of()
testMap ==> {}


jshell> testMap.put("1", "test")
|  Warning:
|  unchecked call to put(K,V) as a member of the raw type java.util.Map
|  testMap.put("1", "test")
|  ^----------------------^
|  java.lang.UnsupportedOperationException thrown:
|        at ImmutableCollections.uoe (ImmutableCollections.java:70)
|        at ImmutableCollections$AbstractImmutableMap.put (ImmutableCollections.java:557)
|        at (#9:1)

jshell> Map testDefaultValueMap = Map.of("1", "Kido", "2", "Kirog", "3", "Uncle", "4", "Bae")
testDefaultValueMap ==> {4=Bae, 3=Uncle, 2=Kirog, 1=Kido}

2.3 Interface 의 method를 private로 지정 가능 

- Java8에서는  Interface에 default메소드를 제공했다. 이는 Default, Static으로 제공되었으나 public 접근 제한자를 지원했다.
- Java9에서는 private 메소드를 제공한다. private메소드, 그리고 private static메소드를 제공한다.

public interface Card {
    private Long createCard() {
        // 내용구현하기.
    }
    private static void displayCardDetails() {
        // 여기에서 내용 구현하기.
    }
}

2.4 Module System 

- Java9 기능 중에서 가장 큰 변화중의 하나는 Module System.
- Modular JDK
- Modular Java Source Code
- Modular Run-time Image
- Encapsulate Java Internal APIs
- Java Platform Module System 
Java 9 이전버젼은 획일적인 Jar을 이용하여 자바 기반 어플리케이션을 개발했었다. 이것은 제약이 많고 결점이 있다. 이를 해결하기 위한 기능으로 Module System을 채택하였다.

- 자세한것은 쩜더 공부해서 추가하기.

2.5 Process API 향상

- Java 9에서는 Process API에 대한 향상을 제공한다. 이를 위해 새로운 클래스들과 메소드 들을 제공하며, 이것은 OS Process 컨트롤과 관리를 쉽게 해준다.

- Java.lang.ProcessHandle
- Java.lang.ProcessHandle.Info
example :
jshell> ProcessHandle handle = ProcessHandle.current()
handle ==> 53386
jshell> System.out.println("PID " + handle.getPid())
PID 53386

2.6 Try-With-Resources 향상

- Java7 에서는 새로운 예외 처리를 위한 구문인 : Try-With-Resource로 리소스를 자동적으로 관리 하는 것을 소개하였다. 이를 사용하는 이유는 더 낳은 리소스 관리를 위한 것이다.

- Java9 버젼에서는 장황한 코딩을 막고 더 읽기 쉽도록 개선되었다.
void testARM_Before_Java9() throws IOException{
 BufferedReader reader1 = new BufferedReader(new FileReader("journaldev.txt"));
 try (BufferedReader reader2 = reader1) {
   System.out.println(reader2.readLine());
 }
}

void testARM_Java9() throws IOException{
 BufferedReader reader1 = new BufferedReader(new FileReader("journaldev.txt"));
 try (reader1) {
   System.out.println(reader1.readLine());
 }
}

2.7 CompletableFuture API 개선

- Java8에서 문제를 발생시키던 Java9에서는 CompletableFuture API에 대한 개선을 가져왔다.
- delays와 timeouts를 추가하였다.

Executor exe = CompletableFuture.delayExecutor(50L, TimeUnit.SECONDS);
delayExecutor메소드는 정적 유틸리티 메소드로 Executor를 반환한다. 그리고 주어진 딜레이 이후에 해당 태스크를 제출한다.

2.8 Reactive Streams

- Reactive 프로그래밍은 최근 몇가지 매우 좋은 이점들로 인해서 유명해졌다. 프레임워크들은 이미 Reactive Streams과 많은 이점들을 준다.
- Reactive Streams API는 Publish/Subscribe 프레임워크로 비동기 구현을 수행할 수 있게 해준다. 또한 확장성, 병렬 어플리케이션을 매우 쉽게 개발 할 수 있도록 한다.
- Java9는 아래 API를 제공한다.
- java.util.concurrent.Flow
- java.util.concurrent.Flow.Publisher
- java.util.concurrent.Flow.Subscriber
- java.util.concurrent.Flow.Processor

2.9 Anonymous Inner Class를 위한 <> 오퍼레이터 제공

- Java7에서 새로운 기능으로 소개된 다이아몬드 오퍼레이터는 장환한 코드를 제거해주었다. 그러나 Anonymous Inner Class 에서 다이아몬드 오퍼레이터의 사용은 한계가 있었다.

public List getEmployee(String empid) {
    // 상세 코드를 작성하면 된다.
    return new List(emp) {};
}
위 코드는 List를 이용하고 타입 파라미터를 지정하지 않고 사용하 ㄹ수 있다.

2.10 Optional Class Improvements

java.util.Optional 클래스에 새로이 유용한 메소드가 추가되어 있다.

Stream<Optional> emp = getEmployee(id)
Stream empStream = emp.flatMap(Optional::stream)

2.11 Stream API 개선 

- Java9에서는 java.util.Stream인터페이스에 유용한 메소드가 추가 되었다. Stream은 인터페이스이며, 새로운 인터페이스는 default메소드로 구현 되었다.  이들 중 2개는 dropWhile과 takeWhile메소드로 매우 중요한 메소드이다.
- 만약 Scala나 Functional 프로그래밍 언어에 익숙하다면 이러한 메소드를 알 것이다. 이들은 함수형 스타일로 개발할때 매우 유용하다.
- takeWhile은 아규먼트를 예측하고, 처음으로 Predicate가 false를 반환할때까지 주어진 스트림 값의 서브셋 스트림을 반환한 값을 채택한다. 만약 처음 값이 Predicate를 만족하지 못하다면 비어있는 스트림을 반환하게 될 것이다.

jshell> Stream.of(1,2,3,4,5,6,7,8,9,10).takeWhile(i -> i < 5 ).forEach(System.out::println)
1
2
3
4

2.12 @Deprecated annotation 개선. 

- Java8 이전에서는 @Deprecate 어노테이션은 단순히 마커 인터페이스였다. 이는 클래스, 필드, 인터페이스, 메소드, 생성자, enum등에서 사용되었다.
- Java9 에서는 더 많은 정보를 추가할 수 있고, deprecated API의 정적 사용에 대한 분석툴을 제공한다.
- forRemoval과 since 메소드를 제공하고 있으며 이는 이러한 정보들을 제공한다.

2.13 HTTP2 Client

- HTTP/2 프로토콜을 지원하기 위한 클라이언트 API를 릴리즈 하였고 WebSocket 기능도 제공한다. 이전에 있던 Legacy HTTP Client API는 HTTP/1만 지원했고 HTTP/2를 지원하지 못하거나 WebSocket을 ㄷ지원하지 않았고, Blocking모드에서만 동작하거나 성능상의 이슈가 있었다.
- Java9에서는 java.net.http 패키지 하위에 이러한 HTTP/2 Client API를 추가하였다. 이는 HTTP/1과 HTTP/2를 둘다 제공한다. 또한 Synchronous (Blocking모드)와 asynchronous (Non Blocking모드) 모두 지원한다. 또한 Asynchronous모드에서 WebSocket을 지원한다.

import java.net.http.*;
import static java.net.http.HttpRequest.*;
import static java.net.http.HttpResponse.*;
...
URI uri = new URI("http://daum.net");
HttpResponse response = HttpRequest.create(uri).body(noBody()).GET().response()
System.out.println("Response was " + response.body(asString()))

2.14. Multi-Resolution Image API

- Java9에서는 Multi-Resolution Image API를 소개했다. 이는 MultiResolutionImage 인터페이스이며 java.awk.image패키지에 포함된다.
- 이는 서로다른 높이, 넓이를 가지는 이미지에 대해서 필요한 기능들을 제공하고 있다.

2.15. 기타

- GC(Garbage Collector) 향상
- Stack-Walking API
- Filter Incoming Serialization Data
- Deprecate the Applet API
- Enhanced Method Handles
- Java Platform Logging API and Service
- Compact Strings
- Parser API for Nashorn
- Javadoc Search
- HTML5 javadoc









GIT pull 오류

GIT pull 오류
Git을 이용하여 pull을 수행할때 다음과 같은 오류가 날 수 있다.

오류상황 :
error: unable to resolve reference refs/remotes/origin/xxxx_file: No such file or directory
From git+ssh://remoteserver/~/test
 ! [new branch]      xxxx_file -> origin/xxxx_file  (unable to update local ref)
error: unable to resolve reference refs/remotes/origin/split-css: No such file or directory
 ! [new branch]      xxxx_file2  -> origin/xxxx_file2  (unable to update local ref)

다음 명령어를 이용하면 불필요하게 꼬인 파일을 제거하여 정상으로 pull을 당길 수 있다.
$ git gc --prune=now
$ git remote prune origin