Главная страница

Ревью 5. Если InputStream не закрывать


Скачать 38.22 Kb.
НазваниеЕсли InputStream не закрывать
АнкорРевью 5
Дата14.12.2022
Размер38.22 Kb.
Формат файлаdocx
Имя файлаРевью 5.docx
ТипДокументы
#845646

Если InputStream не закрывать, то в теории ничего фатального не произойдет, ну будут лишние ресурсы болтаться, ну и ладно. Если у вас богато с ними, то можно пережить.

А вот не закрытие OutputStream это грозит фатальными последствиями. Самая распространенная история - это недописанный последний буфер.
Метод close() можно не вызывать,

если вы используете try-with-resources.
Что такое поток? И какими они бывают в Java?

Это такие абстрактные сущности, которые последовательно выполняют инструкции программы. Потоки протекают в процессе, а процесс, простыми словами, — это любая запущенная программа. Поток в Java представлен в виде экземпляра класса java.lang.Thread. Стоит сразу понимать, что экземпляры класса Thread в Java сами по себе не являются потоками. Это лишь своего рода API для низкоуровневых потоков, которыми управляет JVM и операционная система. Когда при помощи java launcher'а мы запускаем JVM, она создает главный поток с именем main и ещё несколько служебных потоков.

Существует 2 типа потоков: демоны и не демоны. Демон-потоки — это фоновые потоки (служебные), выполняющие какую-то работу в фоне.
Что такое InputStream и OutputStream?

Абстрактные классы InputStream и OutputStream нужны для того, чтобы абстрагировать различные способы ввода и вывода, независимо от того, является ли поток файлом, веб- страницей или картинкой.

InputStream используется для считывания информации. OutputStream используется для записи информации.

Что такое System.in, что такое System.out?


System.in — это "стандартный" поток ввода и объект InputStream. Этот поток уже открыт и готов к подаче входных данных. Обычно этот поток соответствует вводу с клавиатуры или другому источнику ввода, заданному окружением хоста или пользователем.
System.out — это "стандартный" поток вывода и объект PrintStream. Этот поток уже открыт и готов к приему выходных данных. Обычно этот поток соответствует выводу на дисплей или другому месту вывода, указанному окружением хоста или пользователем.

Какие интерфейсы реализует InputStream/ OutputStream/ Reader/ Writer?

InputStream реализует интерфейсы: Closeable и AutoCloseable
OutputStream реализует интерфейсы: Closeable, Flushable, AutoCloseable
Reader реализует интерфейсы: Closeable, AutoCloseable, Readable
Writer реализует интерфейсы: Closeable, Flushable, Appendable, AutoCloseable
На каком паттерне основана иерархия потоков ввода/вывода?

Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга. Такая модель взаимодействия объектов поддерживается в паттерне «Декоратор». В этом паттерне при создании потока нужно использовать несколько объектов.
Почему важно закрывать потоки?

При закрытии потока освобождаются все выделенные для него ресурсы, например, файл. В случае, если поток окажется не закрыт, может произойти утечка памяти

.

Какие потоки можно не закрывать (не вызывать метод close())?

В JDK 7 метод close() определяется интерфейсом AutoCloseable и можно явно не закрывать поток, а использовать оператор try-with-resources, в котором в неявно созданном finally будет вызываться метод close().

Что делает метод available()

Метод available() проверяет, есть ли данные в файле и возвращает примерное количество доступных для чтения байтов.
Можно ли использовать flush() для небуферизированного потока

Метод flush() для небуферезированного потока использовать можно, т.к исходя из документации, "среда хоста может выполнять свою собственную буферизацию, неизвестную Java. В этом случае запись можешь кэшироваться в буферах ОС".
На каком паттерне основана иерархия потока ввода вывода

Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга.

Такая модель взаимодействия объектов возможна в паттерне "Декоратор". В этом паттерне, при создании потока, нужно использовать несколько объектов.
как работает метод read?

При каждом вызове метод read() читает байт из файла и возвращает его как целочисленное значение. По достижении конца файла этот метод возвращает значение -1. При возникновении ошибки метод генерирует исключение IOException.
Что делает метод read(), почему он возвращает int а не байт, почему не может вернуть byte

Метод read() используется для чтения символов.

Данный метод возвращает кол-во только что прочитанных символов (целое число от 0 до 65635) или -1, если достиг конца stream(потока).

