24 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку

Содержание

Класс InputStream

Базовый класс InputStream представляет классы, которые получают данные из различных источников:

  • массив байтов
  • строка (String)
  • файл
  • канал (pipe): данные помещаются с одного конца и извлекаются с другого
  • последовательность различных потоков, которые можно объединить в одном потоке
  • другие источники (например, подключение к интернету)

Для работы с указанными источниками используются подклассы базового класса InputStream:

BufferedInputStream Буферизированный входной поток ByteArrayInputStream Позволяет использовать буфер в памяти (массив байтов) в качестве источника данных для входного потока. DataInputStream Входной поток, включающий методы для чтения стандартных типов данных Java FileInputStream Для чтения информации из файла FilterInputStream Абстрактный класс, предоставляющий интерфейс для классов-надстроек, которые добавляют к существующим потокам полезные свойства. InputStream Абстрактный класс, описывающий поток ввода ObjectInputStream Входной поток для объектов StringBufferInputStream Превращает строку (String) во входной поток данных InputStream PipedInputStream Реализует понятие входного канала. PushbackInputStream Входной поток, поддерживающий однобайтовый возврат во входной поток SequenceInputStream Сливает два или более потока InputStream в единый поток

  • int available() — возвращает количество байтов ввода, доступные в данный момент для чтения
  • close() — закрывает источник ввода. Следующие попытки чтения передадут исключение IOException
  • void mark(int readlimit) — помещает метку в текущую точку входного потока, которая остаётся корректной до тех пор, пока не будет прочитано readlimint байт
  • boolean markSupported() — возвращает true, если методы mark() и reset() поддерживаются потоком
  • int read() — возвращает целочисленное представление следующего доступного байта в потоке. При достижении конца файла возвращается значение -1
  • int read(byte[] buffer) — пытается читать байты в буфер, возвращая количество прочитанных байтов. По достижении конца файла возвращает значение -1
  • int read(byte[] buffer, int byteOffset, int byteCount) — пытается читать до byteCount байт в buffer, начиная с смещения byteOffset. По достижении конца файла возвращает -1
  • reset() — сбрасывает входной указатель в ранее установленную метку
  • long skip(long byteCount) — пропускает byteCount байт ввода, возвращая количество проигнорированных байтов

Как преобразовать InputStream в строку

  1. Using IOUtils.toString (Apache Utils):
  2. Using CharStreams (guava)
  3. Using Scanner (JDK)
    символ «А» является символом начала текста, таким образом вызов next() вернет сразу всю строку.
  4. Using Stream Api (Java 8). Warning: This solution convert different linebreaks (like rn) to n.
  5. Using parallel Stream Api (Java 8). Warning: This solution convert different linebreaks (like rn) to n.
  6. Using InputStreamReader and StringBuilder (JDK)
  7. Using StringWriter and IOUtils.copy (Apache Commons)
  8. Using ByteArrayOutputStream and inputStream.read (JDK)
  9. Using BufferedReader (JDK). Warning: This solution convert different linebreaks (like nr) to line.separator system property (for example, in Windows to «rn»).
  10. Using BufferedInputStream and ByteArrayOutputStream (JDK)
  11. Using inputStream.read() and StringBuilder (JDK). Warning: This soulition has problem with Unicode, for example with Russian text (work correctly only with non-Unicode text)

Warning:
Solutions 4, 5 and 9 convert different linebreaks to one.
Soulution 11 can’t work correclty with Unicode text

BufferedInputStream

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

У класса есть конструктор, где размер буфера устанавливается по умолчанию. Также можно использовать конструктор, где размер буфера устанавливается вручную. Рекомендуется использовать размеры буфера, кратные размеру страницы памяти, дисковому блоку и т.п. и может зависеть от принимающей операционной системы, объёма доступной памяти и конфигурации машины.

ByteArrayInputStream

Класс ByteArrayInputStream использует байтовый массив в качестве источника данных. У данного класса можно не вызывать метод close().

DataInputStream — Форматированное чтение из памяти

Для чтения байтовых данных (не строк) применяется класс DataInputStream. В этом случае необходимо использовать классы из группы InputStream.

Для преобразования строки в массив байтов, пригодный для помещения в поток ByteArrayInputStream, в классе String предусмотрен метод getBytes(). Полученный ByteArrayInputStream представляет собой поток InputStream, подходящий для передачи DataInputStream.

При побайтовом чтении символов из форматированного потока DataInputStream методом readByte() любое полученное значение будет считаться действительным, поэтому возвращаемое значение неприменимо для идентификации конца потока. Вместо этого можно использовать метод available(), который сообщает, сколько еще осталось символов.

