Create a temporary class with new Object () {}

Introduction

Java's ʻObject class is a very important class in the superclass of all classes, but isn't it rare to newitself? In this article, I'll show you two code examples wherenew Object ()` makes sense.

Define a method inside a method

The following is a code example described in the comment "Implementing a combination of mathematics in Java --Qiita". A method that enumerates and returns k combinations from the string array 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);
        }
    }

It consists of two methods, the one that is called directly from the outside is the two-argument combination, and the five-argument combination is used internally. The 5-argument combination is recalling itself, but of the 5 arguments, the 3 arguments (data, comb, result) specify exactly the same value as the argument. If Java can define methods nested, you shouldn't have to write the same arguments on the recall call. Unfortunately, you can't nest methods in Java. So let's rewrite it using 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;
    }

The 5-argument combination is written insidenew Object () {}and the fixed 3 arguments (data, comb, result) are deleted. The new Object () {} in this code defines an anonymous inner class and at the same time creates an instance of that class. The .combination (0, 0) after the new Object () {} calls the combination (int di, int ci) defined in the inner class. The fixed 3 variables (data, comb, result) can be referenced from within the inner class, so there is no need to pass them as arguments for each call. I am creating a useless instance with new Object (), but the overhead is small because I only create one. Stack consumption is reduced because there are fewer arguments on the recall call.

Class for temporary data storage

Suppose you have a class like this:

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;
    }
}

Furthermore, suppose you have the following list of Persons.

List<Person> list = List.of(
    new Person("Yamada", "18"),
    new Person("Ichikawa", "72"),
    new Person("Sato", "39"),
    new Person("Tanaka", "9"));

Consider sorting this by ʻage in ascending order. Since ʻage is a string, it must be written like this to sort it as an integer.

    List<Person> result = list.stream()
        .sorted(Comparator.comparingInt(p -> Integer.parseInt(p.getAge())))
        .collect(Collectors.toList());

This works fine, but it's not very efficient because ʻInteger.parseInt (p.getAge ()) is executed twice each time the values are compared. Even with the fast sorting algorithm, ʻInteger.parseInt will be executed $ 2n \ log n $ times.

Map.Entry

Pairing an instance of Person with an integerized version of ʻagesolves this problem. In such cases, theMap.Entry` class is often used as a temporary storage location.

    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());

The integer ʻageonly needs to be calculated once, but it is intuitively difficult to understand whereMap.Entry` is used.

Records Java 14 adds a feature called Records that makes it easy to define immutable classes for data storage. If you use this, it will be like this.

    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());

It's easier to understand, but it also feels a bit exaggerated because it defines a class for temporary storage.

new Object() This is what happens when you use 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 () {...} is a temporary storage location that is only valid in this expression. Although it is an anonymous class, it is recognized in this expression as a full-fledged class with fields ʻintAgeandperson`.

Summary

How was that? You can see that the ʻObject` class also has various uses. I can't recommend it because it feels tricky, but I've been using it since I knew I could write it like this.

Recommended Posts

Create a temporary class with new Object () {}
[Rails 5] Create a new app with Rails [Beginner]
Mapping to a class with a value object in How to MyBatis
Create exceptions with a fluid interface
Create a Maven project with a command
Create a SandBox account with fastlane spaces ip
Create a multi-key map with the standard library
Create a web api server with spring boot
Create a Spring Boot development environment with docker
[Note] Create a java environment from scratch with docker
Create a Service with an empty model Liferay 7.0 / DXP
Create a simple demo site with Spring Security with Spring Boot 2.1
A memo that handles a class created independently with ArrayList
[Java] How to start a new line with StringBuilder
A series of steps to create portfolio deliverables with Rails
How to move another class with a button action of another class.
Until you create a Web application with Servlet / JSP (Part 1)
Tutorial to create a blog with Rails for beginners Part 2
If you have complicated calculations, let's create a CalcRule class
I tried to create a padrino development environment with Docker
Tutorial to create a blog with Rails for beginners Part 0