简体   繁体   中英

Stream a list of n-integers from a file to create n object array

Assume each T object can be instantiated as

T tobj = new T(//int value);

So to create an array of T[ ] from integers in a file seperated by space I do the following:

 BufferedReader br;
 FileReader fr;
 int[] arr;
 try{               
        fr = new FileReader(fo); // assume "fo" file name
        br = new BufferedReader(fr);
        arr = Arrays.stream(br.readLine().split("\\s")).mapToInt(Integer::parseInt).toArray();

 }catch(SomeException e){//something else}

T[] tobjarr = new T[arr.length];
    for(int i=0; i<arr.length; ++i)){
        tobjarr[i] = new T(arr[i]);
    }

1.Is the above method efficient in terms of time and space usage?

2.Is there any other way? if so how does it compare to above method?

In general your approach is fine. However, you can do that with a single stream cascade . Compared to your original approach this saves you one iteration .

Also note that nowadays we read files using Javas new I/O API called NIO . One big advantage is that it offers Stream methods. For example the Files#lines method that returns a stream over all lines of the file, perfectly suited for your approach.

So all in all, here is the complete code:

String file = ...
Pattern separator = Pattern.compile("\\s");

try (Stream<String> lines = Files.lines(Paths.get(file))) {
    T[] values = lines                      // Stream<String> lines
        .flatMap(separator::splitAsStream)  // Stream<String> words
        .mapToInt(Integer::parseInt)        // IntStream values
        .mapToObj(T::new)                   // Stream<T> valuesAsT
        .toArray(T[]::new);
} catch (IOException e) {
    System.out.println("Something went wrong.");
}

Note that this code is slightly different to yours, as yours will only process one line and mine all lines . You may change that if you don't want it:

List<T[]> valuesPerLine = Files.lines(Paths.get(file))  // Stream<String> lines
    .map(separator::splitAsStream)  // Stream<Stream<String>> wordsPerLine
    .map(lineStream -> {
        return lineStream                 // Stream<String> words
            .mapToInt(Integer::parseInt)  // IntStream values
            .mapToObj(T::new)             // Stream<T> valuesAsT
            .toArray(T[]::new);
    })                              // Stream<T[]> valuesPerLine
    .collect(Collectors.toList());

The main difference to your original approach is that we can easily transform an IntStream into a Stream<T> by using mapToObj(T::new) (or just map if it's a regular stream and not IntStream ) which passes the elements to the constructor. After that we collect Stream<T> into an array by using toArray(T[]::new) .

T[] array = Arrays.stream(br.readLine().split("\\s"))
    .map(s -> new T(Integer.parseInt(s)))
    .toArray(T[]::new)

EDIT: noticed that you're using a different delimiter

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM