Основы программирования с Java Машнин Тимур
Программа компиляции является своего рода системным программным обеспечением, потому что она взаимодействует с другими программами.
Программа компиляции берет программу в качестве входных данных, а затем переводит ее в понятный машиной язык или объектный код.
Этот процесс называют компиляцией.
После компиляции программы, она должна пройти через другой процесс, который называется связыванием или сборкой и который связывает программу с другими программами или библиотеками, которые были включены в оригинальную программу.
В случае Java, есть очень богатая коллекция существующих программ, упакованных в виде библиотек, например, библиотека для часто используемых математических функций, таких как корень квадратный и тригонометрические функции – синус, косинус и тангенс.
Это очень важно при разработке программ, потому что мы можем использовать то, что было написано раньше и не должны разрабатывать все с нуля.
Повторное использование программы является общим действием программной инженерии, которое может сэкономить время и усилия за счет сокращения лишней работы.
Процесс связывания создает компьютерный исполняемый код, который обычно хранится в .exe файле или .jar файле.
Чтобы действительно выполнить программу, исполняемый код должен быть перемещен оттуда, где он хранится, например, на жестком диске, в основную память, где может быть осуществлено выполнение программы, и этот процесс называется загрузка.
Программу необходимо протестировать для разных вводов, прежде чем она может быть опубликована.
Если обнаружена ошибка, программу нужно пересмотреть и провести через последовательность шагов разработки снова.
В настоящее время, все эти процессы могут осуществляться в интегрированной среде разработки (IDE).
Интегрированная среда разработки (IDE) является программным приложением, которое обеспечивает интерактивные инструменты для программистов, чтобы упростить цикл разработки программного обеспечения и таким образом, улучшить производительность.
Далее приведем общие компоненты IDE.
Они в основном соответствуют шагам в цикле разработки программного обеспечения, о которых мы только что говорили.
Редактор в IDE часто предоставляет инструменты, которые помогут вам отформатировать и документировать программы.
Некоторые могут даже помочь вам сделать некоторую первоначальную проверку на синтаксис.
Компилятор, сборщик и загрузчик обеспечивают компиляцию, связывание и загрузку программы для исполнения, как обсуждалось ранее.
Часто существуют ошибки в программах, даже для программ, написанных опытными программистами.
Отладчик может помочь в выявлении и локализации ошибок.
Он позволяет программисту проследить шаг за шагом выполнение программы.
В отладке программы, есть два распространенных типа ошибок, а именно синтаксические ошибки и семантические ошибки.
Синтаксис языка программирования представляет собой набор правил, которые определяют комбинацию символов, которые могут быть правильно использованы вместе в языке.
Это похоже на грамматику в естественном языке, таком как русский или английский язык.
Семантика относится к значению программы, то есть, что программа должна выполнить.
Программа может быть синтаксически правильной, но она может не давать предполагаемое значение.
В естественных языках, таких как русский или английский, может присутствовать двусмысленность, человек делает толкование и может попросить разъяснений, если значение не ясно.
Например, если вы бы дали следующее указание, подумайте о том, какое может быть значение этой инструкции.
Например, инструкция может быть "казнить нельзя помиловать".
Таким образом, это предложение являются синтаксически или грамматически правильным, но семантически неоднозначным.
Для компьютера, он всегда даст каждой программе ровно одну интерпретацию.
Мы будем использовать в основном IntelliJ IDEA как нашу интегрированную среду разработки или IDE здесь, и вы будете иметь лучшее представление о каждом из этих компонентов.
Как решать задачи?
Прежде чем мы рассмотрим, как компьютеры могут быть использованы для решения задач, давайте вначале рассмотрим, как мы обычно решаем задачи в реальной жизни.
Процесс решения задачи, которому мы обычно следуем, не ограничивается использованием только компьютера.
1-й шаг должен определить и проанализировать задачу, которую вы пытаетесь решить, чтобы мы могли получить хорошее понимание задачи.
На этом этапе, в основном, вы пытаетесь придумать спецификацию задачи. Это особенно важно, когда вы решаете задачу с помощью компьютера.
Компьютер не может читать ваши мысли, вы должны дать компьютеру точные инструкции о шагах выполнения.
Так что этот шаг очень важен, потому что вы должны сначала дать себе четкое понимание задачи, прежде чем вы можете сказать компьютеру, что вы от него хотите.
После того как вы получили спецификацию задачи, следующим шагом будет разработать решение.
Во многих задачах может быть несколько решений.
Итак, вы хотите разработать решение, которое наилучшим образом соответствует текущей ситуации или ограничениям.
Например, при попытке решить задачу добраться из одного места в другое, ограничения могут быть в том, что вы должны попасть в определенное время и с определенным бюджетом.
После того как вы определились с решением, вы должны разработать детали реализации, в том числе шаг за шагом реализацию решения.
После того как вы закончили разработку реализации решения, вы должны выполнить некоторые тесты и оценки, чтобы убедиться, что ваша реализация правильно решает проблему.
Это очень важно, потому что ваше решение может оказаться не в состоянии обработать все проблемные случаи.
Этот шаг часто является повторяющимся процессом, и возможно, придется пересмотреть решение или улучшить его, чтобы удовлетворить всем ограничениям и условиям.
И последнее, но не менее важное, вы должны задокументировать решение так, что, если вы или другие люди захотят вновь обратиться к проблеме в более позднее время, вы все равно сможете легко понять это решение.
Документация также помогает поддерживать решение в случае, если оно нуждается в пересмотре или обновлении для возможных будущих изменений.
Используем пример поиска способа путешествовать из Москвы в Лондон.
Предположим, что вы турагент, и определение задачи может быть что-то вроде "Найти лучший способ для вашего клиента, чтобы проехать из центра Москвы в Лондон в Великобритании".
Анализируя эту задачу, вам придется узнать у клиента, что он или она имеет в виду под самым лучшим способом, это кратчайшее расстояние или лучшее время или дешевая стоимость.
Эскизный проект может начаться с рассмотрения всех возможных маршрутов и видов транспорта, возможно, с помощью Google Maps или других сайтов туристических услуг.
И чтобы уточнить решение, нужно оценить различные маршруты и виды транспорта, а затем выбрать маршрут, который наилучшим образом соответствует вашей цели, например, самый короткий маршрут или самый дешевый по стоимости.
Как только вы создали решение, тестирование может быть трудным для этой конкретной задачи, если вы не можете фактически проделать это путешествие.
Если вы не можете выполнить эту поездку, тогда вы можете оценить решение, проверив записи определенных рейсов, чтобы убедиться, что есть достаточно времени для соединения рейсов, если это необходимо.
Или опросить кого-нибудь с предыдущим опытом создания подобной поездки.
Затем вам нужно будет задокументировать свое решение, предоставляя простые инструкции вашему клиенту, чтобы он не упустил соединение рейсов или чтобы было достаточно местной валюты для использования общественного транспорта.
После того как ваш клиент завершил поездку, вы сможете получить обратную связь от него, чтобы можно было вести учет того, был ли положительным опыт или пересмотреть решение, если ваш клиент не был доволен.
И это эквивалентные шаги при попытке запрограммировать компьютер как процесс решения задач.
При определении задачи для компьютера, мы должны придумать очень точные спецификации задачи.
И одним из распространенных подходов, является придумать спецификацию для начального состояния или входную спецификацию и итоговую спецификацию для конечного состояния или выходную спецификацию для задачи.
Это полезно, потому что путь пользователя для взаимодействия с компьютером часто лежит через устройства ввода/вывода.
Вам также необходимо определить, какая дополнительная информация нужна для решения задачи.
Используя предыдущую задачу в качестве примера, вам, возможно, придется узнать, во сколько вы должны прибыть в пункт назначения и сколько денег вы готовы потратить.
Когда мы разрабатываем решения для реальных жизненных задач, мы часто записываем шаги на определенном языке, таком как русский или английский.
При решении задач с помощью компьютера, мы также хотим перечислить шаги на языке, который могут легко понять все те, кто участвует в решении проблемы, это особенно важно, если вы работаете в команде. Такую последовательность шагов часто называют алгоритмом.
В общем, алгоритм представляет собой последовательность точных шагов на английском или другом человеческом языке для выполнения определенных функций.
Очень часто, алгоритм разрабатывается на разных уровнях детализации с помощью интерактивного процесса. Такой подход часто называют пошаговым уточнением.
Выше были приведены подготовительные шаги перед тем, как вы на самом деле реализуете программу или начнете программировать решение задачи.
Можно подумать, что реализация программы является наиболее трудным шагом, но, если вы проделали хорошую работу в процессе подготовки, шаг кодирования будет сделан просто, и перевод с очень хорошо продуманного алгоритма может быть самой легкой частью среди всех этих шагов.
Поэтому, когда вы решаете компактную проблему, мы советуем вам удержаться от соблазна начать кодирование, прежде чем вы получите отчетливое понимание решения задачи.
Еще одно решение, которое нужно сделать в процессе реализации, это нужно определить, какой язык программирования использовать и какое представление будет использоваться для различных аспектов задачи.
После окончания кодирования программы, она должна быть скомпилирована в исполняемый код компьютера, и она должна быть протестирована, используя различные сценарии, чтобы проверить все ли в порядке при различных условиях.
Если возникают ошибки, или если программа не работает, как задумано, нужно отследить ошибки. Этот шаг часто называют шагом отладки.
Для исторической справки. Термин отладки (debugging) используется, потому что первая известная компьютерная ошибка была найдена в 1947 году, когда мотылек (насекомое – bug) был пойман в ловушку в реле компьютера.
Насекомое было записано на пленку в журнале учета Грейс Хоппер и в настоящее время хранится в Смитсоновском музее.
Для сложных проблем, важно протестировать программу в рамках различных сценариев, так как программа, которая работала в одном случае, не означает, что она будет работать для всех случаев.
И полезно придумать план тестирования, чтобы охватить набор общих случаев, которые можно было бы ожидать при работе программы.
Тесты могут привести к двум распространенным типам ошибок, а именно синтаксической ошибки или семантической ошибки.
Также важно документировать и поддерживать программу, особенно для программ, жизнь которых, как ожидается, продлится в течение длительного времени, и для повторного использования, и программ, которые могут быть пересмотрены или изменены другими пользователями.
Игра
Прежде чем погрузиться в программирование, давайте более внимательно посмотрим на важность постановки задачи и представление процесса путем изучения обычно используемого подхода к решению задачи под названием представление пространства состояний.
В представлении пространства состояний, задача представляется в виде множества состояний.
И я буду использовать примеры для иллюстрации того, что я имею в виду под состояниями.
Пространство состояний, это множество всех возможных состояний, в которых задача может находиться.
В частности, есть множество начальных состояний, то есть там, где начинается задача, и набор конечных состояний, в том числе всех возможных решений задачи.
Два состояния связаны, если существует действительная операция, которая может превратить одно состояние в другое.
Давайте рассмотрим несколько примеров, чтобы получить более полное понимание представления пространства состояний.
Это простой пример, и задача заключается в том, чтобы включить смартфон.
Здесь есть два состояния "сон" и "работа" и они соединены операцией нажатия на кнопку питания.
Первоначально, смартфон находится в «спящем» состоянии.
Для перехода к состоянию "работать", пользователь нажимает на кнопку питания.
И смартфон переключается из состояния "сна" в состояние "работать".
Пользователь может переключиться на «спящее» состояние смартфона снова, нажав на кнопку питания.
В этом примере, вероятно, нельзя сказать много о полезности представления пространства состояний.
Давайте теперь рассмотрим более интересный пример – игру крестики-нолики.
В этой игре, два игрока ставят "крестик" или "кружок" в таблице 3x3.
И тот, кто получает 3 крестика или нолика в ряд первым либо горизонтально, либо вертикально, либо по диагонали будет победителем.
Здесь показывается, как два компьютера играют в крестики-нолики друг с другом.
Поскольку компьютеры не делают ошибок, мы можем написать программу, чтобы гарантировать, что они не проиграют в этой игре.
Это своего рода задача, изучаемая в области искусственного интеллекта.
На этой диаграмме видно, что игра начинается с пустой сетки 3x3, мы назовем это начальным состоянием.
Пусть игрок, который ставит крестик, начнет первым.
Есть 9 возможных мест, где 1-й игрок может разместить крестик, но из-за симметрии, график показывает только три варианта, в том числе средний из которых является уникальным, а два других представляет 4 случая.
2-й шаг мог бы быть сделан игроком, который ставит кружок.
Здесь все возможные ходы для 2-го игрока после удаления симметричных случаев.
Если мы будем продолжать, чтобы пройти все возможные ходы, в результате график даст нам пространство состояний.
Угадайте, сколько возможных состояний есть? Если вы достаточно терпеливы, чтобы проследить все возможности, вы увидите, что есть более чем 250000 возможных последовательностей. Вместо того чтобы идти через все случаи, давайте дальше расширять только один конкретный случай.
Здесь все возможные размещения 2-го крестика после этого конкретного выбранного состояния, и все возможные места размещения 2-го кружка.
3-я шаг со стороны игрока с крестиком приведет к первому возможному состоянию выигрыша.
Кроме того, 3-й шаг для кружка приведет ко второму возможному состоянию выигрыша.
Также есть состояние ничьей.
Эти результаты состояния победы вместе с состоянием ничьей образуют множество конечных состояний.
Есть много больше конечных состояний, которые не показаны здесь.
И после прочтения этой книги, вы должны уметь писать программы для такого рода игр или даже более сложных задач.
Пример задачи
Давайте рассмотрим другой пример, чтобы проиллюстрировать, как выбор соответствующего представления может упростить поиск решений более сложной задачи.
Как и в игре крестики-нолики, задача здесь начинается с матрицы 3х3, но в этой задаче, клетки занимают квадратные яблоки.
Давайте назовем это задачей квадратных яблок.
Люди на самом деле могут вырастить квадратные яблоки или даже квадратные арбузы.
Предположим, что в исходном состоянии этой задачи существует червь в средней ячейке.
Вопрос в том, может ли червь съесть все яблоки, выполнив следующие два правила.
Во-первых, после того, как червь закончил целое яблоко в текущей ячейке, он может двигаться только в другую ячейку, которую разделяет общая сторона, так что эти стрелки показывают 4 возможных хода и 2-е правило состоит в том, что вы не можете переместиться в ту ячейку, которую посещали прежде.
То есть, червь может двигаться только в ячейку, где есть еще несъеденное яблоко внутри.
Рисунок показывает, что червь начинает с середины. После того, как заканчивается среднее яблоко, он может двигаться в одну из четырех клеток на стороне, но не в углу. Таким образом, червь может двигаться вправо, двигаться вниз, двигаться влево и двигаться вверх.
Я хочу, чтобы вы подумали, есть ли решение этой задачи.
То есть, может ли червь съесть все 9 яблок.
Это должно быть совершенно очевидно.
Здесь часть пространства состояний графа и это возможный путь, который может привести к решению.
На самом деле, вы обнаружите, что есть 7 других пути для решения, пробуя другие ходы.
Можно написать программу Java, которая была бы создана для решения этой задачи.
И после прочтения этой книги, вы должны быть в состоянии написать собственную программу для решения таких задач, как эта.
Это демо-программа, которая была написана для вас, чтобы проиллюстрировать решение задачи квадратного яблока.
Задача будет начинаться с червем в середине. Червь настигает яблоко, перемещаясь в другую ячейку.
Отображая условие – не посещать клетки, которые были захвачены ранее, цифры показывают последовательность шагов.
Программа также отображает последовательность шагов в другом окне.
Таким образом, вы можете видеть, что есть в общей сложности 8 решений, как обсуждалось ранее.
Давайте теперь посмотрим на 3D-версию задачи. Задача в основном такая же, как и раньше, за исключением того, что у вас есть 3x3x3 куб как кубик Рубика и с квадратным яблоком в каждой ячейке.
То есть, есть в общей сложности, есть 27 яблок. Чтобы помочь вам визуализировать проблему, диаграмма здесь отображает куб в три слоя.
Подобно тому, что у нас было раньше, червь прячется в середине, и мы должны следовать тем же правилам.
То есть, в начале, есть 6 возможных ходов, вместо 4, как в случае 2D, потому что в дополнение к 4 ячейкам на сторонах в среднем слое, червь также может перейти к средней ячейке на переднем плане и средней ячейке на заднем плане.
И теперь вопрос в том, может ли червь по-прежнему съесть все 27 яблок.
Помните, что червь не может вернуться к любым тем ячейкам, которые были захвачены ранее.
Давайте теперь вернемся и посмотрим на 2D-задачу немного по-другому. Некоторые из красных яблок заменены на зеленые яблоки, и они расположены по такой схеме.
Если червь опять должен начать с середины, следуя тем же правилам, это та же задача, как и раньше, независимо от цвета яблок, и у нас есть те же 8 решений, как и в предыдущем случае 2D.
Теперь рассмотрим, что, если вместо того, чтобы начать с середины, червь начинает с одной из ячеек на стороне, а все другие правила те же самые.
Подсказка в том, что надо посмотреть, как меняется цвет, когда червь переходит из одного яблока в другое.
Давайте теперь вернемся к задаче квадратных яблок 3D и будем чередовать цвета яблок, как мы сделали это в 2D случае.
Как и в предыдущем 3D случае червь прячется в середине.
Так что это все та же 3D задача, как и раньше, хотя цвета некоторых из яблок были изменены.
Теперь используйте то, что вы наблюдали в случае 2D, и попытайтесь придумать быстрое решение этой задачи.
Вопросы
Задача
Может ли червь съесть все 27 яблок, если он начинает от центра куба?
1. Да
2. Нет
Ответ: 2.
Задача
Может ли червь съесть все 27 яблок, если он начинается с одного из углов куба?
1. Да
2. Нет
Ответ: 1.
Из задачи 2D квадратных яблок, мы можем наблюдать, что червь сможет съесть все яблоки, если он начинает с ячейки с красным яблоком. Применяя то же правило в задаче квадратных яблок 3D, мы можем быстро сказать, что червь не сможет съесть все яблоки, если он начинает из центра куба, в котором содержится зеленое яблоко. Аналогичным образом можно быстро сказать, что червь может съесть все яблоки, если он начинает с угла куба, который содержит красное яблоко.
Важность представления задачи
В задаче 2D квадратных яблок, используя красное и зеленое представления яблок, вы увидите, что есть 5 красных яблок и 4 зеленых яблока.
Каждое движение будет чередовать яблоки разных цветов.
Если начинать с зеленого яблока, тогда не будет больше зеленого яблока после употребления четвертого красного яблока.
В 3D случае, существует 14 красных яблок и 13 зеленых яблок.
Используя те же рассуждения, что и в случае 2D, если начинать с зеленого яблока, тогда не будет больше зеленого яблока после окончания 13-го красного яблока.
Так что решения этой задачи не будет, если червь начинает со средней ячейки, которая содержит зеленое яблоко.
И нам удается сразу найти решение, без необходимости искать все возможные пути, представляя задачу.
На самом деле, тот же аргумент может быть использован для более широкой задачи, скажем 5x5x5, 7x7x7, или даже больше.
Этот пример показывает важность нахождения правильного представления до решения задачи. Это может сэкономить много времени и усилий.
Первая Java программа
Теперь мы можем начать писать нашу первую Java программу.
По традиции изучения нового языка программирования, ваша первая программа на Java будет печатать приветствие "Hello, World!".
Первая строка здесь содержит комментарии о том, что, как предполагается, программа должна делать.
И мы обсудим документирование программы позже.
Классы являются основными единицами в программах Java. Все программы Java это классы.
Здесь первая строка кода объявляет имя этой программы, как HelloWorld.
Объявление здесь выглядит немного сложно, но вы не должны беспокоиться о том, что здесь сейчас означают различные слова.
Вы можете смотреть на это как на какой-то формат или шаблон, которому вы должны следовать.
Аналогия, когда вы пишете письмо, у вас есть определенный формат, которому вы должны следовать, такой как адреса отправителя и получателя, а также письмо, как правило, начинается со слова "Уважаемый", а затем следует имя из адреса.
Вы просто должны обратить внимание на слово " main ", которое указывает на главную точку входа в программу.
Строка кода внутри фигурных скобок main является важной частью программы, которая явно указывает компьютеру, чтобы распечатать сообщение-приветствие "привет мир".
Перейдем теперь к среде разработке, чтобы посмотреть на программу более детально.
Скачайте и установите среду разработки IntelliJ IDEA версии Community.
И скачайте проект приложения, который доступен в ресурсах к этой книги (https://github.com/novts/java-base).
Распакуйте этот проект и откройте его в среде разработки.
Вот этот файл, соответствующий классу приложения.
Вы можете дважды щелкните по нему, чтобы открыть программу.
И вы можете скомпилировать программу, нажав на кнопку "Build Project".
И вы можете увидеть, что программа составлена правильно, так как в сообщении будет указано, что здесь нет ошибок синтаксиса.
Теперь ваша программа готова к работе. Вы можете запустить программу, выбрав Run.
И в другом экране появится сообщение: «Привет, мир!".
Поздравляем! Вы успешно написали свою первую программу Java.
Язык Java был разработан с самого начала с учетом интернационализации, вместо поддержки только английского языка, и как и в большинстве других языков программирования, Java поддерживает 16-битный стандарт Unicode, который включает в себя много других языков, кроме английского.
Попробуем заменить сообщение в двойных кавычках на аналогичное сообщение на другом языке.