2008-09-05 18 views
245

Printf consiguió añadido a Java con la versión 1.5, pero me parece que no puede encontrar la forma de enviar la salida a una cadena en lugar de un archivo (que es lo que hace sprintf en C). ¿Alguien sabe como hacer esto?sprintf equivalente en Java

Respuesta

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

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

Ver format y su @erickson syntax

22

.

Las cadenas son inmutables tipos. No puede modificarlos, solo devuelve nuevas instancias de cadena.

Debido a eso, "foo" .formato() no tiene mucho sentido, ya que tendría que ser llamado como

string newString = "foo".format(); 

Los autores originales (Java y .NET autores), decidió que un método estático tiene más sentido en esta situación, ya que no está modificando "foo", sino que llama a un método de formato y pasa una cadena de entrada.

EDIT: Heh, este sitio puede ser tan divertido a veces. Me criticaron por mencionar el hecho de que las cadenas son tipos inmutables.

Aquí es un ejemplo de por qué Format() sería tonto como un método de instancia. En .NET (y probablemente en Java), Replace() es un método de instancia.

Usted puede hacer esto:

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

Sin embargo, no pasa nada, porque las cadenas son inmutables. Reemplazar intenta devolver una nueva cadena, pero está asignada a nada.

Esto provoca una gran cantidad de errores de novato comunes como:

// Contrived Example 
inputText.Replace(" ","%20"); 

Una vez más, no pasa nada, en lugar que tiene que hacer:

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

Ahora, si se entiende que las cadenas son inmutables, que hace que sentido perfecto. Si no lo haces, entonces estás confundido. El lugar apropiado para reemplazar, estaría donde Formato es, como un método estático de la secuencia:

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

Ahora no hay duda en cuanto a qué se está encendiendo.

La verdadera pregunta es, ¿por qué los autores de estos marcos deciden que uno debe ser un método de instancia, y el otro estática? En mi opinión, ambos se expresan con mayor elegancia como métodos estáticos, pero Erickson parece pensar que ambos pertenecen como métodos de instancia.

Independientemente de su opinión, la verdad es que son menos propensos a cometer un error utilizando la versión estática, y el código es más fácil de entender (n Gotchas Oculta).

Por supuesto, hay algunos métodos que son perfectos como los métodos de instancia, tomar String.length()

int length = "123".Length(); 

En esta situación, es obvio que no están tratando de modificar "123", que acabamos de inspeccionarlo y devolviendo su longitud ... Este es un candidato perfecto para un método de instancia.

Mis reglas simples para los métodos de instancia sobre inmutables Objetos:

  • Si necesita devolver una nueva instancia del mismo tipo, utilizan un método estático.
  • De lo contrario, utilice un método de instancia.
+3

Veo que de alguna manera tiene la idea de que estaba sugiriendo que se modifique la cadena de formato. Nunca consideré la posibilidad de que alguien espere que una Cadena cambie, ya que su inmutabilidad es tan fundamental. – erickson

+4

Al ver que la cadena de formato es más parecida a "El precio es% 4d", y no "% 4d", todavía veo un gran potencial de confusión. ¿Qué tienes contra los métodos estáticos? :) – FlySwat

+38

Esta respuesta parece no tener nada que ver con la pregunta. –

2

Ambas soluciones funcionan para simular printf, pero de una manera diferente. Por ejemplo, para convertir un valor a una cadena hexadecimal, tiene las 2 siguientes soluciones:

  • con format(), más cercano a sprintf():

    final static String HexChars = "abcdef"; 
    
    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; 
    } 
    
  • con replace(char oldchar , char newchar), un poco más rápido, pero bastante limitadas :

    ... 
        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))); 
        ... 
    
  • Hay una tercera solución que consiste en solo anuncios ding el char a ret uno por uno (char son números que suman entre sí!) como por ejemplo en:

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

... pero eso sería realmente feo.

+0

Todas las ideas excelentes, pero convierte su código en un código de escritura imposible de entender para su compañero de trabajo. – Ben