Он возвращает int, потому что диапазон byte в Java лежит от -127 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255.

Чтобы получит представление byte в int, в методе read() используется побитовое "И" с числом 255, т.е убираются лидирующие единицы.
Что возвращает перегруженный read? Какое максимальное значение вернет?

Перегруженный read вернет -1 (65635 байта), а максимальное значение 65634 байта
Что вернёт метод read() если считает -1, а -3

Если методу read() встречается байт равный -1, то он вернет значение, к которому применилось побитовое "И" с числом 255. Т.е вернёт 255.

В консоль выводится 253, а не -3. т. к. метод read() возвращает не само значение byte, а его представление в 32х битном виде. Диапазон byte в Java лежит от -128 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255.
что такое scanner

Scanner класс в java.util для чтение данных примитивных типов int, double, string и т.д. Это самый простой способ для получения входящих данных,

Для чего нужен Scanner?

Сканер нужен для считывания данных из источника, который мы для него указываем. Например, из строки, файла или консоли. Далее он распознает эту информацию и обрабатывает нужным образом.

Сканер выполняет поиск токенов во входной строке.

Что такое токен в Scanner?

Токен (или маркер) представляет собой серию цифровых или буквенно-цифровых символов, которая заканчивается разделителем. Разделителем может быть символ табуляции, возврат каретки (перевод строки или же просто ‘Enter’), конец файла или пробел.

Пример: если пользователем был введен ряд чисел с пробелами между каждым номером, то класс Scanner будет принимать все номера в качестве отдельного токена. В этом случае пробельные символы выступают в качестве разделителей.

Отличие Scanner'a от BufferedReader'a
Scanner позволяет разобрать строку на составляющие (токены), с помощью различных разделителей. Он не синхронизирован и , также не выбрасывает исключения.
BufferedReader предназначен для чтения потока символов с буферизацией.
java.util.Scanner - это в первую очередь сканер текста. Он использует регулярные выражения, чтобы выделить нужные типы данных из строки: nextInt(), nextDouble() и т.д.

java.io.BufferedReader просто читает последовательность символов. Это быстрее, чем Scanner, но расшифровывать это нужно вручную.
BufferedReader  размер буфера

Размер буфера BufferedReader по умолчанию составляет 8 Кбайт.
Есть ли у сканера буфер?

У сканера есть буфер, но он довольно маленький — всего 1024 символа.
Абсолютный и относительный путь

Абсолютный путь всегда содержит корневой элемент и полный список каталогов, для нахождения файла. Для проверки, является ли путь абсолютным, есть метод isAbsolute().

Относительный путь представляет собой путь по отношению к текущему рабочему каталогу пользователя или активных приложений.

Что такое канонический путь?


Канонический путь зависит от системы.
Обычно, если (полный) путь содержит псевдонимы, ярлыки или символические ссылки, канонический путь разрешает все это в фактические каталоги, на которые они ссылаются. Путь, который не содержит ничего из перечисленного ниже:

  1. жесткиессылки в собственный (.) и родительский (..) каталоги

  2. повторяющиеся разделители (/)

  3. символические ссылки

класс File

В Java класс File представляет файлы и пути каталогов в абстрактной манере. Этот класс используется для создания, поиска, удаления файлов и каталогов и т.д.. File-объект представляет собой фактический файл или каталог на диске. Класс File, определенный в пакете java.io, не работает напрямую с потоками. Его задачей является управление информацией о файлах и каталогах. Хотя на уровне операционной системы файлы и каталоги отличаются, но в Java они описываются одним классом File.
Методы класса File

createNewFile() - создает новый файл по пути, который передан в конструкторе;

delete() - удаляет каталог или файл по пути, который передан в конструкторе;

exists() - проверяет, существует ли по указанному в конструкторе пути файл или каталог; getAbsolutePath() - возвращает абсолютный путь для пути, который передан в конструктор getName() - возвращает краткое имя файла или каталога

length() - возвращает размер файла в байтах

mkdir() - создает новый каталог и при удачном создании возвращает значение true
Как создать файл на компьютере с помощью Java?

Для создания нового файла, во время инициализации объекта File, мы должны предоставить ему имя файла, а затем создать сам новый файл вызовом метода createNewFile().

Создать файл в Java с помощью объекта File можно тремя способами:

1. Передав в объект абсолютный путь

2. Указать только имя файла

