0

My goal is to to generate an enum in order to create an EnumSet. This part works if I write the enum. Instead of writing an enum of 50000 lines, I would like to import the 50000 rows CSV. The trouble starts when I try to replace the enum I wrote by the the CSV import.

package VilleEnumSet;

public class VilleEnumSet {
    
    
    //ENUM SANS CSV
    enum Ville {
        Paris("FR", "75000", "Paris", "Ile de France", "Paris", "75", "Paris", "751", "48.8534", "2.3488"),
        Lyon("FR", "69000", "Lyon", "Auvergne-Rhone-Alpes", "Rhone", "69", "Lyon", "691", "45.7485", "4.8467"),
        Marseille("FR", "13000", "Marseille", "Provence-Alpes-Cote d'Azure", "Bouches-du-Rhone", "13", "Marseille", "133", "43.2969", "5.3811"),
        Montpellier("FR", "34000", "Montpellier", "Occitanie", "Herault", "34", "Montpellier", "343", "43.6109", "3.8764");
    
        
    //ATTRIBUTS
    private final String pays;
    private final String codePostal;
    private final String nom;
    private final String region;
    private final String departement;
    private final String numDepartement;
    private final String prefecture;
    private final String codeCommune;
    private final String latitude;
    private final String longitude;
    
    

    //CONSTRUCTEUR
    private Ville(String pays, String codePostal, String nom, String region, String departement, String numDepartement,
            String prefecture, String codeCommune, String latitude, String longitude) {
        this.pays = pays;
        this.codePostal = codePostal;
        this.nom = nom;
        this.region = region;
        this.departement = departement;
        this.numDepartement = numDepartement;
        this.prefecture = prefecture;
        this.codeCommune = codeCommune;
        this.latitude = latitude;
        this.longitude = longitude;
    }

    
    //GETTERS
    public String getPays() {
        return pays;
    }

    public String getCodePostal() {
        return codePostal;
    }

    public String getNom() {
        return nom;
    }

    public String getRegion() {
        return region;
    }

    public String getDepartement() {
        return departement;
    }

    public String getNumDeprtement() {
        return numDepartement;
    }

    public String getPrefecture() {
        return prefecture;
    }

    public String getCodeCommune() {
        return codeCommune;
    }

    public String getLatitude() {
        return latitude;
    }

    public String getLongitude() {
        return longitude;
    }
    
    
    //TOSTRING
    public String toString() {
        return String.format("%-40s%-10s\n", "Pays: " + pays, "Code Postal: " + codePostal) 
                + String.format("%-40s%-10s\n", "Nom: " + nom, "Region: " + region) 
                + String.format("%-40s%-10s\n", "Departement: " + departement, "Num Departement: " + numDepartement)
                + String.format("%-40s%-10s\n", "Prefecture: " + prefecture, "Code Commune: " + codeCommune)
                + String.format("%-40s%-10s\n\n", "Latitude: " + latitude, "Longitude: " + longitude);
    }
    }

}
package VilleEnumSet;

import java.util.EnumSet;
import java.util.Iterator;

import VilleEnumSet.VilleEnumSet.Ville;

public class MainVilleEnumSet {
    
public static void main(String[] args) {
        
        // Creating an EnumSet using allOf()
        EnumSet<Ville> villes = EnumSet.allOf(Ville.class);
        
        // Creating an iterator on games
        Iterator<Ville> iterate = villes.iterator();
        
        // Message
        System.out.println("EnumSet: " + "\n");
        
        while (iterate.hasNext()) {
            System.out.println(iterate.next());
        }
    }

}

my code returns this:

EnumSet: 

Pays: FR                                Code Postal: 75000
Nom: Paris                              Region: Ile de France
Departement: Paris                      Num Departement: 75
Prefecture: Paris                       Code Commune: 751
Latitude: 48.8534                       Longitude: 2.3488


Pays: FR                                Code Postal: 69000
Nom: Lyon                               Region: Auvergne-Rhone-Alpes
Departement: Rhone                      Num Departement: 69
Prefecture: Lyon                        Code Commune: 691
Latitude: 45.7485                       Longitude: 4.8467

For the CSV structure, each column corresponds to an attribute in the class "VilleEnumSet".

