2015-02-02 35 views
12

Trong API Java 8 luồng, hãy gọi chars() trên đối tượng String trả về đối tượng IntStream chứa tất cả các ký tự.Java 8 Luồng: IntStream thành Chuỗi

Cách nào đúng để chuyển đổi đối tượng IntStream trả về thành String? Gọi số toArray() sẽ cho tôi số int[], không được chấp nhận bởi bất kỳ công cụ xây dựng String nào.

+0

Những lớp chứa' chars() 'phương pháp? – gvlasov

+2

Phương thức được định nghĩa trong giao diện 'CharSequence', mà' Chuỗi' thực hiện. – yyoon

Trả lời

12

Bạn có thể sử dụng toArray(), sau đó chọn phương thức khởi tạo String(int[], int, int). Điều này không hoàn toàn thỏa đáng khi chars() được chỉ định để trả lại đơn vị mã UTF-16, về cơ bản:

Trả về luồng int không kéo dài giá trị char từ chuỗi này. Bất kỳ char nào ánh xạ tới một điểm mã thay thế được truyền qua không giải thích được.

Thay vào đó, sử dụng codePoints() sẽ phù hợp hơn với nhà xây dựng này, hy vọng các điểm mã thay vì đơn vị mã UTF-16. Nếu không (với chars) nếu chuỗi gốc của bạn chứa cặp thay thế, bạn có thể thấy bạn gặp lỗi - tôi chưa thử, nhưng điều đó sẽ có ý nghĩa.

Tôi không biết cách đơn giản để làm điều này mà không chuyển đổi thành mảng trước tiên.

+0

OK. Có vẻ như an toàn hơn khi sử dụng 'codePoints()' thay vì 'chars()', mặc dù nó không quan trọng trong trường hợp của tôi bởi vì tôi chỉ làm việc trong phạm vi ASCII. Dù sao cũng cảm ơn. – yyoon

4

Đây là một ý tưởng khác:

@Test 
public void testIntStreamSequential() { 
    final String testString = "testmesoftly"; 
    IntStream is = testString.chars(); 
    String result = is.collect(
     StringBuilder::new, 
     (sb, i) -> sb.append((char)i), 
     StringBuilder::append 
     ).toString(); 
    assertEquals(testString, result); 
} 

@Test 
public void testIntStreamParallel() { 
    final String testString = "testmesoftly"; 
    IntStream is = testString.chars(); 
    String result = is.parallel().collect(
     StringBuilder::new, 
     (sb, i) -> sb.append((char)i), 
     StringBuilder::append 
     ).toString(); 
    assertEquals(testString, result); 
} 

Lưu ý rằng việc sử dụng một chuyên Collector theo đề nghị của @Lii không phải là rất hiệu quả, vì đấm bốc vì vậy bạn nên sử dụng ba tham số cấu trúc này (nhờ @holger)

+0

Tôi thực sự nghĩ về hướng này, nhưng nó có vẻ quá phức tạp cho mục đích. Tôi có một câu hỏi nhanh. Tại sao tham số thứ ba '(sb1, sb2) -> {}'? Chính xác điều này có nghĩa là gì? Phần này có được sử dụng không? Có lẽ nó chỉ có liên quan khi sử dụng các luồng song song? – yyoon

+0

Nó là bộ kết hợp, "Một hàm chấp nhận hai kết quả một phần và kết hợp chúng." Nó không được sử dụng khi sử dụng tuần tự. Tuy nhiên ví dụ của tôi là xấu xí, vì vậy tôi đã cải thiện nó và loại bỏ cảnh báo về hỗ trợ song song – rmuller

+1

'IntStream' không hỗ trợ cho' Collector 'chuyên dụng, vì vậy sử dụng phương thức' collect' ba arg là lựa chọn duy nhất (trừ khi bạn muốn hộp mỗi 'int'…). – Holger

6

tôi khá chắc chắn phải có nhiều cách để làm điều đó, nhưng một cách khác là sử dụng một StringWriter:

IntStream in = "It was the best of times".chars(); 
StringWriter sw = new StringWriter(); 
in.forEach(sw::write); 
System.out.println(sw.toString()); 

này tất cả cũng có thể được thể hiện trong một nhà sưu tập như:

IntStream in = "It was the best of times".chars(); 
String text = in.collect(
    StringWriter::new, 
    StringWriter::write, 
    (swl, swr) -> swl.write(swr.toString())).toString(); 
System.out.println(text); 
+1

Đã không nghĩ đến việc kết hợp nó với các thư viện IO. Cảm ơn. – yyoon

+2

@nullstein Nó cũng có thể được viết như là một nhà sưu tập, như phiên bản của tôi cho thấy, mặc dù tôi nghi ngờ nó làm cho nó dễ dàng hơn để đọc. Về mặt tươi sáng, nó có tính minh bạch tham chiếu tốt hơn, vì các hiệu ứng phụ được ẩn khỏi người dùng luồng. Điều này cuối cùng cũng tương tự như câu trả lời StringBuilder. –

+0

Lưu ý rằng một StringWriter là một wrapper xung quanh StringBuffer (phiên bản đồng bộ của StringBuilder) vì vậy là (tương đối) chậm hơn nhiều so với sử dụng StringBuilder – rmuller

7

sử dụng StringBuilder 's appendCodePoint phương pháp sẽ làm các trick là tốt,

IntStream in = "Convert me to a String".codePoints(); 

String intStreamToString = in.collect(StringBuilder::new, 
     StringBuilder::appendCodePoint, StringBuilder::append) 
     .toString(); 

System.out.println(intStreamToString); 
+0

Vâng, nhưng điều này cũng có vấn đề mã đơn vị/mã điểm không khớp @ jon-skeet chỉ ra . 'Chars()' trả về luồng của _code units_, trong khi 'appendCodePoint' dự kiến ​​nhận _code points_, như tên cho thấy. – yyoon

Các vấn đề liên quan