3. Указать относительный путь

Как удалить директорию с файлами. Что если в ней есть вложенные директории?

Необходимо воспользоваться методом delete(Path path) класса Files. Директория будет удалена только если она пустая. Вложенные директории удаляются с помощью рекурсии.

Чтобы удалить директорию с файлами, сначала необходимо удалить сами файлы в папке, а затем и саму папку.
В чём отличие File от Path

File - класс, самая старая версия работы с папками и файлами

Его методы возвращают тру/фолс

Path - интерфейс, гораздо новый, его методы выбрасывают исключение в случае проблем
Что такое клонирование. Как реализовано клонирование в Java?

Иногда нужно на основе существующего объекта создать второй такой же, то есть - создать его клон. Этот процесс в Java называется клонированием.

Клонировать объект в Java можно тремя способами:

1. Переопределение метода clone() и реализация интерфейса Cloneable;

2. Использование конструктора копирования;

3. Использовать для клонирования механизм сериализации;
Клонирование объекта. Глубокое и поверхностное.

Поверхностное копирование

копирует настолько маленькую часть, насколько это возможно. По умолчанию, копирование в Java является поверхностным, т.е Object class не знает о структуре

класса, которого он копирует. Копируются значения простых полей и ссылочные значения.

Сначала необходимо переопределить метод clone() как public. В переопределенном методе следует вызвать базовую версию метода super.clone(), которая и выполняет клонирование.

Класс должен реализовывать интерфейс Cloneable.

Глубокое копирует поля ссылочных (объектных) типов, созданы новые, но эквивалентные экземпляры полей. Глубокое копирование — это две коллекции, в одну из которых дублируются все элементы оригинальной коллекции. Мы хотим сделать копию, при которой внесение любых изменений в копию не затронет оригинальную коллекцию.
Какое клонирование в java по умолчанию?

По умолчанию, клонирование в Java является поверхностным, т.е. Object class не знает о структуре класса, которого он копирует.
Чем отличается копирование от клонирования?

При копировании объектов, мы создаем не новый объект, а объект, который ссылается на копируемый. Т.е изменения, которые мы произведем во втором объекте, будут так же отражены и в первом.

При клонировании, мы создаем отдельную копию первого объекта, но со своей собственной ссылкой. При этом каждый объект будет иметь свою собственную ссылку.
Можно ли клонировать String, массив String?

Класс String представляет неизменяемую строку. Нет смысла клонировать String. Если вы чувствуете, что вам нужно клонировать его, вы можете просто повторно использовать ту же ссылку и добиться того же эффекта.

Даже если бы вы могли clone s1 как s2, тогда s1 != s2 все равно был бы true. Они по-прежнему будут ссылками на отдельные объекты.

Массив String клонировать можно, т.к он реализует интерфейс Cloneable
Что за интерфейс Serializable?
1) Интерфейс java.io.Serializable - это интерфейс-маркер, в нем нет методов.
2) Если класс реализует интерфейс, это говорит сериализующему механизму, что этот класс можно сериализовать.

Что такое сериализация и десериализация?

Сериализация — процесс сохранения состояния объекта в последовательность байт. Десериализация — процесс восстановления объекта из этих байт.

Любой Java объект можно преобразовать в последовательность байт.

Одно уточнение — чтобы появилась возможность сериализовать объект, он должен наследовать интерфейс Serializable.

Данный интерфейс не имеет каких-либо методов, а просто дает понять системе, что объект, который реализует его, может быть сериализован.

Для сериализации объектов в поток используется класс ObjectOutputStream. Он записывает данные в поток.

Для десериализации используется класс ObjetInputStream
Назовите несколько форматов сериализации

Основные форматы сериализации:

1. JSON - JavaScript Object Notation
2. XML
3. BinarySON - тот же JSON только в двоичном представлении.
4. YAML - Yet Another Markup Language
Какие объекты можно сериализовать?

Сериализовать можно только те объекты, которые реализуют интерфейс Serializable. Этот интерфейс не определяет никаких методов, просто он служит указателем системе, что объект, реализующий его, может быть сериализован. Объект сериализуется вместе с объектами на которые он ссылается, они ьо же должны быть помечены!
Как сериализовать объект класса?

Чтобы сериализовать объект класса, мы сначала создаем файл, в который будем записывать объект, затем преобразуем объект в байты и с помощью метода writeObject() сохраняем.
Что делать, если одно из полей сериализовывать не нужно?

