Dlaczego char [] to jedyne tablice nieobsługiwane przez Arrays.stream ()?

43

Podczas omawiania sposobów konwertowania prymitywnych tablic na strumienie okazało się, że char[]nie są one obsługiwane, podczas gdy obsługiwane są inne pierwotne typy tablic. Czy jest jakiś konkretny powód, aby pominąć je w strumieniu?

ghostrider
źródło
3
stackoverflow.com/questions/22435833/... W tym wątku IMO odpowiada na podobne pytanie
Mark Bramnik

Odpowiedzi:

31

Jak powiedział Eran, nie tylko on zaginął.

A BooleanStreambyłby bezużyteczny, a ByteStream(jeśli istniałby ) może być traktowany jako InputStreamlub konwertowany na IntStream(jak może short) i floatmoże być obsługiwany jako DoubleStream.

Ponieważ i chartak nie jest w stanie reprezentować wszystkich znaków (patrz link), byłby to nieco starszy strumień. Chociaż większość ludzi i tak nie musi mieć do czynienia ze współrzędnymi kodowymi, więc może się to wydawać dziwne. Mam na myśli, że używasz String.charAt()bez myślenia „to nie działa we wszystkich przypadkach”.

Dlatego niektóre rzeczy zostały pominięte, ponieważ nie uznano ich za tak ważne. Jak powiedział JB Nizet w powiązanym pytaniu :

Projektanci wyraźnie postanowili uniknąć eksplozji klas i metod, ograniczając prymitywne strumienie do 3 typów, ponieważ inne typy (char, short, float) mogą być reprezentowane przez ich większy odpowiednik (int, double) bez żadnej znaczącej utraty wydajności.

Powód BooleanStreambyłby bezużyteczny, ponieważ masz tylko 2 wartości, co znacznie ogranicza operacje. Nie trzeba wykonywać żadnych operacji matematycznych, a jak często pracujesz z wieloma wartościami logicznymi?

Kayaman
źródło
7
„A BooleanStreambyłoby bezużyteczne”: dlaczego?
glglgl
12
Czy naprawdę nieuzasadnione jest zakładanie, że ktoś może potrzebować np. reduce(Boolean::logicalAnd)Lub reduce(Boolean::logicalOr)na boolean[]? W końcu metody logicalAndi logicalOrzostały dodane w Javie 8, więc mogę wykonać te operacje redukcji Stream<Boolean>… Nawiasem mówiąc, możesz przesyłać strumieniowo char[]tak łatwo CharBuffer.wrap(array).chars()lub CharBuffer.wrap(array).codePoints(), w zależności od tego, który semantyczny preferujesz.
Holger
2
@Holger tylko dlatego Boolean::logicalAnd, że istnieje, niekoniecznie gwarantuje istnienie BooleanStream. Można ich jednak użyć w sytuacjach, w których lambda nie jest strumieniowe. Mogę sobie wyobrazić, że ktoś chce zrobić reduce(Boolean::logicalAnd), ale w żadnym wypadku nie będzie nikomu potrzebę , aby to zrobić.
Kayaman
4
Nie rozumiem, jaki argument masz na myśli. W swojej ekstremalnej formie: „Mogę sobie wyobrazić, że ktoś chciałby to zrobić while (i < limit), ale w żadnym wypadku nikt nie musi tego robić [za pomocą instrukcji montażu oddziału i skoku]”
Alexander - Przywróć Monikę
11
Wydaje mi się, że jedynym powodem, <Primitive>Streamdla którego nie ma każdego prymitywnego typu, jest to, że nadmiernie nadyma API. Prawidłowe pytanie, które należy zadać, brzmi „dlaczego IntStreamw ogóle jest?” a niefortunną odpowiedzią jest to, że system typów Java nie jest wystarczająco rozbudowany, aby wyrazić Stream<int>bez całego wydatku związanego z wydajnością Integer. Gdyby Java miała typy wartości, które mogłyby być przypisane do stosu lub osadzone bezpośrednio w innych strukturach danych, nie byłoby takiej potrzeby poza niczym innymStream<T>
Alexander - Przywróć Monikę
32

Oczywiście odpowiedź brzmi „ bo tak postanowili projektanci ”. Nie ma technicznego powodu, dla CharStreamktórego nie mógłby istnieć.

Jeśli potrzebujesz uzasadnienia, zwykle musisz zmienić listę mailingową OpenJDK *. Dokumentacja JDK nie ma zwyczaju uzasadniać, dlaczego coś jest, dlaczego tak jest.

Ktoś zapytał

Używanie IntStream do reprezentowania strumienia char / bajtów jest nieco niewygodne. Czy powinniśmy również dodać CharStream i ByteStream?

Odpowiedź Briana Goetza (architekta języka Java) mówi

