Generyki w Javie: odczytanie kolumn z CSV dla double i String

2017-10-30 20:01
0

Taka sytuacja:
Mam 2 klasy odpowiedzialne za wczytywanie słowników z csv.
1 klasa pobiera 2 kolumny z csv i zapisuje jako Map<String, String>.
2 klasa pobiera 2 kolumny z csv i zapisuje jako Map<String, Double>.

Co zrobić by nie dublować kodu? Ano zrobić klasę bardziej ogólną odpowiedzialną za tworzenie Map z csv. No to robię:

package Main;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.function.Function;

public interface MapFromCsv<T1, T2> {

    public default Map<T1, T2> getMap(String FILE_TO_LOAD){
        Map<T1, T2> mapResult = new HashMap<>();
        File f = new File(FILE_TO_LOAD);
        try (Scanner sc = new Scanner(f)) {
            while (sc.hasNextLine()) {
                String tmp = sc.nextLine();
                String[] tmp2 = tmp.split(";");
                mapResult.put((T1) tmp2[0], (T2) tmp2[1]);
            }
        } catch (FileNotFoundException fntf) {
            System.err.println("File " + f.getPath() + "was not found.");
        } catch (Exception e) {
            System.err.println("Something went wrong with reading " + f.getPath());
        }
        return mapResult;
    }
}

klasa1:

package Main;

import java.util.Map;

public enum AreaMapFromCsv implements MapFromCsv<String, String> {

    INSTANCE;
    final String FILE_TO_LOAD = "resources/areaMap.csv";
    private Map<String, String> areaMap;

    private AreaMapFromCsv() {
        initAreaMap();
    }

    private void initAreaMap() {
        this.areaMap = getMap(FILE_TO_LOAD);
    }

    public void reloadAreaMap() {
        initAreaMap();
    }

    public Map<String, String> getAreaMap() {
        return areaMap;
    }

}

klasa2:

package Main;

import java.util.Map;

public enum CurrencyMapFromCsv implements MapFromCsv<String, Double>{

    INSTANCE;
    final String FILE_TO_LOAD = "resources/currencyMap.csv";
    private Map<String, Double> currencyMap;

    private CurrencyMapFromCsv() {
        initCurrency();
    }

    private void initCurrency() {
        this.currencyMap = getMap(FILE_TO_LOAD);
    }

    public void reloadCurrency() {
        initCurrency();
    }

    public Map<String, Double> getCurrencyMap() {
        return currencyMap;
    }

}

Tylko teraz jest problem taki o, że klasa MapToCsv nie wie jak zamienić Stringa na doubla i wywala się na castowaniu. Postanowiłem mu wlepić funkcje, ale mi nie działa:

package Main;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.function.Function;

public interface MapFromCsv<T1, T2> {

    public default Map<T1, T2> getMap(String FILE_TO_LOAD, Function<String, T1> foo1, Function<String, T2> foo2){
        Map<T1, T2> mapResult = new HashMap<>();
        File f = new File(FILE_TO_LOAD);
        try (Scanner sc = new Scanner(f)) {
            while (sc.hasNextLine()) {
                String tmp = sc.nextLine();
                String[] tmp2 = tmp.split(";");
                mapResult.put((T1) foo1.apply(tmp2[0]), (T2) foo2.apply(tmp2[1]));
            }
        } catch (FileNotFoundException fntf) {
            System.err.println("File " + f.getPath() + "was not found.");
        } catch (Exception e) {
            System.err.println("Something went wrong with reading " + f.getPath());
        }
        return mapResult;
    }
}

i wtedy bym w klasie1 przekazał jako 2 funkcje: String::toString, a w klasie2: String::toString i Double::parseDouble.

EDIT: jednak działa. :O Jak to bardziej przejrzyście zrobić?

edytowany 7x, ostatnio: Julian_, 2017-10-30 21:11
Tytułowanie wątków – przeczytaj, a następnie zmień tytuł wątku na sensownie opisujący problem. - furious programming 2017-10-30 21:10

Pozostało 580 znaków

2017-10-30 21:42
1

Zrób sobie w interfejsie metodę, która będzie konwertowała wczytane dane na odpowiedni typ generyczny i nadpisz ją w klasach implementujących interfejs.

Pozostało 580 znaków

2017-10-30 21:58
0
Aterwik napisał(a):

Zrób sobie w interfejsie metodę, która będzie konwertowała wczytane dane na odpowiedni typ generyczny i nadpisz ją w klasach implementujących interfejs.

czyli tak lepiej?

//...
@Override
convertMap Map<String, Double> (Map<String, String> mp){
    Map<String, Double> mp2 = new HashSet<>();
    mp.entrySet().stream().forEach(x -> mp2.put(x.getKey(), Double.parseDouble(x.getValue()))); 
    return mp2;
}
//...
edytowany 2x, ostatnio: Julian_, 2017-10-30 22:28

Pozostało 580 znaków

2017-10-30 22:17
1

Raczej chodziło mi mniej więcej o coś takiego. Sensowniej tu chyba będzie też zrobić klasę abstrakcyjną zamiast interfejsu.

public abstract class MapLoader<T1, T2> {

    public  Map<T1, T2> getMap(String FILE_TO_LOAD){
        Map<T1, T2> mapResult = new HashMap<>();
        File f = new File(FILE_TO_LOAD);
        try (Scanner sc = new Scanner(f)) {
            while (sc.hasNextLine()) {
                String tmp = sc.nextLine();
                String[] tmp2 = tmp.split(";");
                mapResult.put((T1) tmp2[0], interpretData(tmp2[1]));
            }
        } catch (FileNotFoundException fntf) {
            System.err.println("File " + f.getPath() + "was not found.");
        } catch (Exception e) {
            System.err.println("Something went wrong with reading " + f.getPath());
        }
        return mapResult;
    }

    protected abstract T2 interpretData(String data); // tutaj konwersja
}

Pozostało 580 znaków

2017-10-30 22:24
0

A da się tak w Javie zrobić by nadpisywanie tej abstrakcyjnej metody było opcjonalne? Ewentualnie przekazywać ją opcjonalnie w argumentach metody jako Function ?

Chodzi o to, że większość moich słowników nie będzie wymagać tutaj konwersji, bo będzie <String, String> dla par <key, value>, więc nie chce mi się za każdym razem nadpisywać tej metody (s) -> s.

edytowany 2x, ostatnio: Julian_, 2017-10-30 22:26

Pozostało 580 znaków

Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0