Чтобы сериализовать определенные поля, можно воспользоваться одним из двух методов:

1. Использовать ключевое слово transient

2. Вместо реализации Seriazable использовать его расширение — интерфейс Externalizable

При использовании слова transient мы явно указываем, какое поле или поля не нужно сериализовывать.

При использовании интерфейса Externalizable нам необходимо переопределить два метода writeExternal() и readExternal(). В методе writeExternal() мы указываем, какие поля будут сериализованы, а в readExternal() как прочитать эти поля.
Какие поля не сериализуются?

имеющие модификатор static
Как сериализовать статическое поле?

При стандартной сериализации, поля с модификатором static не сериализуются. Соответственно, после десериализации это поле значение не поменяет.

При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками.
Externalizable vs Serializable

1) Externalizable extends Serializable
2) Интерфейс Serializable полностью реализует виртуальная машина JVM.
3) Интерфейс Externalizable имеет методы writeExternal() и readExternal(), которые позволяют вручную указать - какие поля записывать. Это может в том числе повысит производительность.

Он дает гораздо большую гибкость, мы можем управлять процессами сериализации и десериализации как хотим.

Производительность под вопросом.
Безопасность. Можно шифровать данные.

Может дать немалый выигрыш по объему сериализованных данных.

Сериализация потомков сериализованных родителей.

Если суперкласс является сериализуемым, то по умолчанию сериализуемым является каждый подкласс. Следовательно, даже если подкласс не реализует сериализуемый интерфейс (и если его суперкласс реализует сериализуемый), тогда мы можем сериализовать объект подкласса.



Что если при десериализации поменять тип?

Если при десериализации поменять тип поля, то можно получить исключение ClassCastException.

Например, если при десериализации я захочу изменить тип данных со строки на список, то получу исключение, потому что он не может преобразовать строку в список.
Особенность сериализации поля final?

Можно ли сериализовать и десериализовать final переменную с помощью Externalizable?

Поля с модификатором final сериализуются как и обычные. За одним исключением – их невозможно десериализовать при использовании Externalizable, поскольку final-поля должны быть инициализированы в конструкторе, а после этого в readExternal изменить значение этого поля будет невозможно. Соответственно, если необходимо сериализовать объект с final-полем неоходимо использовать только стандартную сериализацию.
Что будет при сериализации объекта у которого есть поле и оно не Serializable?

  1. В таком случае код скомпилируется.
    2) Но в рантайме при попытке сериализации , когда мы дойдем до этого поля и объекта, мы получим NotSerializableException.


Особенность сериализации поля final

Поля с модификатором final сериализуются, как обычные. За одним исключением — их невозможно десериализовать при использовании Externalizable.
Как преобразовать считанные байты в символы? Какой класс для этого используется?

InputStreamReader является мостом от потоков байтов до символьных потоков, читает байты и декодирует их в символы, используя указанную кодировку charset.
Отличие пакетов IO и NIO, InputStream от Reader.

Основное отличие IO от NIO в том, что IO потокоориентированный , а NIO буферо-ориентированным

Потокоориентированный ввод/вывод подразумевает чтение/запись из потока/в поток одного или нескольких байт в единицу времени поочередно.

Подход, на котором основан Java NIO немного отличается. Данные считываются в буфер для последующей обработки

.

Блокирующий и неблокирующий ввод/вывод

Потоки ввода/вывода (streams) в Java IO являются блокирующими.

Это значит, что когда в потоке выполнения (tread) вызывается read() или write() метод любого класса из пакета java.io.*, происходит блокировка до тех пор, пока данные не будут считаны или записаны. Поток выполнения в данный момент не может делать ничего другого.

Неблокирующий режим Java NIO позволяет запрашивать считанные данные из канала (channel) и получать только то, что доступно на данный момент, или вообще ничего, если доступных данных пока нет. Вместо того, чтобы оставаться заблокированным пока данные не станут доступными для считывания, поток выполнения может заняться чем-то другим.


InputStream и Reader

InputStream - это сырой метод получения информации из ресурса. Он захватывает данные байт за байтом, не выполняя никакого перевода. Если вы читаете данные изображения или любой двоичный файл, этот поток следует использовать.

