--Il est pratique de définir toString ()
et formatTo ()
lors de la création d'une classe.
--toString
a un format facile à comprendre par les développeurs pour le débogage.
--Le formatTo
a un format facile à comprendre pour l'utilisateur
À l'automne 2018 du JJUG CCC, «Revisiting Effective Java in 2018» [session] d'Edson Yanaga (https://jjug-cfp.cfapps.io/submissions/0fb90e6a-1717-4ce9-a2b9-56cef379a131) est apparu sobrement J'ai essayé d'organiser l'histoire du format, ce qui m'a impressionnée.
La session était très intéressante car c'était comme parler du savoir-faire de Effective Java 3rd Edition + α en live coding. En ce qui concerne formatTo, j'ai été surpris qu '"Y a-t-il une chose aussi utile dans le paquet java.lang
?", Mais même si je cherchais avec Qiita, il n'y avait presque pas d'articles, alors j'ai décidé de l'écrire moi-même.
Tout d'abord, la méthode familière toString
.
Une méthode qui renvoie une représentation sous forme de chaîne d'un objet. Il est appelé dans les situations suivantes.
--Lorsque vous combinez une chaîne et un objet
--Lorsqu'il est passé à une méthode qui génère une chaîne de caractères, telle que System.out.println ()
--Lors de l'affichage des variables dans le débogueur
Il est défini dans la classe Object comme nom de classe +" @ "+ représentation hexadécimale de la valeur de hachage
, mais il n'est pas très gérable et il est recommandé de le remplacer dans la sous-classe.
référence Object#toString
Remplacer toString
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + ", " + age + " years old.";
}
}
En remplaçant ʻObject # toString` comme ceci, vous pouvez sortir une chaîne de caractères formatée simplement en passant la variable telle qu'elle est lors de la sortie en standard.
Exemple d'utilisation de toString
Person marty = new Person("Marty", 17);
Person doc = new Person("Doc", 65);
System.out.println(marty); // Marty, 17 years old.
System.out.println(doc); // Doc, 65 years old.
En particulier, je pense qu'il est très "orienté objet" de savoir comment l'objet lui-même doit être stringifié, quelle que soit la manière dont il contient les données spécifiques.
--Charted dans le même format partout
Dans l'exemple ci-dessus, toute la sortie du débogueur et du journal sera sortie sous la forme de «Marty, 17 ans».
Je veux utiliser toString
pour la sortie utilisateur, mais je veux des informations plus détaillées pour le débogage.
C'est là qu'intervient la méthode formatTo
.
formatTo
À propos de la chaîne de spécification de format avant formatTo
C'est un mécanisme qui peut faire quelque chose de similaire à printf ou sprintf en langage C.
System.out.printf("%s, %d years old.%n", "Marty", 17); // --> Marty, 17 years old.
String str = String.format("%s, %d years old.", "Marty", 17); // --> "Marty, 17 years old."Est généré
Comme la méthode de spécification du format est assez compliquée, veuillez consulter Javadoc de la classe Formatter. Cependant, tout ce que vous devez savoir pour le moment est que le format est spécifié par les paramètres suivants.
Méthode de spécification du format du formateur
%[argument_index$][flags][width][.precision]conversion
La signification de chacun est la suivante.
//
//conversion (Comment convertir l'argument. La valeur entière est%d, le nombre réel est%Spécifiez la conversion en fonction du type tel que f)
//
String.format("%d", 12); // ---> "12"
System.out.printf("%f", Math.PI); // ---> 3.141593
//
//largeur (nombre minimum de caractères, l'espace manquant est rempli d'espaces)
//
String.format("%5d", 12); // ---> " 12"
//
// flag (-, +, #Indicateurs pour le contrôle d'options de formatage, etc.)
//
//Ajouter un signe moins pour s'aligner à gauche
String.format("%-5d", 12); // ---> "12 "
//Ajouter 0 pour remplir avec des zéros au lieu d'espaces
String.format("%05d", 12); // ---> "00012"
//Au début+Afficher le code avec
System.out.printf("%+5d", 12); // ---> "+12"
System.out.printf("%+5d", -12); // ---> "-12"
//
//précision (essentiellement utilisé pour désigner le nombre maximum de caractères)
//
//Dans le cas d'une valeur réelle, le nombre de chiffres après la virgule décimale (dans ce cas, il semble être traité comme "le nombre maximum de caractères après la virgule décimale")
System.out.printf("%4.2f", Math.PI); // ---> 3.14
Par exemple, «% -4.2f» a les valeurs suivantes.
conversion | flag | width | precision |
---|---|---|---|
f | - | 4 | 2 |
Person doc = new Person("Doc", 65);
String.format("%30s", doc);
String.format("%30s", doc.toString()); //La sortie sera la même que celle-ci
De cette façon, si vous passez un objet comme argument, la méthode toString
de cette classe sera appelée et le résultat sera traité comme une chaîne.
Cependant, si la classe passée à l'argument implémente l'interface Formattable
, il est possible de contrôler la méthode de sortie au lieu du résultat de toString
.
Une interface dans laquelle les méthodes suivantes sont définies.
Interface formatable
void formatTo(Formatter formatter,
int flags,
int width,
int precision)
Si vous passez une instance d'une classe qui implémente cette interface à une famille de méthodes printf, la méthode formatTo
sera appelée pour formater la partie correspondante.
class Person implements Formattable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "{name=" + name + ",age=" + age + "}";
}
@Override
public void formatTo(Formatter formatter, int flags, int width, int precision) {
//Le formatage est effectué en manipulant le formateur dans la méthode formatTo.
//Comment utiliser String#Identique au format
formatter.format("%s, %d years old.", name, age);
}
}
Exemple d'utilisation d'une classe qui implémente formatTo
Person marty = new Person("Marty", 17);
Person doc = new Person("Doc", 65);
System.out.printf("%s%n", marty); // Marty, 17 years old.
System.out.printf("%s%n", doc); // Doc, 65 years old.
System.out.println(marty); // {name=Marty,age=17}
System.out.println(doc); // {name=Doc,age=65}
De cette façon, en laissant la sortie pour l'utilisateur à la méthode formatTo
, la sortie pour le débogage peut être gérée librement afin qu'elle soit facile à utiliser du point de vue du développeur.
Encore plus pratique, la méthode formatTo
peut gérer les informations locales.
Par exemple, le support multilingue est possible comme suit.
@Override
public void formatTo(Formatter formatter, int flags, int width, int precision) {
if (formatter.locale() == Locale.JAPAN) {
formatter.format("%s est%J'ai d ans.", name, age);
} else {
formatter.format("%s, %d years old.", name, age);
}
}
Par défaut, il s'agit de la locale du système, mais vous pouvez changer l'affichage en passant la locale comme argument de printf.
System.out.printf("%s%n", doc); //Doc a 65 ans.
System.out.printf(Locale.ENGLISH, "%s%n", doc); // Doc, 65 years old.
Puisque la largeur d'affichage est passée à l'argument de formatTo
, il est possible de basculer automatiquement en fonction de la largeur de sortie.
Exemple de changement automatique de la notation yuan
private enum Gengou implements Formattable {
MEIJI("Meiji", 'M'), TAISHO("Taisho", 'T'), SHOWA("Showa", 'S'), HEISEI("Heisei", 'H');
private String name;
private char initialLetter;
private Gengou(String japaneseName, char initial) {
this.name = japaneseName;
this.initialLetter = initial;
}
/**
*Si la largeur d'affichage est de 2 caractères ou plus, le nom officiel est affiché.
*/
@Override
public void formatTo(Formatter formatter, int flags, int width, int precision) {
if (width >= 2) {
formatter.format("%s", name);
} else {
formatter.format("%s", initialLetter);
}
}
}
System.out.printf("Cette année%3s 30 ans.%n", Gengou.HEISEI); // Cette année平成 30 年です。
System.out.printf("Cette année%1s 30 ans.%n", Gengou.HEISEI); // Cette annéeH 30 年です。
Puisque l'argument de formatTo
peut être manipulé librement, il est possible de contrôler la sortie de la classe représentant le paragraphe (Paragraph) en utilisant la précision comme nombre de caractères d'ellipse et la largeur comme nombre total de caractères.
private static class Paragraph implements Formattable {
private String content;
public Paragraph(String content) {
this.content = content;
}
@Override
public void formatTo(Formatter formatter, int flags, int width, int precision) {
StringBuilder sb = new StringBuilder();
if (content.length() < width) {
sb.append(content);
} else {
sb.append(content.substring(0, width - precision));
if (precision > 0) {
for (int i = 0; i < precision; i++) {
sb.append(".");
}
}
}
formatter.format(sb.toString());
}
}
Paragraph p = new Paragraph("This is very very long text!");
System.out.printf("%15.3s%n", p); // This is very...
System.out.printf("%10.4s%n", p); // This i....
En écrivant l'article, j'ai remarqué que si la sortie est du texte comme la classe Person
mentionnée dans l'exemple, je pense qu'il est plus simple de créer une classe séparée pour le formatage des messages.
Au contraire, dans le cas d'une classe de type objet de valeur qui a une signification en tant que valeur par elle-même, telle que «montant» et «ID utilisateur», je pense qu'il est toujours bon d'implémenter «Formattable». ..
Recommended Posts