La classe ʻObjectde Java est une classe très importante dans la superclasse de toutes les classes, mais n'est-il pas rare de se "nouveau"? Dans cet article, je vais vous montrer deux exemples de code où
new Object ()` a du sens.
Voici un exemple de code décrit dans le commentaire «Implémentation d'une combinaison de mathématiques en Java --Qiita». Cette méthode énumère et renvoie «k» combinaisons à partir du tableau de chaînes «data».
static List<String[]> combination(String[] data, int k) {
List<String[]> result = new ArrayList<String[]>();
combination(data, 0, new String[k], 0, result);
return result;
}
static void combination(String[] data, int di, String[] comb, int ci, List<String[]> result) {
if (ci == comb.length) {
result.add(comb.clone());
return;
}
for ( ; di <= data.length - (comb.length - ci); di++) {
comb[ci] = data[di];
combination(data, di + 1, comb, ci + 1, result);
}
}
Il se compose de deux méthodes, celle qui est appelée directement de l'extérieur est la «combinaison» à deux arguments, et la «combinaison» à cinq arguments est utilisée en interne. La «combinaison» à 5 arguments se rappelle d'elle-même, mais sur les 5 arguments, les 3 arguments («data», «comb», «result») spécifient exactement la même valeur que l'argument.
Si Java peut définir des méthodes imbriquées, vous ne devriez pas avoir à écrire les mêmes arguments lors d'un appel de rappel. Malheureusement, vous ne pouvez pas imbriquer de méthodes en Java.
Réécrivons-le donc en utilisant new Object ()
.
static List<String[]> combination(String[] data, int k) {
int length = data.length;
List<String[]> result = new ArrayList<String[]>();
String[] comb = new String[k];
new Object() {
void combination(int di, int ci) {
if (ci == k) {
result.add(comb.clone());
return;
}
for (; di <= length - (k - ci); di++) {
comb[ci] = data[di];
combination(di + 1, ci + 1);
}
}
}.combination(0, 0);
return result;
}
La «combinaison» à 5 arguments est écrite dans le «nouvel Object () {}» et les 3 arguments fixes («data», «comb», «result») sont supprimés.
Le new Object () {}
dans ce code définit une classe interne anonyme et crée en même temps une instance de cette classe. Le .combination (0, 0)
après lenouvel Object () {}
appelle la combinaison (int di, int ci)
définie dans la classe interne.
Les 3 variables fixes (data
, comb
, result
) peuvent être référencées à partir de la classe interne, il n'est donc pas nécessaire de les passer comme arguments pour chaque appel.
Je crée une instance inutile avec new Object ()
, mais la surcharge est faible car je n'en crée qu'une. La consommation de pile est réduite car il y a moins d'arguments sur l'appel de rappel.
Supposons que vous ayez une classe comme celle-ci:
public class Person {
private final String name;
private final String age;
public Person(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public String getAge() {
return this.age;
}
}
De plus, supposons que vous ayez la liste suivante de Person
s.
List<Person> list = List.of(
new Person("Yamada", "18"),
new Person("Ichikawa", "72"),
new Person("Sato", "39"),
new Person("Tanaka", "9"));
Pensez à trier ceci dans l'ordre croissant par «âge». Puisque ʻage` est une chaîne, il doit être écrit comme ceci pour le trier comme un entier.
List<Person> result = list.stream()
.sorted(Comparator.comparingInt(p -> Integer.parseInt(p.getAge())))
.collect(Collectors.toList());
Cela fonctionne bien, mais ce n'est pas très efficace car ʻInteger.parseInt (p.getAge ()) est exécuté deux fois à chaque fois que les valeurs sont comparées. Même avec l'algorithme de tri rapide, ʻInteger.parseInt
est exécuté $ 2n \ log n $ fois.
Map.Entry
L'appariement d'une instance de Person
avec une version intégrale de ʻagerésout ce problème. Dans de tels cas, la classe
Map.Entry` est souvent utilisée comme emplacement de stockage temporaire.
List<Person> result = list.stream()
.map(p -> Map.entry(Integer.parseInt(p.getAge()), p))
.sorted(Comparator.comparingInt(Entry::getKey))
.map(Entry::getValue)
.collect(Collectors.toList());
L'entier ʻagen'a besoin d'être calculé qu'une seule fois, mais il n'est pas intuitivement clair où
Map.Entry` est utilisé.
Records Java 14 ajoute une fonctionnalité appelée Records qui facilite la définition de classes immuables pour le stockage de données. Si vous utilisez ceci, ce sera comme ça.
record PersonWithAge(Person p, int age) {
PersonWithAge(Person p) {
this(p, Integer.parseInt(p.getAge()));
}
}
List<Person> result = list.stream()
.map(PersonWithAge::new)
.sorted(Comparator.comparingInt(PersonWithAge::age))
.map(PersonWithAge::p)
.collect(Collectors.toList());
C'est plus facile à comprendre, mais cela semble aussi un peu exagéré car il définit une classe pour le stockage temporaire.
new Object()
C'est ce qui se passe lorsque vous utilisez new Object ()
.
List<Person> result = list.stream()
.map(p -> new Object() {
int intAge = Integer.parseInt(p.getAge());
Person person = p;
})
.sorted(Comparator.comparingInt(obj -> obj.intAge))
.map(obj -> obj.person)
.collect(Collectors.toList());
new Object () {...}
est un emplacement de stockage temporaire qui n'est valide que dans cette expression. Bien que ce soit une classe sans nom, elle est reconnue dans cette expression comme une classe à part entière avec les champs ʻintAge et
person`.
Comment était-ce? Vous pouvez voir que la classe ʻObject` a également diverses utilisations. Je ne peux pas le recommander car il semble délicat, mais je l'utilise depuis que je savais que je pouvais l'écrire comme ça.
Recommended Posts