Если InputStream не закрывать, то в теории ничего фатального не произойдет, ну будут лишние ресурсы болтаться, ну и ладно. Если у вас богато с ними, то можно пережить. А вот не закрытие OutputStream это грозит фатальными последствиями. Самая распространенная история - это недописанный последний буфер. Метод close() можно не вызывать, если вы используете try-with-resources. Что такое InputStream и OutputStream? Абстрактные классы InputStream и OutputStream нужны для того, чтобы абстрагировать различные способы ввода и вывода, независимо от того, является ли поток файлом, вебстраницей или картинкой. InputStream используется для считывания информации. OutputStream используется для записи информации. Почему важно закрывать потоки? При закрытии потока освобождаются все выделенные для него ресурсы, например, файл. В случае, если поток окажется не закрыт, может произойти утечка памяти. Какие потоки можно не закрывать (не вызывать метод close())? В JDK 7 метод close() определяется интерфейсом AutoCloseable и можно явно не закрывать поток, а использовать оператор try-with-resources, в котором в неявно созданном finally будет вызываться метод close(). Что делает метод available() Метод available() проверяет, есть ли данные в файле и возвращает примерное количество доступных для чтения байтов. Можно ли использовать flush() для небуферизированного потока Метод flush() для небуферезированного потока использовать можно, т.к исходя из документации, "среда хоста может выполнять свою собственную буферизацию, неизвестную Java. В этом случае запись можешь кэшироваться в буферах ОС". На каком паттерне основана иерархия потока ввода вывода Объекты классов Java, которые используются для ввода/вывода, для обеспечения необходимой функциональности наслаиваются друг на друга. Такая модель взаимодействия объектов возможна в паттерне "Декоратор". В этом паттерне, при создании потока, нужно использовать несколько объектов. Что делает метод read(), почему он возвращает int а не байт, почему не может вернуть byte Метод read() используется для чтения символов. Данный метод возвращает кол-во только что прочитанных символов (целое число от 0 до 65635) или -1, если достиг конца stream(потока). Он возвращает int, потому что диапазон byte в Java лежит от -127 до 127, а возвращаемое значение метода read() лежит в диапазоне от 0 до 255. Чтобы получит представление byte в int, в методе read() используется побитовое "И" с числом 255, т.е убираются лидирующие единицы. Что вернёт метод read() если считает -1 Если методу read() встречается байт равный -1, то он вернет значение, к которому применилось побитовое "И" с числом 255. Т.е вернёт 255. Для чего нужен Scanner? Сканер нужен для считывания данных из источника, который мы для него указываем. Например, из строки, файла или консоли. Далее он распознает эту информацию и обрабатывает нужным образом. Сканер выполняет поиск токенов во входной строке. Что такое токен в Scanner? Токен — это серия цифровых или буквенно-цифровых символов, которые заканчиваются разделителем. Отличие Scanner'a от BufferedReader'a BufferedReader имеет значительно большую буферную память (8192 символа), чем . Используйте BufferedReader, если необходимо просто получить длинные строки из потока, и используйте , если хотите разобрать определенный тип токенов из потока. BufferedReader является синхронным, а — нет. Используйте , если хотите работать с несколькими потоками. Scanner скрывает IOException, в то время как бросает его немедленно. Есть ли у сканера буфер? У сканера есть буфер, но он довольно маленький — всего 1024 символа. Абсолютный и относительный путь Абсолютный путь всегда содержит корневой элемент и полный список каталогов, для нахождения файла. Например: "c:\\windows\\projects\\note.txt" — это абсолютный путь. Для проверки, является ли путь абсолютным, есть метод isAbsolute(). Относительный путь необходимо соединить с другим путем, чтобы получить доступ к файлу. Например, joe/foo — это относительный путь. Без дополнительной информации, программа не сможет достоверно определить местоположение каталога joe/foo в файловой системе. Методы класса File createNewFile() - создает новый файл по пути, который передан в конструкторе; delete() - удаляет каталог или файл по пути, который передан в конструкторе; exists() - проверяет, существует ли по указанному в конструкторе пути файл или каталог; getAbsolutePath() - возвращает абсолютный путь для пути, который передан в конструктор getName() - возвращает краткое имя файла или каталога length() - возвращает размер файла в байтах mkdir() - создает новый каталог и при удачном создании возвращает значение true Как создать файл на компьютере с помощью Java? Для создания нового файла, во время инициализации объекта File, мы должны предоставить ему имя файла, а затем создать сам новый файл вызовом метода createNewFile(). Создать файл в Java с помощью объекта File можно тремя способами: 1. Передав в объект абсолютный путь 2. Указать только имя файла 3. Указать относительный путь Как удалить директорию с файлами. Что если в ней есть вложенные директории? Чтобы удалить директорию с файлами, сначала необходимо удалить сами файлы в папке, а затем и саму папку. В чём отличие File от Path File - класс, самая старая версия работы с папками и файлами Его методы возвращают тру/фолс Path - интерфейс, гораздо новый, его методы выбрасывают исключение в случае проблем Что такое клонирование. Как реализовано клонирование в Java? Иногда нужно на основе существующего объекта создать второй такой же, то есть - создать его клон. Этот процесс в Java называется клонированием. Клонировать объект в Java можно тремя способами: 1. Переопределение метода clone() и реализация интерфейса Cloneable; 2. Использование конструктора копирования; 3. Использовать для клонирования механизм сериализации; Клонирование объекта. Глубокое и поверхностное. Поверхностное копирование копирует настолько маленькую часть, насколько это возможно. По умолчанию, копирование в Java является поверхностным, т.е Object class не знает о структуре класса, которого он копирует. Копируются значения простых полей и ссылочные значения. Сначала необходимо переопределить метод clone() как public. В переопределенном методе следует вызвать базовую версию метода super.clone(), которая и выполняет клонирование. Класс должен реализовывать интерфейс Cloneable. Глубокое копирует поля ссылочных (объектных) типов, созданы новые, но эквивалентные экземпляры полей. Глубокое копирование — это две коллекции, в одну из которых дублируются все элементы оригинальной коллекции. Мы хотим сделать копию, при которой внесение любых изменений в копию не затронет оригинальную коллекцию. Чем отличается копирование от клонирования? При копировании объектов, мы создаем не новый объект, а объект, который ссылается на копируемый. Т.е изменения, которые мы произведем во втором объекте, будут так же отражены и в первом. При клонировании, мы создаем отдельную копию первого объекта, но со своей собственной ссылкой. При этом каждый объект будет иметь свою собственную ссылку. Можно ли клонировать String, массив String? Класс String представляет неизменяемую строку. Нет смысла клонировать String. Если вы чувствуете, что вам нужно клонировать его, вы можете просто повторно использовать ту же ссылку и добиться того же эффекта. Даже если бы вы могли clone s1 как s2, тогда s1 != s2 все равно был бы true. Они по-прежнему будут ссылками на отдельные объекты. Массив String клонировать можно, т.к он реализует интерфейс Cloneable Что такое сериализация и десериализация? Сериализация — процесс сохранения состояния объекта в последовательность байт. Десериализация — процесс восстановления объекта из этих байт. Любой Java объект можно преобразовать в последовательность байт. Одно уточнение — чтобы появилась возможность сериализовать объект, он должен наследовать интерфейс Serializable. Данный интерфейс не имеет каких-либо методов, а просто дает понять системе, что объект, который реализует его, может быть сериализован. Для сериализации объектов в поток используется класс ObjectOutputStream. Он записывает данные в поток. Для десериализации используется класс ObjetInputStream Назовите несколько форматов сериализации Основные форматы сериализации: JSON YAML XML BSON Как сериализовать объект класса? Чтобы сериализовать объект класса, мы сначала создаем файл, в который будем записывать объект, затем преобразуем объект в байты и с помощью метода writeObject() сохраняем. Что делать, если одно из полей сериализовывать не нужно? Чтобы сериализовать определенные поля, можно воспользоваться одним из двух методов: 1. Использовать ключевое слово transient 2. Вместо реализации Seriazable использовать его расширение — интерфейс Externalizable При использовании слова transient мы явно указываем, какое поле или поля не нужно сериализовывать. При использовании интерфейса Externalizable нам необходимо переопределить два метода writeExternal() и readExternal(). В методе writeExternal() мы указываем, какие поля будут сериализованы, а в readExternal() как прочитать эти поля. Как сериализовать статическое поле? При стандартной сериализации, поля с модификатором static не сериализуются. Соответственно, после десериализации это поле значение не поменяет. При использовании реализации Externalizable сериализовать и десериализовать статическое поле можно, но не рекомендуется этого делать, т.к. это может сопровождаться трудноуловимыми ошибками. Externalizable vs Serializable При записи Serializable класса весь контроль над сериализацией достается JVM. Интерфейс Externalizable расширяет Serializable и добавляет методы записи и чтения writeExternal и readExternal. Этот интерфейс позволяет реализовать полностью свой механизм сериализации, стандартно запишется только идентификатор класса. Что если при десериализации поменять тип? Если при десериализации поменять тип поля, то можно получить исключение ClassCastException. Например, если при десериализации я захочу изменить тип данных со строки на список, то получу исключение, потому что он не может преобразовать строку в список. Что будет при сериализации объекта у которого есть поле и оно не Serializable? Если это поле находится в классе, от которого наследуется класс, над которым будет проходить сериализация, то это поле должно быть доступно напрямую или через геттеры и сеттеры классу, над которым будет проходить сериализация. В этом классе придется реализовать пользовательскую сериализацию. Ещё один из приемлемых вариантов — это пометить поле transient, чтобы оно игнорировалось во время процессов сериализации и десериализации. Особенность сериализации поля final Поля с модификатором final сериализуются, как обычные. За одним исключением — их невозможно десериализовать при использовании Externalizable. Отличие пакетов 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 Что такое паттерн адаптер и паттерн декоратор Паттерн проектирования адаптер — это такой шаблон проектирования, который позволяет обернуть несовместимые объекты в адаптер, чтобы сделать их совместимыми друг с другом. Паттерн проектирования декоратор — шаблон декоратор позволяет вам динамически изменять поведение объекта во время работы, оборачивая их в объект класса декоратора. Представим, что у вас есть свой автосервис. Как вы будете рассчитывать сумму в счете за услуги? Вы выбираете одну услугу и динамически добавляете к ней цены на предоставляемые услуги, пока не получите окончательную стоимость. Здесь каждый тип сервиса является декоратором. что делает flush? выполнится ли flush если мы сделаем close? Flush очищает буфер и скидывает содержимое в поток Да, выполнится В соответствии с документами java, вызывая close() на любом потоке java.io, автоматически вызывает flush(). Но я видел много примеров, даже в производственных кодексах разработчики явно использовали flush() непосредственно перед close() Разница между mkdir и mkdirs javadocs для mkdirs() : Создает каталог с именем этого абстрактного пути, включая все необходимые, но несуществующие родительские каталоги. Обратите внимание, что в случае сбоя этой операции, возможно, удалось создать некоторые из необходимых родительских каталогов. javadocs для mkdir() : Создает каталог с именем этого абстрактного пути.