Класс DataInputStream позволяет читать элементарные данные из потока через интерфейс DataInput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных.

FileInputStream

Класс FileInputStream создаёт объект класса InputStream, который можно использовать для чтения байтов из файла.

  • FileInputStream (File file) — указывается объекта типа File
  • FileInputStream (FileDescriptor fd)
  • FileInputStream (String path) — указывается полное имя файла

При создании объект открывается для чтения. Класс переопределяет методы класса InputStream, кроме методов mark() и reset().

Для чтения байтов входного потока из файла используется конструкция:

PushbackInputStream

Разновидность буферизации, обеспечивающая чтение байта с последующим его возвратом в поток. Класс PushbackInputStream представляет механизм «заглянуть» во входной поток и увидеть, что оттуда поступит в следующий раз, не извлекая информации.

У класса есть дополнительный метод unread().

SequenceInputStream

Класс SequenceInputStream позволяет соединять вместе несколько экземпляров класса InputStream. Конструктор принимает в качестве аргумента либо пару объектов класса InputStream, либо интерфейс Enumeration.

Во время работы класс выполняет запросы на чтение из первого объекта класса InputStream и до конца, а затем переключается на второй. При использовании интерфейса работа продолжится по всем объектам класса InputStream. По достижении конца каждого файла, связанный с ним поток закрывается. Закрытие потока, созданного объектом класса SequenceInputStream, приводит к закрытию всех открытых потоков.

SavePearlHarbor

Ещё одна копия хабора

Главное меню

Навигация по записям

Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку

У меня есть хобби: я собираю различные решения типовых задач в Java, которые нахожу в инете, и пытаюсь выбрать наиболее оптимальное по размеру/производительности/элегантности. В первую очередь по производительности. Давайте рассмотрим такую типовую задач, которые часто встречаются в программировании на Java как «преобразование InputStream в строку» и разные варианты её решения.

Посмотрим какие ограничения есть у каждого (требования подключения определенной библиотеки/определенной версии, корректная работа с unicode и т.д.). Английскую версию этой статьи можно найти в моем ответе на stackoverflow. Тесты в моем проекте на github.

Если вы ещё не видели, советую посмотреть статью Список полезных ссылок для Java программиста, на мой взгляд наиболее полезная из всех моих статей на данный момент.

Преобразование InputStream в строку (String)

Очень часто встречающая задача, давайте рассмотрим какими способами можно это сделать (их будет 11):

Используя IOUtils.toString из библиотеки Apache Commons . Один из самых коротких однострочников.

Используя CharStreams из библиотеки guava . Тоже довольно короткий однострочник.

Используя Scanner (JDK). Решение короткое, хитрое, с помощью чистого JDK, но это скорее хак, который вынесет мозг тем кто о таком фокусе не знает.

Используя Stream Api с помощью Java 8 . Предупреждение: Оно заменяет разные переносы строки (такие как rn ) на n , иногда это может быть критично.

Используя parallel Stream Api ( Java 8 ). Предупреждение: Как и 4 решение, оно заменяет разные переносы строки (такие как rn ) на n .

Используя InputStreamReader и StringBuilder из обычного JDK

Используя StringWriter и IOUtils.copy из Apache Commons

Используя ByteArrayOutputStream и inputStream.read из JDK

Используя BufferedReader из JDK . Предупреждение: Это решение заменяет разные переносы строк (такие как nr ) на line.separator system property (например, в Windows на «rn»).

Используя BufferedInputStream и ByteArrayOutputStream из JDK

Используя inputStream.read() и StringBuilder ( JDK ). Предупреждение: Это решение не работает с Unicode, например с русским текстом

Итак о использовании:

Решения 4 , 5 и 9 преобразую разные переносы строки в одну.

