Java에서 Sprintf에 해당


284

Printf가 1.5 릴리스에서 Java에 추가되었지만 출력이 파일이 아닌 문자열 (Sprintf가 C에서 수행하는 것)이 아닌 문자열로 보내는 방법을 찾지 못하는 것 같습니다. 누구든지 이것을하는 방법을 알고 있습니까?

답변:


474
// Store the formatted string in 'result'
String result = String.format("%4d", i * j);

// Write the result to standard output
System.out.println( result );

형식구문을 참조하십시오


28

문자열은 변경할 수없는 유형입니다. 수정할 수 없으며 새 문자열 인스턴스 만 반환합니다.

이 때문에 인스턴스 메소드를 사용한 형식화는 다음과 같이 호출되어야하므로 거의 의미가 없습니다.

String formatted = "%s: %s".format(key, value);

원래 Java 작성자 (및 .NET 작성자)는 대상을 수정하지 않고 대신 형식 메소드를 호출하고 입력 문자열을 전달하므로이 상황에서 정적 메소드가 더 의미가 있다고 결정했습니다.

다음은 format()인스턴스 메소드로 바보 같은 이유의 예입니다 . .NET (및 아마도 Java)에서 Replace()인스턴스 메소드입니다.

당신은 이것을 할 수 있습니다 :

 "I Like Wine".Replace("Wine","Beer");

그러나 문자열은 변경할 수 없으므로 아무 일도 일어나지 않습니다. Replace()새 문자열을 반환하려고 시도하지만 아무것도 할당되지 않았습니다.

이로 인해 다음과 같은 일반적인 신인 실수가 많이 발생합니다.

inputText.Replace(" ", "%20");

다시 말하지만 아무 일도 일어나지 않고 대신해야합니다.

inputText = inputText.Replace(" ","%20");

이제 문자열을 변경할 수 없다는 것을 이해하면 완벽하게 이해됩니다. 그렇지 않으면 혼란 스러울 수 있습니다. 위한 적절한 위치 Replace()어디 것 format()인 정적 메소드로서 String:

 inputText = String.Replace(inputText, " ", "%20");

이제 무슨 일이 일어나고 있는지 의심의 여지가 없습니다.

실제 질문은 왜이 프레임 워크의 작성자가 하나는 인스턴스 메소드 여야하고 다른 하나는 정적이어야한다고 결정 했습니까? 제 생각에는 둘 다 정적 메소드로보다 우아하게 표현됩니다.

당신의 의견에 관계없이, 진실은 정적 버전을 사용하여 실수하는 경향이 적고 코드를 이해하기 쉽다는 것입니다 (No Hidden Gotchas).

물론 인스턴스 메소드로 완벽한 일부 메소드가 있습니다. String.Length ()

int length = "123".Length();

이 상황에서 우리는 "123"을 수정하려고하지 않고 단지 검사하고 길이를 반환하는 것이 분명합니다. 이것은 인스턴스 메소드의 완벽한 후보입니다.

불변 객체의 인스턴스 메소드에 대한 간단한 규칙 :

  • 동일한 유형의 새 인스턴스를 리턴해야하는 경우 정적 메소드를 사용하십시오.
  • 그렇지 않으면 인스턴스 메소드를 사용하십시오.

4
형식 문자열을 수정하라는 제안을 받았다는 것을 알 수 있습니다. 불변성이 매우 근본적이기 때문에 누군가가 문자열이 변경 될 것으로 예상 할 가능성을 결코 고려하지 않았습니다.
erickson

4
형식 문자열은 일반적으로 "% 4d"가 아니라 "The Price is % 4d"와 비슷하지만 여전히 혼란의 가능성이 많습니다. 정적 메소드에 대해 무엇을 가지고 있습니까? :)
FlySwat

44
이 답변은 질문과 관련이없는 것 같습니다.
Steve McLeod

2
대답은 .NET에 더 많은 관련성이, 심지어 자바 보인다되지 않습니다
Photodeus

3
-1. 하향식 b / c 접선입니다. 불변에 가장 적합한 스타일 일 필요는 없습니다. 이 스타일은 특히 연쇄 작업의 경우 간단한 메서드 호출보다 더 장황합니다. 그리고 정적 메소드를 호출하기 때문에 런타임 다형성을 포기합니다. YMMV.
Andrew Janke

3

두 솔루션 모두 printf를 시뮬레이션하지만 다른 방식으로 작동합니다. 예를 들어, 값을 16 진 문자열로 변환하려면 다음 두 가지 솔루션이 있습니다.

  • format()가장 가까운 sprintf():

    final static String HexChars = "0123456789abcdef";
    
    public static String getHexQuad(long v) {
        String ret;
        if(v > 0xffff) ret = getHexQuad(v >> 16); else ret = "";
        ret += String.format("%c%c%c%c",
            HexChars.charAt((int) ((v >> 12) & 0x0f)),
            HexChars.charAt((int) ((v >>  8) & 0x0f)),
            HexChars.charAt((int) ((v >>  4) & 0x0f)),
            HexChars.charAt((int) ( v        & 0x0f)));
        return ret;
    }
    
  • replace(char oldchar , char newchar)다소 빠르지 만 꽤 제한 :

        ...
        ret += "ABCD".
            replace('A', HexChars.charAt((int) ((v >> 12) & 0x0f))).
            replace('B', HexChars.charAt((int) ((v >>  8) & 0x0f))).
            replace('C', HexChars.charAt((int) ((v >>  4) & 0x0f))).
            replace('D', HexChars.charAt((int) ( v        & 0x0f)));
        ...
    
  • 다음과 같이 문자를 ret하나씩 추가하는 것으로 구성된 세 번째 솔루션이 있습니다 (문자는 서로 더하는 숫자입니다 !).

    ...
    ret += HexChars.charAt((int) ((v >> 12) & 0x0f)));
    ret += HexChars.charAt((int) ((v >>  8) & 0x0f)));
    ...
    

...하지만 그건 정말 못 생겼어.


모든 훌륭한 아이디어이지만 코드를 동료가 이해하기 어려운 쓰기 전용 코드로 바꿉니다.
Ben

0

PrintStream을 사용하여 OutputStream 인 모든 것에 printf를 수행 할 수 있습니다. 어떻게 든 문자열 스트림으로 인쇄합니다.

PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s", "hello", 3, "friends");
System.out.println(baos.toString());
baos.reset(); //need reset to write new string
ps.printf("there is a %s from %d %s", "flip", 5, "haters");
System.out.println(baos.toString());
baos.reset();

이 ByteArrayOutputStream과 같이 문자열 스트림을 만들 수 있습니다.

ByteArrayOutputStream baos = new ByteArrayOutputStream();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.