我正在为3个文件(例如“ city_id”;“ country_id”;“ region_id”;“ name”)制作CSV解析器,并且遇到了通用的实例化问题。有什么办法可以解决并坚持使用DRY吗? (我看到答案可能是在构造函数中使用T,但我看不到如何在我的情况下正确使用它。)
compiling Fortran sources
Fortran f77 compiler: C:\msys64\mingw64\bin\gfortran.exe -Wall -g -ffixed-form -fno-second-underscore -O3 -funroll-loops
Fortran f90 compiler: C:\msys64\mingw64\bin\gfortran.exe -fopenmp -O3 -funroll-loops
Fortran fix compiler: C:\msys64\mingw64\bin\gfortran.exe -Wall -g -ffixed-form -fno-second-underscore -fopenmp -O3 -funroll-loops
compile options: '-Ic:\users\ben\appdata\local\temp\tmpzsrysh\src.win-amd64-2.7 -IC:\Users\Ben\Anaconda2\lib\site-packages\numpy\core\include -IC:\Users\Ben\Anaconda2\include -IC:\Users\Ben\Anaconda2\PC -c'
gfortran.exe:f90: zernsurf.f95
gfortran.exe:f77: c:\users\ben\appdata\local\temp\tmpzsrysh\src.win-amd64-2.7\zernsurf-f2pywrappers.f
could not find library 'gomp' in directories []
C:\msys64\mingw64\bin\gfortran.exe -Wall -g -Wall -g -shared ..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o ..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\users\ben\appdata\local\temp\tmpzsrysh\src.win-amd64-2.7\zernsurf-f2pywrappers.o -LC:\msys64\mingw64\lib\gcc\x86_64-w64-mingw32\7.3.0 -LC:\Users\Ben\Anaconda2\libs -LC:\Users\Ben\Anaconda2\PCbuild\amd64 -LC:\Users\Ben\Anaconda2\PC\VS9.0\amd64 -o c:\users\ben\appdata\local\temp\tmpzsrysh\Release\extra-dll\libzernsurf.NVNMLU4BAM43JLHGAZSG5DZQSFKWQ4FF.gfortran-win_amd64.dll -Wl,--allow-multiple-definition -Wl,--output-def,c:\users\ben\appdata\local\temp\tmpzsrysh\Release\libzernsurf.NVNMLU4BAM43JLHGAZSG5DZQSFKWQ4FF.gfortran-win_amd64.def -Wl,--export-all-symbols -Wl,--enable-auto-import -static -mlong-double-64
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0xb55): undefined reference to `omp_get_num_threads'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0xb62): undefined reference to `omp_get_thread_num'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0x1080): undefined reference to `omp_get_num_threads'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0x108d): undefined reference to `omp_get_thread_num'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0x15ae): undefined reference to `omp_get_num_threads'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0x15ba): undefined reference to `omp_get_thread_num'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0x5cd0): undefined reference to `GOMP_parallel'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0x5e09): undefined reference to `GOMP_parallel'
..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o:zernsurf.f95:(.text+0x659c): undefined reference to `GOMP_parallel'
collect2.exe: error: ld returned 1 exit status
error: Command "C:\msys64\mingw64\bin\gfortran.exe -Wall -g -Wall -g -shared ..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\zernsurf.o ..\..\users\ben\appdata\local\temp\tmpzsrysh\Release\users\ben\appdata\local\temp\tmpzsrysh\src.win-amd64-2.7\zernsurf-f2pywrappers.o -LC:\msys64\mingw64\lib\gcc\x86_64-w64-mingw32\7.3.0 -LC:\Users\Ben\Anaconda2\libs -LC:\Users\Ben\Anaconda2\PCbuild\amd64 -LC:\Users\Ben\Anaconda2\PC\VS9.0\amd64 -o c:\users\ben\appdata\local\temp\tmpzsrysh\Release\extra-dll\libzernsurf.NVNMLU4BAM43JLHGAZSG5DZQSFKWQ4FF.gfortran-win_amd64.dll -Wl,--allow-multiple-definition -Wl,--output-def,c:\users\ben\appdata\local\temp\tmpzsrysh\Release\libzernsurf.NVNMLU4BAM43JLHGAZSG5DZQSFKWQ4FF.gfortran-win_amd64.def -Wl,--export-all-symbols -Wl,--enable-auto-import -static -mlong-double-64" failed with exit status 1
答案 0 :(得分:1)
这是我使用Java 8可以想到的DRYest版本。
public static <T> List<T> parseCsvFile(String filePath, Function<String[], T> mapper) {
return Files.lines(new File(filePath).toPath())
.map(s -> s.replace("\"", "").split(";"))
.map(mapper)
.collect(Collectors.toList());
}
像这样使用。
List<Foo> foos = parseCsvFile("foos.csv", columns -> {
return new Foo(columns[0], columns[1], columns[2], columns[3]);
});
答案 1 :(得分:1)
在Java中行不通的是通用给定类的new T(...)
实例化。您只能将new
关键字与特定的类名一起使用。
在运行时,您的csvParcer()
方法甚至都不知道T
使用了哪个类,对于JVM,T
将被Object
替换。因此,您的方法无法知道要实例化哪个类。您需要在方法中传递一些信息,以允许您针对给定情况实例化所需的类。
一种方法是在您的方法中添加一个参数,以命名您要实例化的类:
public static <T> List<T> csvParcer(String filePath, Class<T> tClazz) {
List<T> cities = new ArrayList<>();
String line;
String[] dividedLine;
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
reader.readLine();
while ((line = reader.readLine()) != null) {
dividedLine = line.replace("\"", "").replace(";", " ").split(" ");
Constructor<T> myConstructor = tClazz.getConstructor(String.class, String.class, String.class);
T object = myConstructor.newInstance(dividedLine[0], dividedLine[1], dividedLine[2], dividedLine[3]);
cities.add(object);
}
return cities;
} catch (Exception ex) {
throw new RuntimeException("Error reading " + filePath, ex);
}
}
[顺便说一句,如果我的方法无法正确读取和解析文件,我更改了错误处理以引发异常,因为这是告诉调用者他无法获得结果的首选方法。] < / p>
缺点是您浪费了运行时性能(与读取CSV文本文件相比并不明显),并且如果您需要的类没有一个完全接受四个字符串的公共构造函数,则不会出现编译时错误
这是Leo已经提出的方法,您传入一个封装实例创建的对象-一个“工厂”对象,并且对于要从CVS阅读器获取的每个不同的T类,都需要一个对象。 Leo使用优雅的Java-8流编码样式重写了您的示例,但是在经典样式中也可以实现,更接近您的原始想法。首先,我们需要一个工厂接口:
public interface TFactory<T> {
T create(String arg0, String arg1, String arg2, String arg3);
}
解析器方法如下:
public static <T> List<T> csvParcer(String filePath, TFactory<T> factory) {
List<T> cities = new ArrayList<>();
String line;
String[] dividedLine;
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
reader.readLine();
while ((line = reader.readLine()) != null) {
dividedLine = line.replace("\"", "").replace(";", " ").split(" ");
T object = factory.create(dividedLine[0], dividedLine[1], dividedLine[2], dividedLine[3]);
cities.add(object);
}
return cities;
} catch (Exception ex) {
throw new RuntimeException("Error reading " + filePath, ex);
}
}
您可以像以下示例一样使用它:
private void example() {
TFactory<City> cityFactory = new TFactory<City>() {
@Override
public City create(String arg0, String arg1, String arg2, String arg3) {
return new City(arg0, arg1, arg2, arg3);
}
};
List<City> cities = csvParcer("C:\\temp\\cities.csv", cityFactory);
}
具有四个显式的String参数使代码比使用String []数组更为冗长,但是为您提供了额外的编译时安全性。