Решения 11 не работает с Unicode текстом

  • Решение 1 , 7 требует использование библиотеки Apache Commons, 2 требует библиотеку Guava, 4 и 5 требуют Java 8 и выше,
  • Замеры производительности

    Предупреждение: замеры производительности всегда сильно зависят от системы, условий замера и т.п. Я измерял на двух разных компьютерах, один Windows 8.1, Intel i7-4790 CPU 3.60GHz2, 16Gb, второй — Linux Mint 17.2, Celeron Dual-Core T3500 2.10Ghz2, 6Gb, однако не могу гарантировать что результаты являются абсолютной истиной, вы всегда можете повторить тесты (test1 и test2) на вашей системе.

    Читать еще:  Расширение для сортировки и организации подписок YouTube

    Замеры производительности для небольших строк (длина = 175), тесты можно найти на github (режим = среднее время выполнения (AverageTime), система = Linux Mint 17.2, Celeron Dual-Core T3500 2.10Ghz*2, 6Gb, чем значение ниже тем лучше, 1,343 — наилучшее):

    Замеры производительности для больших строк (длина = 50100), тесты можно найти на github (режим = среднее время выполнения (AverageTime), система = Linux Mint 17.2, Celeron Dual-Core T3500 2.10Ghz*2, 6Gb, чем значение ниже тем лучше, 200,715 — наилучшее):

    График зависимости среднего времени от длины строки, система Windows 8.1, Intel i7-4790 CPU 3.60GHz 3.60GHz, 16Gb:

    Таблица зависимости среднего времени от длины строки, система Windows 8.1, Intel i7-4790 CPU 3.60GHz 3.60GHz, 16Gb:

    Выводы

    Самым быстрым решением во всех случаях и всех системах оказался 8 тест: Используя ByteArrayOutputStream и inputStream.read из JDK

    Коротким и весьма быстрым решением будет использование IOUtils.toString из Apache Commons

    Stream Api из Java 8 показывает среднее время, а использование параллельных стримов имеет смысл только при довольно большой строки, иначе он работает очень долго (что в общем-то было ожидаемо)

  • Решение 11 лучше не использовать в принципе, так как он работает медленнее всех и не работает с Unicode,
  • P.S.

    1. Английскую версию этой статьи можно найти в моем ответе на stackoverflow. Тесты в моем проекте на github. Если эта статья вам понравилась и вы поставите плюс на stackoverflow/звезду на github’е буду вам благодарен.
    2. Буду очень благодарен за любые замечания, исправления, указания на ошибки или другие способы преобразования InputStream в строку
    3. Если вы ещё не видели, советую посмотреть статью Список полезных ссылок для Java программиста, на мой взгляд наиболее полезная из всех моих статей на данный момент.

    Java: InputStream. Потоки ввода

    Java, как и многие современные языки программирования, поддерживает реализацию потоков ввода данных. В Java InputStream является базовым классом для байтовых потоков. Данный класс является абстрактным, то есть в процессе работы программы мы не можем создавать его экземпляр. Однако в пакете io имеется множество классов, которые наследуют и расширяют функциональность InputStream. Чтобы использовать этот класс в своем коде, его нужно импортировать из пакета java.io.InputStream. Далее мы рассмотрим базовую функциональность, которую предоставляет класс InputStream, а также основные классы, реализующие его.

    Методы класса InputStream

    Прежде чем приступить к подробному изучению методов класса InputStream, следует упомянуть, что он реализует интерфейсы Closeable и AutoCloseable. Интерфейс Closeable говорит нам о том, что при завершении работы с потоком его необходимо обязательно закрыть. Делается это при помощи метода close(). Поскольку большинство методов класса InputStream в случае возникновения ошибки генерирует исключение типа IOException, все операции требуется проводить в блоке try, а метод close() выносить в блок finally, чтобы он сработал вне зависимости от результата работы в теле try.

    Интерфейс AutoCloseable значительно сокращает объем технического кода, поскольку позволяет методу close() срабатывать автоматически и не добавлять в ваш код блок finally. Если вы используете седьмую или более позднюю версию Java, InputStream можно помещать в так называемый try с ресурсами, который все операции по закрытию потоков берет на себя.

    Рассмотрим основные методы класса InputStream:

    • int available() – возвращает доступное для чтения количество байтов;
    • int read() – берет из ресурса текущий байт и возвращает его в целочисленном представлении; если все байты прочитаны, возвращает -1;
    • int read(byte[] буфер) – читает доступные байты в указанный буфер в виде массива типа byte (количество читаемых байтов равно размеру заданного буфера; возвращает количество байтов, которые удалось прочитать; если все доступные байты прочитаны, возвращает -1);
    • int read(byte[] буфер, int смещение, int количество байтов) – перегрузка предыдущего метода, делает то же самое, но с указанной в «смещении» позиции и читает столько, сколько задано в «количестве байтов»;
    • long skip(long количество байтов) – пропускает указанное количество байтов и возвращает фактическое количество пропущенных.

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

    Чтение файлов

    Байтовый поток для чтения информации из файлов реализуется классом FileInputStream. Для того чтобы открыть файл для чтения байтов, достаточно создать экземпляр данного класса, передав его конструктору имя файла в качестве аргумента. Если файла с переданным именем не существует, будет сгенерировано исключение типа FileNotFoundException.

    В случае удачного открытия файла, работа с ним выполняется при помощи описанных выше методов, так как FileInputStream является наследником InputStream.

    Чтение примитивных типов данных

    В предыдущем примере описывалась работа с байтовыми значениями, которые можно интерпретировать как символы. Но как быть, если нам необходимо прочитать целочисленное, дробное или логическое значение? Для этого в Java InputStream косвенно расширяется классом DataInputStream. Данный класс является оболочкой для InputStream, который передается ему при создании в качестве аргумента конструктора. Такого рода поток читает данные в бинарном виде.

    DataInputStream также реализует интерфейс DataInput и его методы для чтения примитивных типов данных. Ниже представлен список этих методов.

    Названия методов говорят сами за себя – каждый из них предназначен для чтения определенного типа данных.

    Буферизированный поток ввода

    Буферизированный поток чтения данных реализуется классом BufferedInputStream в Java. InputStream заключается в оболочку этим классом. Данный класс дополняет поток буфером, что позволяет читать одновременно не один, а несколько байтов. Это дает возможность значительно повысить производительность операции. BufferedInputStream является непрямым потомком InputStream и, соответственно, наследует все указанные выше методы.

    Данный класс имеет два конструктора:

    • BufferedInputStream(InputStream поток ввода);
    • BufferedInputStream(InputStream поток ввода, int размер буфера)

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

    Заключение

    Мы рассмотрели основные реализации InputStream. Если вам нужно преобразовать полученные байты в строку, то в Java InputStream to String(), к сожалению, не перегружен, поэтому для этого придется использовать специальные утилиты, например IOUtils из библиотеки Apache Commons.

    Собеседование по Java — потоки ввода/вывода (вопросы и ответы)

    Вопросы и ответы для собеседования Java по теме — потоки ввода/вывода.

    К списку вопросов по всем темам

    Вопросы

    1. Какие существуют виды потоков ввода/вывода?
    2. Назовите основные предки потоков ввода/вывода.
    3. Что общего и чем отличаются следующие потоки: InputStream, OutputStream, Reader, Writer?
    4. Что вы знаете о RandomAccessFile?
    5. Какие есть режимы доступа к файлу?
    6. В каких пакетах лежат классы-потоки?
    7. Что вы знаете о классах-надстройках?
    8. Какой класс-надстройка позволяет читать данные из входного байтового потока в формате примитивных типов данных?
    9. Какой класс-надстройка позволяет ускорить чтение/запись за счет использования буфера?
    10. Какие классы позволяют преобразовать байтовые потоки в символьные и обратно?
    11. Какой класс предназначен для работы с элементами файловой системы (ЭФС)?
    12. Какой символ является разделителем при указании пути к ЭФС?
    13. Как выбрать все ЭФС определенного каталога по критерию (например, с определенным расширением)?
    14. Что вы знаете об интерфейсе FilenameFilter?
    15. Что такое сериализация?
    16. Какие условия “благополучной” сериализации объекта?
    17. Какие классы позволяют архивировать объекты?

    Ответы

    1. Какие существуют виды потоков ввода/вывода?

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

    Система ввода/вывода: http://developer.alexanderklimov.ru/android/java/io.php
    Oracle Lesson: Basic I/O tutorial: https://docs.oracle.com/javase/tutorial/essential/io/

    2. Назовите основные предки потоков ввода/вывода.

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

    Символьные: java.io.Reader, java.io.Writer;

    3. Что общего и чем отличаются следующие потоки: InputStream, OutputStream, Reader, Writer?

    Базовый класс InputStream представляет классы, которые получают данные из различных источников:
    — массив байтов
    — строка (String)
    — файл
    — канал (pipe): данные помещаются с одного конца и извлекаются с другого
    — последовательность различных потоков, которые можно объединить в одном потоке
    — другие источники (например, подключение к интернету)

    Класс OutputStream — это абстрактный класс, определяющий потоковый байтовый вывод. В этой категории находятся классы, определяющие, куда направляются ваши данные: в массив байтов (но не напрямую в String; предполагается что вы сможете создать их из массива байтов), в файл или канал.

    Символьные потоки имеют два основных абстрактных класса Reader и Writer, управляющие потоками символов Unicode. Класс Reader — абстрактный класс, определяющий символьный потоковый ввод. Класс Writer — абстрактный класс, определяющий символьный потоковый вывод. В случае ошибок все методы класса передают исключение IOException.

    4. Что вы знаете о RandomAccessFile?

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

    Работа с классом RandomAccessFile напоминает использование совмещенных в одном классе потоков DataInputStream и DataOutputStream (они реализуют те же интерфейсы DataInput и DataOutput). Кроме того, метод seek() позволяет переместиться к определенной позиции и изменить хранящееся там значение.

    При использовании RandomAccessFile необходимо знать структуру файла. Класс RandomAccessFile содержит методы для чтения и записи примитивов и строк UTF-8.

    Читать еще:  Как сделать скриншот в Word

    5. Какие есть режимы доступа к файлу?

    RandomAccessFile может открываться в режиме чтения («r») или чтения/записи («rw»). Также есть режим «rws», когда файл открывается для операций чтения-записи и каждое изменение данных файла немедленно записывается на физическое устройство.

    6. В каких пакетах лежат классы-потоки?

    Классы потоков вводавывода лежат в java.io; С JDK 7 добавлен более современный способ работы с потоками — Java NIO. Классы лежат в java.nio. Для работы с архивами используются классы из пакета java.util.

    7. Что вы знаете о классах-надстройках?

    Классы-надстройки наделяют существующий поток дополнительными свойствами. Примеры классов: BufferedOutputStream , BufferedInputStream , BufferedWriter — буферизируют поток и повышают производительность.

    8. Какой класс-надстройка позволяет читать данные из входного байтового потока в формате примитивных типов данных?

    Для чтения байтовых данных (не строк) применяется класс DataInputStream. В этом случае необходимо использовать классы из группы InputStream.

    Для преобразования строки в массив байтов, пригодный для помещения в поток ByteArrayInputStream, в классе String предусмотрен метод getBytes(). Полученный ByteArrayInputStream представляет собой поток InputStream, подходящий для передачи DataInputStream.

    При побайтовом чтении символов из форматированного потока DataInputStream методом readByte() любое полученное значение будет считаться действительным, поэтому возвращаемое значение неприменимо для идентификации конца потока. Вместо этого можно использовать метод available(), который сообщает, сколько еще осталось символов.

    Класс DataInputStream позволяет читать элементарные данные из потока через интерфейс DataInput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных.

    Конструктор: DataInputStream(InputStream stream)
    Методы: readDouble(), readBoolean(), readInt()

    9. Какой класс-надстройка позволяет ускорить чтение/запись за счет использования буфера?

    Для этого используются классы, позволяющие буферизировать поток:
    java.io.BufferedInputStream(InputStream in) || BufferedInputStream(InputStream in, int size),
    java.io.BufferedOutputStream(OutputStream out) || BufferedOutputStream(OutputStream out, int size),
    java.io.BufferedReader(Reader r) || BufferedReader(Reader in, int sz),
    java.io.BufferedWriter(Writer out) || BufferedWriter(Writer out, int sz)

    10. Какие классы позволяют преобразовать байтовые потоки в символьные и обратно?

    OutputStreamWriter — мост между классом OutputStream и классом Writer. Символы, записанные в поток, преобразовываются в байты.

    Java вопрос. Реализация ввода данных

    1). InputStream inputStream = System.in;

    2). Reader inputStreamReader = new InputStreamReader(inputStream);

    3). BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

    4). String name = bufferedReader.readLine();

    5). String sAge = bufferedReader.readLine();

    6). int nAge = Integer.parseInt(sAge);

    Вопрос только по первой строке

    1. InputStream это абстрактный класс. Создать объект его типа невозможно. По сути мы создаём ссылку inputStream на класс System и метод in? Т.е. System.in будет работать с классом InputStream в паре?

    Переменная System.in имеет тип InputStream

    Но, как вы отметили, InputStream абстрактный, то есть, нельзя создать переменную этого класса. И да, на самом деле System.in ссылается на объект класса FileInputStream

    Представьте такой код где-то в недрах пакета java.io:

    public static InputStream in;

    FileInputStream stdinFileHandle = new FileInputStream(0);

    System.in = stdinFileHandle; // System.in ссылается на этот объект, но сам объект не копируется

    То есть, реально System.in ссылается на объект класса FileInputStream, но вам об этом не следует знать, поэтому наружу (вам) отдается объект типа InputStream. И дальше вы работаете с этим FileInputStream так, как будто это InputStream

    То есть да, класс InputStream абстрактный, но ведь и его экземпляра не было создано. Все по правилам.

    Когда вы пишете

    InputStream inputStream = System.in

    это вы создаете просто ссылку на тот же объект, что и System.in. Сам этот объект как был, так и остается в единственном экземпляре.

    нашел место. иди на форум javatalks.ru

    Блин, чувак, есть же stackoverflow, cyberforum и десятки других форумов.

    дружище, у тебя там пост был с названием «Учусь Java самостоятельно», а по итогу уже 5-ый пост с вопросом.

    иди учи, что такое свойство, а что такое метод

    5 знаков, что вам пора заняться программированием (ищите себя)

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

    1. Вы ищете способ написать «скрипт» для всего: оптимальный маршрут для сбора грязной посуды в доме, шаблоны ответов в деловой переписке и так далее.

    2. Вы совсем не разбираетесь в программировании, но знаете, что вас влечет эта сфера, потому что вы понимаете — она стабильна, и IT-специалисты востребованы. Освоив специальность, вы не останетесь за бортом и всегда сможете найти работу.

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

    4. Когда-то вы случайно нажали F12 и открыли код страницы. С тех пор вы умеете вытаскивать картинки с сайтов, где их нельзя сохранить просто так.

    5. Вам нравится докапываться до сути процессов и вещей, чтобы узнать, как они работают.

    Чтобы твердо решить, что программирование — это ваше, пройдите бесплатный интенсив от GeekBrains. За два часа вы разберетесь с фундаментальными основами программирования на JavaScript, научитесь использовать переменные, ветвления и циклы. И главное: поймете, насколько программирование — то, что вам нужно. А после интенсива получите материалы и инструкции для дальнейшего развития. Вперед!

    Ты будешь плакать как тучка

    В: Ребята, посоветуйте книгу которая заставила вас плакать

    O: «Структуры данных и алгоритмы в Java», 2-е издание

    Обучение программированию на C# и Java бесплатно без регистрации и смс

    На волне поста prodigal.son’а об обучение кодингу на Ruby, в связи с избытком времени, я (Java developer) и мой лучший друг (.Net developer) готовы бесплатно помочь наставлять на путь истинный обучения програмированию пикабушников. Почему наставлять, а не проводить какие то уроки? Да потому что вся информация, курсы, книги, материалы и задачи и так разбросаны по сети. Но из-за этого избытка новички просто теряется в этом океане информации и я хочу помочь им разобраться по мере своих возможностей. А тем кто уже что то-делает и немного умеет подсказывать :).

    Сразу к делу, отвечу на несколько популярных вопросов и дам важные комментарии.

    Все ли смогут научиться программированию?

    Скажу честно, не все. На всевозможных курсах вам будут обещать золотые горы, легкий вход в отрасль, а иногда даже гарантировать 100% успех. Но мало кто расскажет о подводных камнях профессии. Профессия программиста легка на первый взгляд, также присутствуют нюансы, возможно узнав которые может от затеи учиться кодить. Поэтому вряд ли кто-то кроме вас сможет сказать получится у вас или нет. Все зависит от человека, его целей и желания. Если у тебя есть мотивация много учиться, то у тебя есть шансы.

    Почему именно Java и C#?

    С чем работаем, с тем и помогаем 🙂 Это одни из наиболее популярных языков программирования в 2020 году в мире. И к тому же высокооплачиваемые. Да, языки не самые простые. Главное не подумайте, что все обучение это изучение синтаксиса одного языка.

    Что лучше — курсы, книги или видео?

    Важно все, но еще важнее — практика, практика и еще раз практика. Кодить и кодить каждый день, причем вам должно это нравится. Если вам не будет это нравится то исход печален.

    Можно ли войти в отрасль после 30+?

    Да, можно, примеров достаточно. Тяжелее чем более молодому соискателю, но опять же, все зависит от Вас. Предрассудки в России по поводу возраста никто не отменял. Поэтому плавно переходим к следующему вопросу.

    Тяжело ли найти работу на начальную позицию?

    В 2020 году чтобы войти в IT-отрасль на позицию Junior-разработчика требования к подготовке серьезные. 10 лет назад было гораздо проще. Но не унывай падаван, IT отрасль все еще рынок соискателя, главное что-то представлять из себя ценное. Мы готовы указать на знания, твое дело их принять.

    Насколько важен английский?

    Архиважен. Без него на успех и не надейтесь. В начале со словарем, но по мере углубления в тему без английского не обойтись. Лучшие книги, онлайн курсы будут на английском и это не шутки. Поэтому готовьтесь к изучения необходимого уровня языка. Из приятных бонусов английский нужен не только в IT.

    Что насчет хороших зарплат?

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

    Самое главное, осилит путь идущий. Путь новичка нелегок. Мы будем помогать мотивировать, от вас нужна полная самоотдача и усидчивость. Лень наш главный враг и с ней мы не будем мириться.

    Как все будет происходить?

    Для всего этого я создал чат в котором мы будем отвечать на ваши вопросы в телеграм и другие пикабушники будут помогать, если мы не будем успевать отвечать:

    Также я создал канал для важной информации и плана обучения. На текущий момент уже создан небольшой FAQ для новичков. Скоро появятся важные книги.

    Также будем рады уже состоявшимся сеньорам помидорам (^_^), которые готовы будут помогать новичкам пикабушникам.

    Читать еще:  Создание электронных книг в Natata eBook Compiler Free

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

    И напоследок, в силу последних событий в мире у многих нас появилось время, которое можно потратить с пользой и «вложить» в себя. Вложиться в себя значит инвестировать в свое будущее. Так что нам надо начинать, let’s start!

    Многопоточное программирование в Java 8. Часть первая. Параллельное выполнение кода с помощью потоков

    Многопоточное программирование в Java 8. Часть первая. Параллельное выполнение кода с помощью потоков

      Переводы , 8 июля 2015 в 16:58

    Добро пожаловать в первую часть руководства по параллельному программированию в Java 8. В этой части мы на простых примерах рассмотрим, как выполнять код параллельно с помощью потоков, задач и сервисов исполнителей.

    Впервые Concurrency API был представлен вместе с выходом Java 5 и с тех пор постоянно развивался с каждой новой версией Java. Большую часть примеров можно реализовать на более старых версиях, однако в этой статье я собираюсь использовать лямбда-выражения. Если вы все еще не знакомы с нововведениями Java 8, рекомендую посмотреть мое руководство.

    Потоки и задачи

    Все современные операционные системы поддерживают параллельное выполнение кода с помощью процессов и потоков. Процесс — это экземпляр программы, который запускается независимо от остальных. Например, когда вы запускаете программу на Java, ОС создает новый процесс, который работает параллельно другим. Внутри процессов мы можем использовать потоки, тем самым выжав из процессора максимум возможностей.

    Потоки (threads) в Java поддерживаются начиная с JDK 1.0. Прежде чем запустить поток, ему надо предоставить участок кода, который обычно называется «задачей» (task). Это делается через реализацию интерфейса Runnable , у которого есть только один метод без аргументов, возвращающий void — run() . Вот пример того, как это работает:

    Поскольку интерфейс Runnable функциональный, мы можем использовать лямбда-выражения, которые появились в Java 8. В примере мы создаем задачу, которая выводит имя текущего потока на консоль, и запускаем ее сначала в главном потоке, а затем — в отдельном.

    Результат выполнения этого кода может выглядеть так:

    Из-за параллельного выполнения мы не можем сказать, будет наш поток запущен до или после вывода «Done!» на экран. Эта особенность делает параллельное программирование сложной задачей в больших приложениях.

    Потоки могут быть приостановлены на некоторое время. Это весьма полезно, если мы хотим сэмулировать долго выполняющуюся задачу. Например, так:

    Когда вы запустите этот код, вы увидите секундную задержку между выводом первой и второй строки на экран. TimeUnit — полезный класс для работы с единицами времени, но то же самое можно сделать с помощью Thread.sleep(1000) .

    Работать с потоками напрямую неудобно и чревато ошибками. Поэтому в 2004 году в Java 5 добавили Concurrency API. Он находится в пакете java.util.concurrent и содержит большое количество полезных классов и методов для многопоточного программирования. С тех пор Concurrency API непрерывно развивался и развивается.

    Давайте теперь подробнее рассмотрим одну из самых важных частей Concurrency API — сервис исполнителей (executor services).

    Исполнители

    Concurrency API вводит понятие сервиса-исполнителя (ExecutorService) — высокоуровневую замену работе с потоками напрямую. Исполнители выполняют задачи асинхронно и обычно используют пул потоков, так что нам не надо создавать их вручную. Все потоки из пула будут использованы повторно после выполнения задачи, а значит, мы можем создать в приложении столько задач, сколько хотим, используя один исполнитель.

    Вот как будет выглядеть наш первый пример с использованием исполнителя:

    Класс Executors предоставляет удобные методы-фабрики для создания различных сервисов исполнителей. В данном случае мы использовали исполнитель с одним потоком.

    Результат выглядит так же, как в прошлый раз. Но у этого кода есть важное отличие — он никогда не остановится. Работу исполнителей надо завершать явно. Для этого в интерфейсе ExecutorService есть два метода: shutdown() , который ждет завершения запущенных задач, и shutdownNow() , который останавливает исполнитель немедленно.

    Вот как я предпочитаю останавливать исполнителей:

    Исполнитель пытается завершить работу, ожидая завершения запущенных задач в течение определенного времени (5 секунд). По истечении этого времени он останавливается, прерывая все незавершенные задачи.

    Callable и Future

    Кроме Runnable , исполнители могут принимать другой вид задач, который называется Callable . Callable — это также функциональный интерфейс, но, в отличие от Runnable , он может возвращать значение.

    Давайте напишем задачу, которая возвращает целое число после секундной паузы:

    Callable-задачи также могут быть переданы исполнителям. Но как тогда получить результат, который они возвращают? Поскольку метод submit() не ждет завершения задачи, исполнитель не может вернуть результат задачи напрямую. Вместо этого исполнитель возвращает специальный объект Future, у которого мы сможем запросить результат задачи.

    После отправки задачи исполнителю мы сначала проверяем, завершено ли ее выполнение, с помощью метода isDone() . Поскольку задача имеет задержку в одну секунду, прежде чем вернуть число, я более чем уверен, что она еще не завершена.

    Вызов метода get() блокирует поток и ждет завершения задачи, а затем возвращает результат ее выполнения. Теперь future.isDone() вернет true , и мы увидим на консоли следующее:

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

    Вы, возможно, заметили, что на этот раз мы создаем сервис немного по-другому: с помощью метода newFixedThreadPool(1) , который вернет исполнителя с пулом в один поток. Это эквивалентно вызову метода newSingleThreadExecutor() , однако мы можем изменить количество потоков в пуле.

    Таймауты

    Любой вызов метода future.get() блокирует поток до тех пор, пока задача не будет завершена. В наихудшем случае выполнение задачи не завершится никогда, блокируя ваше приложение. Избежать этого можно, передав таймаут:

    Выполнение этого кода вызовет TimeoutException :

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

    InvokeAll

    Исполнители могут принимать список задач на выполнение с помощью метода invokeAll() , который принимает коллекцию callable-задач и возвращает список из Future .

    В этом примере мы использовали функциональные потоки Java 8 для обработки задач, возвращенных методом invokeAll . Мы прошлись по всем задачам и вывели их результат на консоль. Если вы не знакомы с потоками (streams) Java 8, смотрите мое руководство.

    InvokeAny

    Другой способ отдать на выполнение несколько задач — метод invokeAny() . Он работает немного по-другому: вместо возврата Future он блокирует поток до того, как завершится хоть одна задача, и возвращает ее результат.

    Чтобы показать, как работает этот метод, создадим метод, эмулирующий поведение различных задач. Он будет возвращать Callable , который вернет указанную строку после необходимой задержки:

    Используем этот метод, чтобы создать несколько задач с разными строками и задержками от одной до трех секунд. Отправка этих задач исполнителю через метод invokeAny() вернет результат задачи с наименьшей задержкой. В данном случае это «task2»:

    В примере выше использован еще один вид исполнителей, который создается с помощью метода newWorkStealingPool() . Этот метод появился в Java 8 и ведет себя не так, как другие: вместо использования фиксированного количества потоков он создает ForkJoinPool с определенным параллелизмом (parallelism size), по умолчанию равным количеству ядер машины.

    ForkJoinPool впервые появился в Java 7, и мы рассмотрим его подробнее в следующих частях нашего руководства. А теперь давайте посмотрим на исполнители с планировщиком (scheduled executors).

    Исполнители с планировщиком

    Мы уже знаем, как отдать задачу исполнителю и получить ее результат. Для того, чтобы периодически запускать задачу, мы можем использовать пул потоков с планировщиком.

    ScheduledExecutorService способен запускать задачи один или несколько раз с заданным интервалом.

    Этот пример показывает, как заставить исполнитель выполнить задачу через три секунды:

    Когда мы передаем задачу планировщику, он возвращает особый тип Future — ScheduledFuture , который предоставляет метод getDelay() для получения оставшегося до запуска времени.

    У исполнителя с планировщиком есть два метода для установки задач: scheduleAtFixedRate() и scheduleWithFixedDelay() . Первый устанавливает задачи с определенным интервалом, например, в одну секунду:

    Кроме того, он принимает начальную задержку, которая определяет время до первого запуска.

    Обратите внимание, что метод scheduleAtFixedRate() не берет в расчет время выполнения задачи. Так, если вы поставите задачу, которая выполняется две секунды, с интервалом в одну, пул потоков рано или поздно переполнится.

    В этом случае необходимо использовать метод scheduleWithFixedDelay() . Он работает примерно так же, как и предыдущий, но указанный интервал будет отсчитываться от времени завершения предыдущей задачи.

    В этом примере мы ставим задачу с задержкой в одну секунду между окончанием выполнения задачи и началом следующей. Начальной задержки нет, и каждая задача выполняется две секунды. Так, задачи будут запускаться на 0, 3, 6, 9 и т. д. секунде. Как видите, метод scheduleWithFixedDelay() весьма полезен, если мы не можем заранее сказать, сколько будет выполняться задача.

    Это была первая часть серии статей про многопоточное программирование. Настоятельно рекомендую разобрать вышеприведенные примеры самостоятельно. Все они доступны на GitHub. Можете смело форкать репозиторий и добавлять его в избранное.

    Надеюсь, вам понравилась статья. Если у вас возникли какие-либо вопросы, вы можете задать их в твиттере.

    Ссылка на основную публикацию
    Статьи c упоминанием слов:
    Adblock
    detector