Krótka odpowiedź: nie.

Każda z tych formularzy, które prawie nigdy nie są używane, nie jest warta więcej niż 100 000 JDK. Gdybyśmy to dodali, ktoś zażądałby krótkiego, zmiennoprzecinkowego lub logicznego.

Innymi słowy, gdyby ludzie upierali się, że mamy wszystkie prymitywne specjalizacje, nie mielibyśmy prymitywnych specjalizacji. Co byłoby gorsze niż status quo.

Źródło

On również mówi to samo w innym miejscu

Jeśli chcesz traktować je jako znaki, możesz z łatwością zrzucić je na znaki. Nie wydaje się wystarczająco ważnym przypadkiem użycia, aby mieć cały „inny zestaw strumieni”. (To samo z Short, Byte, Float).

Źródło

TL; DR: Nie warte kosztów utrzymania.


* Jeśli jesteś ciekawy, użyłem zapytania Google

site:http://mail.openjdk.java.net/ charstream
Michał
źródło
2
Czy ktoś mógłby wyjaśnić, co mają na myśli 100K+ of JDK footprint?
yassin
3
@yassin Ktoś musi napisać kod. Szacuje, że każda specjalizacja strumienia zawiera ponad 100 000 wierszy kodu
Michael
3
@BulgarSadykov Takie pytania dotyczące „ dlaczego X jest jak Y ” są często zamykane jako oparte na opiniach, ponieważ nie można odczytać myśli oryginalnego autora i, chyba że się pojawią, wszystko, co otrzymasz, to domysł. Jeśli zapytam „jak wysłać żądanie POST za pomocą klienta HTTP Apache?”, Każdy, kto zna bibliotekę, może na to odpowiedzieć. Dlaczego biblioteka jest zaprojektowana w taki sposób, że zwykle nie jest możliwe udzielenie odpowiedzi. Jedynym powodem dla którego jesteśmy w stanie odpowiedzieć na to naprawdę jest, ponieważ istnieje rejestrów publicznych z ich rozmów. Właśnie do tego dążyłem w pierwszym zdaniu.
Michael
2
@BulgarSadykov przypomina to również, wspomina blog Erica Lipperta o C #, ale na temat „dlaczego funkcja Foo nie jest zaimplementowana w języku” stackoverflow.com/a/5588850/479251
Pac0
2
@BulgarSadykov Z poważaniem się nie zgadzam. Ponownie powtarzam moje przykładowe pytanie „ jak wysłać żądanie POST za pomocą klienta HTTP Apache? ”. Odpowiedź na to pytanie wyraźnie nie zaczyna się od „ ponieważ tak postanowili projektanci ”. Przepraszam, nie zmieniam sformułowania.
Michael
7

To nie tylko char tablice nie są obsługiwane.

Są tylko 3 rodzaje strumieni - prymitywnych IntStream, LongStreami DoubleStream.

W efekcie, Arraysma metody konwersji int[], long[]i double[]do odpowiednich pierwotnych strumieni.

Brak odpowiednich metod boolean[], byte[], short[], char[]i float[], ponieważ te typy pierwotne nie ma odpowiedniego pierwotne strumienie.

Eran
źródło
4
„Ponieważ te pierwotne typy nie mają odpowiadających im pierwotnych strumieni”. Następnie pytanie brzmiałoby „dlaczego”?
Federico klez Culloca
7
@FedericoklezCulloca na pytanie uzupełniające można znaleźć odpowiedź tutaj
Eran
6

charjest zależną częścią String- przechowywania wartości UTF-16. Symbol Unicode, punkt kodowy , jest czasem zastępczą parą znaków. Tak więc każde proste rozwiązanie z znakami obejmuje tylko część domeny Unicode.

Był czas, który charmiał własne prawo do bycia typem publicznym. Ale w dzisiejszych czasach lepiej jest użyć punktów kodowych , IntStream. Strumień zwęglenia nie był w stanie bezpośrednio poradzić sobie z parami zastępczymi.

Innym bardziej prozaicznym powodem jest to, że model „procesora” JVM używa intnajmniejszego „rejestru”, utrzymując wartości logiczne, bajty, skróty, a także znaki w takiej wielkości pamięci. Aby niekoniecznie nadmuchać klasy Java, jedna powstrzymała się od wszystkich możliwych wariantów kopiowania.

W dalekiej przyszłości można oczekiwać, że prymitywne typy będą mogły działać jako ogólne parametry parametrów, pod warunkiem, że List<int>. Wtedy możemy zobaczyć Stream<char>.

Na razie lepiej unikać char, a może używać java.text.Normalizerunikalnej kanonicznej formy punktów kodowych / ciągów znaków Unicode.

Joop Eggen
źródło