Reader предназначен для потоков символов. Если информация, которую вы читаете, полностью состоит из текста, то Reader позаботится о декодировании символов и предоставит символы юникода из необработанного входного потока.
Что такое System.in, что такое System.out?

System.in — это "стандартный" поток ввода и объект InputStream. Этот поток уже открыт и готов к подаче входных данных. Обычно этот поток соответствует вводу с клавиатуры или другому источнику ввода, заданному окружением хоста или пользователем.

System.out — это "стандартный" поток вывода и объект PrintStream. Этот поток уже открыт и готов к приему выходных данных. Обычно этот поток соответствует выводу на дисплей или другому месту вывода, указанному окружением хоста или пользователем.
Что такое потоки ввода и вывода. Как это реализовано в Java?

Разделяют 2 вида потоков байтовые и системные.

Байтовые: java.io.InputStream,java.io.OutputStream;

Символьные: java.io.Reader, java.io.Writer;
Какие интерфейсы реализует InputStream/ OutputStream/ Reader/ Writer?

InputStream реализует интерфейсы: Closeable и AutoCloseable

OutputStream реализует интерфейсы: Closeable, Flushable, AutoCloseable

Reader реализует интерфейсы: Closeable, AutoCloseable, Readable

Writer реализует интерфейсы: Closeable, Flushable, Appendable, AutoCloseable

Что такое паттерн адаптер и паттерн декоратор
Паттерн проектирования адаптер — это такой шаблон проектирования, который позволяет обернуть несовместимые объекты в адаптер, чтобы сделать их совместимыми друг с другом.

Паттерн проектирования декоратор — шаблон декоратор позволяет вам динамически изменять поведение объекта во время работы, оборачивая их в объект класса декоратора.

Представим, что у вас есть свой автосервис. Как вы будете рассчитывать сумму в счете за услуги? Вы выбираете одну услугу и динамически добавляете к ней цены на предоставляемые услуги, пока не получите окончательную стоимость. Здесь каждый тип сервиса является декоратором.
Пример адаптера и декоратора из IO

примеры использования Адаптера это java.io.InputStreamReader и OutputStreamWriter.

Примеры Декораторов java.io.InputStreamOutputStream
что делает flush? выполнится ли flush если мы сделаем close?

Flush очищает буфер и скидывает содержимое в поток

Да, выполнится

В соответствии с документами java, вызывая close() на любом потоке java.io, автоматически вызывает flush(). Но я видел много примеров, даже в производственных кодексах разработчики явно использовали flush() непосредственно перед close()
Гарантируется ли запись данных в файл при вызове flush ?

Если целевым назначением этого потока является абстракция, предоставляемая базовой операционной системой, например файл, то очистка потока гарантирует только то, что байты, ранее записанные в поток, передаются операционной системе для записи; это не гарантирует, что они действительно записаны на физическое устройство, такое как жесткий диск.
Можно ли использовать flush() для небуферизированного потока и что будет?

Метод flush() для небуферезированного потока использовать можно, т.к исходя из документации, "среда хоста может выполнять свою собственную буферизацию, неизвестную Java. В этом случае запись можешь кэшироваться в буферах ОС".

Разница между mkdir и mkdirs

javadocs для mkdirs() :
Создает каталог с именем этого абстрактного пути, включая все необходимые, но несуществующие родительские каталоги. Обратите внимание, что в случае сбоя этой операции, возможно, удалось создать некоторые из необходимых родительских каталогов.

javadocs для mkdir() :
Thread и Runnable, что выбрать ? Зачем нужно два вида реализации

многопоточности; какую из них и когда использовать?

Thread - это класс, некоторая надстройка над физическим потоком.

Runnable - это интерфейс, представляющий абстракцию над выполняемой задачей.

Помимо того, что Runnable помогает разрешить проблему множественного наследования, несомненный плюс от его использования состоит в том, что он позволяет логически отделить логику выполнения задачи от непосредственного управления потоком.

Реализация интерфейса Runnable используется в случаях, когда класс уже наследует какой-либо родительский класс и не позволяет расширить класс Thread. К тому же хорошим тоном программирования в java считается реализация интерфейсов. Это связано с тем, что в java может наследоваться только один родительский класс. Таким образом, унаследовав класс Thread, невозможно наследовать какой-либо другой класс.

Расширение класса Thread целесообразно использовать в случае необходимости переопределения других методов класса помимо метода run().


написать администратору сайта