2015-06-13 49 views
6

Tôi có một file văn bản như thế này:Cách tạo mảng hai chiều từ luồng trong Java 8?

ids.txt

1000 
999 
745 
123 
... 

Tôi muốn đọc tập tin này và tải nó trong một mảng hai chiều. Tôi hy vọng sẽ có một mảng tương tự như hình dưới đây:

Object[][] data = new Object[][] { // 
    { new Integer(1000) }, // 
    { new Integer(999) }, // 
    { new Integer(745) }, // 
    { new Integer(123) }, // 
    ... 
}; 

Đây là mã tôi đã viết:

File idsFile = ... ; 
try (Stream<String> idsStream = Files.lines(idsFile.toPath(), StandardCharsets.US_ASCII)) { 
    Object[][] ids = idsStream 
     .filter(s -> s.trim().length() > 0) 
     .toArray(size -> new Object[size][]); 

    // Process ids array here... 
} 

Khi chạy mã này, một ngoại lệ được nâng lên:

java.lang.ArrayStoreException: null 
at java.lang.System.arraycopy(Native Method) ~[na:1.8.0_45] 
at java.util.stream.SpinedBuffer.copyInto(Unknown Source) ~[na:1.8.0_45] 
at java.util.stream.Nodes$SpinedNodeBuilder.copyInto(Unknown Source) ~[na:1.8.0_45] 
at java.util.stream.SpinedBuffer.asArray(Unknown Source) ~[na:1.8.0_45] 
at java.util.stream.Nodes$SpinedNodeBuilder.asArray(Unknown Source) ~[na:1.8.0_45] 
at java.util.stream.ReferencePipeline.toArray(Unknown Source) ~[na:1.8.0_45] 
... 

Làm thế nào có thể giải quyết ngoại lệ này?

+0

Tại sao 'mới Integer (1000) '? Và bạn muốn một '[] []' trong đó mảng bên trong luôn luôn có 'length == 1'? –

+0

@BoristheSpider Các id được chuyển đến thư viện của bên thứ ba chỉ chấp nhận 'Object [] []' làm đầu vào. – Stephan

Trả lời

11

Cho một Stream<String> bạn có thể phân tích từng hạng mục để một int và quấn nó thành một Object[] sử dụng:

strings 
     .filter(s -> s.trim().length() > 0) 
     .map(Integer::parseInt) 
     .map(i -> new Object[]{i}) 

Bây giờ để biến kết quả đó vào một Object[][] bạn chỉ cần làm:

Object[][] result = strings 
     .filter(s -> s.trim().length() > 0) 
     .map(Integer::parseInt) 
     .map(i -> new Object[]{i}) 
     .toArray(Object[][]::new); 

Đối với đầu vào:

final Stream<String> strings = Stream.of("1000", "999", "745", "123"); 

Output:

[[1000], [999], [745], [123]] 
+5

Nếu bạn nghi ngờ rằng các chuỗi có thể không thường xuyên có dấu cách trước và sau, thì tốt hơn nên thêm bước 'trim' riêng biệt:' strings.map (String :: trim) .filter (s ->! S.isEmpty()) ' . Ngoài ra tôi sẽ sử dụng 'Integer :: valueOf' thay vì' Integer :: parseInt' vì nó khớp với kiểu mong muốn tốt hơn ('Integer', chứ không phải' int'). Mặc dù có lẽ đó là vấn đề về hương vị. –

+0

@TagirValeev Tại sao "tốt hơn để thêm bước cắt riêng biệt"? – Stephan

+2

@Stephan: theo cách này bạn có thể phân tích các tệp có dấu cách sau số (như '" 1 \ n2 \ n3 \ n "'). Hiện tại bạn sẽ có 'NumberFormatException' trên các tệp như vậy. –

5

Dòng cuối cùng của bạn có thể là size -> new Object[size], nhưng bạn sẽ cần phải cung cấp mảng Số nguyên của kích thước một và bạn cũng cần phải phân tích chuỗi thành Số nguyên.

Tôi đề nghị như sau:

try (Stream<String> idsStream = Files.lines(idsFile.toPath(), StandardCharsets.US_ASCII)) { 
    Object[][] ids = idsStream 
     .map(String::trim) 
     .filter(s -> !s.isEmpty()) 
     .map(Integer::valueOf) 
     .map(i -> new Integer[] { i }) 
     .toArray(Object[][]::new); 

    // Process ids array here... 
} 
Các vấn đề liên quan