Подпишитесь на рассылку
Компьютерной школы Hillel

Вы получите:

  1. Информацию о полезных отраслевых мероприятиях
  2. Интересные статьи IT-сферы
  3. Новости Компьютерной школы Hillel
Спасибо!
Нет, спасибо
На нашу рассылку уже подписалось 2241 человека.

Выбор первого языка программирования — обзор Java

Автор: Максим Фарсиков

27 голосов
13149

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

Попытаемся разобраться почему Java выбирается в современных проектах в качестве основного языка программирования.

Си-подобный синтаксис*

В то время, когда создавался язык Java, самым популярным языком программирования был C++. Для того, чтобы «переманить» программистов на новый Java было принято решение сделать его максимально похожим на С++, взяв по возможности лучшее от него.

Java и С++ не единственные, кто обладает подобным синтаксисом. Прародителем C++ был язык C (Си), потому все языки использующие подобный синтаксис называются си-подобными, и их существует великое множество (Wikipedia: C-family).

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

Плюсы:

  • популярен

Минусы:

  • требует привыкания

* Синтаксис — это набор правил, которым должен соответствовать текст программы. По-простому: то, как выглядит программа. Более сложно - на вики.

Язык общего назначения

По своему назначению языки программирования бывают:

  • специальные (решающие задачи в определённой отрасли. Например в математике Fortran, в базах данных SQL);
  • общего назначения (решающие широкий спектр задач в любых отраслях. Например С++, Java, C#).

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

Плюсы:

  • универсален, решает любые задачи

Минусы:

  • в отдельных отраслях уступает (по скорости работы и удобству использования) специализированным языкам

Объектно-ориентированный

Все компьютерные программы пытаются описать процессы нашего мира в командах процессора. Поскольку компьютер ничего не знает об объектах нашего мира, программисту всегда приходилось «переводить» всё на язык цифр и инструкций. Так было до 70-х годов, пока не появилась объектно ориентированная парадигма программирования. С её помощью оказалось возможным программирование на уровне объектов из нашего мира, а не на уровне цифр из мира компьютерного.

Например, вот так выглядит описание двух столов в не-объектном виде:

  • длина первого стола: 1200мм
  • ширина первого стола: 500мм
  • высота первого стола: 1000мм
  • длина второго стола: 1300мм
  • ширина второго стола: 600мм
  • высота второго стола: 1100мм

Между параметрами нет никакой связи, кроме их названий. Можно легко допустить ошибку, в попытке посчитать площадь стола: умножить длину ПЕРВОГО стола на ширину ВТОРОГО.

Пример объектно-ориентированного описания:

Первый стол:

  • длина: 1200мм
  • ширина: 500мм
  • высота: 1000мм

Второй стол:

  • длина: 1300мм
  • ширина: 600мм
  • высота: 1100мм

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

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

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

Плюсы:

  • ООП используется во многих других языках программирования
  • широко использует абстракции
  • легко моделировать объекты реального мира

Минусы:

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

Функциональный

Когда необходимо уменьшить время выполнения программы есть два очевидных пути:

  1. Оптимизировать программу;
  2. Увеличить частоту процессора.

С оптимизацией имеем следующие проблемы:

  • оптимизировать приходится ВСЕ программы;
  • существует логический лимит, дальше которого оптимизировать невозможно.

Ускорение процессора решает эти проблему, и ускоряет выполнение сразу всех программ.

Благодаря закону Мура мир развивался вторым путём — ускорял процессоры. Закон гласил, что каждые два года частота процессоров обязана удваиваться. Но однажды закон Мура перестал работать и частота перестала расти. И мы перестали получать необходимое нам ускорение программ. Во всём сразу обвинили Мура, сказали что он всё не так понял, и в закон внесли поправку: не частота удваивается, а количество транзисторов!

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

Но сделать это не так-то просто: все куски программ зависят друг от друга, зависят от общих данных (особенно если речь идёт об объектно-ориентированном программировании).

И тут на помощь приходит функциональное программирование, которое сводит к минимуму (а в идеале полностью исключает) использование общих данных, что позволяет легко и просто выполнять программу на разных ядрах.

Объектно-ориентированной парадигме потребовалось 20 лет, чтобы пройти путь от теории к массовому использованию. Зная как стремительно сейчас изменяется наш мир, можно подумать что это исключение из правил, и мы принимаем всё новое гораздо быстрее и охотней.

Однако функциональной парадигме программирования потребовалось гораздо больше времени чем объектно-ориентированной. Впервые эта парадигма была представлена в 30-е годы, однако в широкие массы функциональное программирование начинает входить только в наши дни.

Существуют полностью функциональные языки (Haskel, Erlang) и гибридные — сочетающие в себе объектно-ориентированный и функциональный подходы (Scala, C++).

Начиная с 8 версии Java приобретает механизмы функционального программирования (такие как ссылки на функции и лямбда-выражения), что позволяет легко создавать программы, которые могут выполняться на нескольких ядрах одновременно.

Плюсы:

  • доступны новые приёмы программирования
  • легко создаются программы, способные использовать одновременно несколько ядер процессора

Минусы:

  • требует дополнительного изучения и развития функционального (математического) мышления

Типизация: строгая, статическая, явная

Строгая типизация

Судя из названия, если типизация строгая — то существуют какие-то правила, нарушать которые нельзя.

Если типизация НЕ строгая (например как в JavaScript), это не значит что правил нет. Правила есть, при чём есть ещё дополнительные правила, которые вступают в силу, когда нарушаются основные.

Пример (необходимо понимать что строки и числа — это разные типы данных):

Сложение двух чисел и двух строк, не зависимо от модели типизации, везде происходит одинаково:

5 + 5 = 10

«5» + «5» = «55»

Разница будет когда мы (возможно по ошибке) попытаемся сложить число и строку:

5 + «5» = ? (10 или «55»)

Строго типизированный язык скажет что здесь затаилась ошибка и заставит нас явно привести всё к какому-то одному типу.

Не строго типизированный начнёт хитрить: он прибегнет к дополнительному набору правил на случай не соответствия типов. В зависимости от этих правил будет выбран один из вариантов:

  1. Строка «5» станет числом и результат будет 10 (сложение чисел)
  2. Число «5» станет строкой и результат будет «55» (конкатенация строк)

Получается, что при не строгой типизации, по ошибке мы можем попытаться выполнить операцию над несовместимыми типами данных и в зависимости от «дополнительных правил» получить разный результат: 10 или «55».

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

Плюсы:

  • нет дополнительных правил автоматического преобразования типов: их не нужно знать и нет ошибок не правильного преобразования
  • быстро приходит понимание типизации

Минусы:

  • все необходимые преобразования приходится выполнять явно

Статическая типизация

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

Таким образом Java избегает целый класс ошибок (ошибок несовместимости типов), т.к. они все обнаруживаются во время компиляции благодаря статической типизации.

Естественно, что в наши дни никто не пишет код в блокноте, и не компилирует из командной строки — всё это умеют делать современные инструменты разработки IDE (IDEA, Eclipse, NetBeans). И все указанные IDE активно пользуются тем, что типизация статическая, и проверяют ошибки ещё до того, как мы попытаемся код скомпилировать.

Ещё одним плюсом статической типизации является то, что IDE способна подсказывать какие методы и свойства есть у объекта. Это очень сильно упрощает и разработку, и обучение.

Плюсы:

  • об ошибках несовместимых типов мы узнаём во время компиляции (с использованием IDE во время написания кода), а не во время выполнения программы
  • зная тип данных IDE может подсказывать какие операции с ним можно выполнить (очень полезно, особенно на начальных этапах знакомства с языком)

Минусы:

  • необходимость определять типы самостоятельно

Явная типизация

Для того, чтобы объявить переменную в Java необходимо явно указать её тип. Например, переменная i целочисленного типа объявляется так:

int i = 5;

При этом на самом деле Java умеет вывести тип переменной i и без нашего int. Достаточно было бы написать:

var i = 5;

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

Плюсы:

  • нет

Минусы:

  • необходимость указывать типы явно (микро-проблема)

Кросс-платформенный

Для того, чтобы написанное вами приложение могло запускаться на разных платформах (Linux, Windows, Android), оно должно быть преобразовано (скомпилированно) совместимые с этой платформой в процессорные инструкции.

Java декларирует, что для её программ этого не требуется. За счёт чего это достигается?

Код, написанный на Java, компилируется не в инструкции процессора (как у большинства компилируемых языков), а в специальный байт-код. Этот байт-код запускается на Java-машине — специальной программе, которая умеет преобразовать байт-код в процессорные инструкции.

Таким образом от платформы зависит не код, а Java-машина. Установив соответствующую Java-машину на каждую платформу наш код будет одинаково работать на каждой из них.

Плюсы:

  • программы могут работать на разных системах

Минусы:

  • страдает производительность (незначительно)

Сборщик мусора

Память. Она не резиновая. В процессе работы программы создаются объекты, загромождая память. На плечи программиста ложится бремя следить за этими объектами, и когда они становятся не нужны — удалять их. Задача не из простых. Если что-то пошло не так — образуется утечка памяти, и приложение неизбежно (это вопрос времени) остановится с ошибкой об исчерпании всей доступной памяти.

Так вот Java решает эту проблему с помощью сборщика мусора. Вы просто не должны думать о ненужных объектах, думайте только о нужных! А о не нужных позаботится сборщик. Сам. Без напоминаний.

Попутно сборщик решает ещё одну проблему — фрагментацию памяти. Если в двух словах суть проблемы в следующем: есть кусок памяти на 10 ячеек, 5 из них заняты, и 5 свободны. Вы хотите записать целый объект на 5 ячеек в память — но не можете сделать этого. Т.к. свободные ячейки расположены не подряд, а три вначале, и две в конце.

Плюсы:

  • не нужно следить за объектами, и принимать решение об очистке памяти
  • нет проблемы фрагментации памяти

Минусы:

  • страдает производительность

Hello world

Обзор языка был бы не полным без классического примера самой простой программы:

public class MyFirstClass {

public static void main(String[] args) {

System.out.println("Hello world!");

}

}

Из-за многословности этого, казалось бы, элементарного действия считают что «порог входа» в Java слишком велик, и это отпугивает многих потенциальных пользователей этого языка. Действительно, hello world на Java окунает в ООП заставляя задуматься что такое класс? Почему он паблик? Зачем статик? Однако на самом деле достаточно относится первое время к этому, как к магии, и продолжать изучение этого замечательного языка.

И со временем Вам будут открыты все таинства заклинаний Java :)

10.03.2016 13149
Максим Фарсиков
Senior Developer,
Opower
Оцените этот материал
comments powered by HyperComments