I have no idea what to do. I've looked for help, but many suggest to switch to list which I don't want to.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Apage
  • 3
  • 2
  • 3
    Why do you want to use an enum for this? Why not a collection of Java records, or beans? I see you "don't want to", but why not? – andrewJames May 04 '23 at 15:43
  • 2
    An enum of 50000 items? Can you explain why you want something like this? This really looks better suited for a database table. This is not something I'd use an enum for. – stdunbar May 04 '23 at 15:43
  • 1
    Enums are specifically for naming the object instances for use in code so unless you are directly accessing each enum by it's enum name directly from code, you don't want an enum, you just want a collection of objects, an array or a hash. You may want to load this collection from your original csv file at runtime, no need to pre-process it into code or anything. – Bill K May 04 '23 at 15:59
  • 2
    `Ville` should be a class, not an `enum` – g00se May 04 '23 at 16:00
  • This exercise takes place in a bigger one, in which I have to compare which one works better between the HashSet and the EnumSet. This is why I "absolutly" need the EnumSet – Apage May 04 '23 at 22:10

2 Answers2

3

Enum not appropriate to your needs

An enum is meant to represent a small set of values known at compile-time. The names of these values are meant to be used within your source code, as discussed in the correct Answer by Bill K.

That does not match your situation.

You have a large number of values loaded at runtime. Representing such values is the purpose of a custom class. Grouping objects of your custom class is the purpose of the Java Collections Framework with lists, sets, queues, maps, and such.

record

If the main purpose of your custom class is to communicate data transparently and immutably, define your class as a record. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.

record Ville (String pays, String codePostal, String nom, String region, String departement, String numDepartement, String prefecture, String codeCommune, String latitude, String longitude) {}

By the way, know that as of Java 16 a record can be defined locally within a method, or nested within a class, or separately. (Ditto for enums and interfaces.)

As your CSV library imports each row of input, instantiate an object of your record class. Add to a collection object, likely an implementation of List. You may choose to instead use a NavigableSet/SortedSet after implementing the Comparable interface. In Java 21+, see SequencedSet.

If your inputs were to change during runtime, you can replace the collection of objects with fresh ones based on another data import. With enums, you can change the value of any member fields, but you cannot add or remove the named enum objects at runtime.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Well the big picture of my exercise is to compare the performances between the HashSet and the EnumSet. The HashSet works with datas from csv. But I am stuck with the EnumSet, I don't know how to import the datas from the csv to the EnumSet – Apage May 04 '23 at 22:00
  • @Apage HashSet and EnumSet serve two different purposes. Comparing them for performance does not make sense. If you have enum objects, an `EnumSet` will be faster; that’s why it exists, for the benefits of a [bit array](https://en.wikipedia.org/wiki/Bit_array). (And a `EnumSet` takes little memory.) But if enums are not an appropriate solution, as seen in your situation, the performance difference is irrelevant. – Basil Bourque May 04 '23 at 23:42
0

Although you absolutely would not use an enum for this, but there actually is a valid use case so It's worth an answer in case anyone else comes here.

The actual direct answer to your question is that you would want to generate the code for the enum progmatically. One way (the wrong way) is to just write a pre-compiler to build the file manually by emitting the beginning of the class as a constant string, the repeated lines for each group of data from the csv file and then the end of the class as another constant string. This pre-compiler is called by your buildfile before launching the actual java compiler.

This has problems--it will require a pre-compile step and will probably not integrate with your IDE.

The more correct way to do it would be to create an annotation processor. Annotations can be processed before your code is compiled and allows you to insert arbitrary code into the file.

If your annotation was inside the enum, your Annotation Processor could just emit the lines like this:

Paris("FR", "75000", "Paris", "Ile de France", "Paris", "75", "Paris", "751", "48.8534", "2.3488"),

and the rest of the file would be an actual java classfile contining an annotation that causes your Processor to be called.

The annotation processor is passed to the java compiler via a command line switch like "javac -processor (fullClassName)".

The nice thing about doing it this way is that you can tell the IDE that this is an annotation processor and it will ensure that adding a record to your CSV file makes the enum immideately available. It also prevents a temporary source file from being generated (Those almost always lead to trouble as people try to edit them by hand or something)

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • Annotation Processors cannot *modify* source files, they can only create new source files that will be compile in a successive compilation cycle. Consequently, the pre-processor is the better option here. – tquadrat May 04 '23 at 20:43
  • @tquadrat I'll admit I've only reviewed the annotation processors and not actually made code using that compile step so I'll have to look again--but I'm pretty sure there is a way to make the annotaiton processor work even if it involves adding a few text files with the pre and post text and generating your source file from scratch. The advantage, however, of having your IDE be able to use it immideatly as a java source file is immense. – Bill K May 08 '23 at 16:23