В Java: почему некоторые методы Stream принимают int вместо байта или даже char? - PullRequest
3 голосов
/ 30 июня 2010

Почему некоторые методы, которые записывают bytes/chars в потоки, принимают int вместо byte/char ??

Кто-то сказал мне в случае in т вместо char: потому что char в java имеет длину всего 2 байта, что нормально с большинством символьных символов, которые уже используются, но для определенных символьных символов (слитков или чего-либо еще) символ представляется более чем в 2 байта, и поэтому мы используем int вместо этого.

Насколько это объяснение близко к истине?

EDIT: Я использую слово stream для представления двоичных и символьных потоков (не только двоичных)

Спасибо.

Ответы [ 6 ]

5 голосов
/ 01 июля 2010

Кто-то сказал мне в случае int вместо char: поскольку char в java имеет длину всего 2 байта, что нормально для большинства символов, которые уже используются, но для определенных символов (китайских или любых других),символ представляется более чем в 2 байтах, и, следовательно, мы используем вместо него int.

Предполагая, что в данный момент вы говорите конкретно о методе Reader.read(), утверждении "кого-то", что выдействительно: неверно .

Это правда, что некоторые кодовые точки Unicode имеют значения больше 65535 и поэтому не могут быть представлены как один Java char.Однако API Reader фактически создает последовательность значений Java char (или -1), а не последовательность кодовых точек Unicode.Это ясно указано в javadoc .

Если ваш входной сигнал содержит (надлежащим образом закодированную) кодовую точку Unicode, которая больше 65535, то вам фактически потребуется дважды вызвать метод read()чтобы увидеть это.То, что вы получите, будет суррогатной парой UTF-16;то есть два значения Java char, которые вместе представляют кодовую точку.Фактически, это соответствует тому, как работают классы Java String, StringBuilder и StringBuffer;все они используют представление на основе UTF-16 ... со встроенными суррогатными парами.

Реальная причина, по которой Reader.read() возвращает int, а не char, состоит в том, чтобы позволить ему возвратить -1 всигнал о том, что больше нет символов для чтения.Та же логика объясняет, почему InputStream.read() возвращает int, а не byte.

Гипотетически, я предполагаю, что разработчики Java могли бы указать, что методы read() выдают исключение, сигнализирующее о состоянии "конца потока".Однако это просто заменило бы один потенциальный источник ошибок (неспособность проверить результат) другим (неспособность справиться с исключением).Кроме того, исключения относительно дороги, и конец потока на самом деле не является неожиданным / исключительным событием.Короче говоря, нынешний подход лучше, IMO.

(Еще один ключ к 16-битной природе API Reader - это сигнатура метода read(char[], ...). Как это будет работать с кодовыми точками, превышающими 65535?если суррогатные пары не использовались?)

РЕДАКТИРОВАТЬ

Случай DataOutputStream.writeChar(int) кажется немного странным.Однако в javadoc четко указано, что аргумент записывается в виде 2-байтового значения.И на самом деле, реализация явно записывает только два нижних байта в базовый поток.

Я не думаю, что для этого есть все основания.В любом случае для этого есть запись в базе данных об ошибках ( 4957024 ), которая помечена как «11-Closed, Not a Defect» со следующим комментарием:

»Это не лучший дизайн или оправдание, но он слишком запятнан, чтобы мы могли его изменить. "

... что является подтверждением того, что является дефект, по крайней мере, с точки зрения дизайна.

Но это не то, что стоит суетиться, ИМО.

3 голосов
/ 30 июня 2010

Я не совсем уверен, что вы имеете в виду, но, возможно, вы думаете о InputStream.read () ? Он возвращает целое число вместо байта, потому что возвращаемое значение перегружено, чтобы также представлять конец потока, который представлен как -1. Поскольку существует 257 различных возможных возвращаемых значений, байта недостаточно.

В противном случае, возможно, вы могли бы привести более конкретные примеры.

2 голосов
/ 01 июля 2010

Есть несколько возможных объяснений.

Во-первых, как отметили несколько человек, это может быть из-за того, что read() обязательно возвращает int, и поэтому можно считать элегантным, что write () принимает int, чтобы избежать приведения:

int read = in.read();
if ( read != -1 )
   out.write(read);
//vs
   out.write((byte)read);

Во-вторых, было бы неплохо избежать других случаев кастинга:

//write a char (big-endian)
char c;
out.write(c >> 8);
out.write(c);

//vs
out.write( (byte)(c >> 8) );
out.write( (byte)c );
0 голосов
/ 30 июня 2010

возможно, будет симметричным с методом read (), который возвращает int.ничего серьезного.

0 голосов
/ 30 июня 2010

В Java потоки предназначены для необработанных байтов.Чтобы писать символы, вы помещаете поток в Writer.

В то время как Writer s имеют write(int) (который записывает 16 младших битов; это int, потому что байт слишком мал, а short слишком мал из-за того, что он подписан), вы должны использовать write(char[]) или write(String) вместо.

0 голосов
/ 30 июня 2010

Правильно, что максимально возможная кодовая точка равна 0x10FFFF, что не вписывается в символ. Однако методы потока ориентированы на байты, а методы записи - 16-разрядные. OutputStream.write (int) записывает один байт, а Writer.write (int) просматривает только младшие 16 бит.

...