Является ли Java лучшим языком программирования для начинающих? / Хабр
Привет, Хабр! Представляю вашему вниманию перевод статьи «Is Java The Best Programming language to Learn First?» автора Javin Paul.Часто получаю вопросы, вроде: «Какой язык программирования изучить первым?», «Java-тот самый язык программирования, на котором стоит начать писать?», «Насколько Java хорош в качестве первого языка программирования?», «Который из языков программирования самый подходящий для начинающих?» или «Начать с Java или Python?».
Ответом на все эти вопросы является то, что Java – один из самых популярных языков программирования, и есть много причин начать его изучать, начиная с карьерных возможностей и заканчивая получением поддержки со стороны сообщества.
По моему мнению, самая веская причина начала программирования на Java или выбора его в качестве первого языка – Java освоить проще.
Некоторые могут утверждать, что Python ещё проще Java и даже не требует компиляции, но лично я нахожу Java языком, понимать и читать на котором много легче (много лёгким для чтения и понимания).
Последнее поколение программистов начинало учиться писать код с Бейсика и только потом переходило на C и C++ с Java в качестве своего второго или третьего языка программирования.
Одной из причин для этого может быть то, что C и C++ были более востребованными в те дни в отличие от Java. Но действительная причина в том, что учебная программа была построена так, что нас обучали C и C++, поскольку тогда ещё не было Python, по крайней мере, в нашем колледже.
И правда, часто нам не приходится выбирать, и мы изучаем в школе или колледже программирование как часть учебной программы. В моё время C был первым языком программирования в нашем инженерном колледже, потом мы изучали C++, VB, VC++, и, наконец, Java.
Сейчас я говорю о том, что Java проще и легче освоить, но помню, как отметил, что он сложнее по синтаксису по сравнению с C++, поскольку мне приходилось прописывать System.
out.println() вместо короткой формы записи cout для того, чтобы вывести сообщение на экран, однако это просто кратковременное неудобство.Когда я начал писать и поддерживать большие программы, я нашёл код на Java более читабельным, и вы можете понять, что делает код. В Java отладка и поиск ошибок были много более удобные, чем в C++ или C.
Кстати говоря, я учусь профессиональному программированию или, как вы скажете, настоящему кодингу на моей первой работе. Именно тогда я и начал серьёзно изучать Java.
Java – язык программирования, с которого стоит начать?
Несколько причин, почему я считаю Java подходящим языком программирования, чтобы на нём учиться писать код:
- Java проще, синтаксис гораздо более читабельный, чем синтаксис C, C++ или другого языка.
- Язык Java хорош для изучения объектно-ориентированного программирования, но не для процедурного, где он уступает C. ООП или Объектно-Ориентированное Программирование
- Java имеет богатый API, и вы можете делать очень много в Java, например, работать с графикой, звуком и, что всего вероятнее, писать небольшие игры, такие как Крестики-Нолики, Тетрис и др. Не то, что вы не можете сделать это на других языках, но тогда вам придётся часто загружать и устанавливать различные программы и библиотеки, что для начинающего программиста работа непростая. Когда вы устанавливаете Java, большая часть всего необходимого для работы устанавливается уже в процессе установки языка.
- Java имеет сильную поддержку сообщества, неважно, какого рода вопросы, сомнения или проблемы у вас возникли, Google сможет найти ответы. Если не Google, то есть Stack Overflow, форумы Java и множество других сообществ, которые вам помогут. Это действительно самая главная причина, почему я советую начинающим учиться писать код на Java, поскольку, когда вы начнёте учиться программировать, вы столкнётесь с множеством различных проблем, прежде чем начать понимать основы программирования и сам Java. Поскольку Java-разработчиков насчитывается несколько миллионов и оказывается поддержка сообщества, всего вероятнее вы быстро отыщите ответы без каких-либо разочарований и недовольств.
- Java – строго типизированный язык, который исправляет множество ошибок, допущенных начинающими программистами. Также, в меньшей мере, подходит для статической типизации. Это ещё одна причина, по которой я предлагаю начинающим изучать сначала Java, а не Python, потому что Python – язык с динамической типизацией, и вам не нужно определять типы, что обычно запутывает.
- Java устанавливается со встроенным Garbage collection (автоматическое управление памятью, что занимают неиспользуемые объекты), что является большим плюсом для абсолютных новичков. Управление памятью – это большое дело в начале обучения программированию.
Это те несколько причин, почему я считаю, что начинающим следует сначала освоить Java и только потом любой другой язык программирования. Я могу быть предвзятым, потому что я Java-программист, но я также знаю Python и я также занимался профессиональным программированием на C и C++.
Исходя из этого опыта, я могу сказать, что Java, несомненно, является одним из лучших языков программирования для начинающих, и вы определённо можете выбрать Java в качестве первого языка программирования для изучения программирования.
Достаточно ли Java для успешной карьеры программиста?
Вопрос не в различии языков программирования, нет. Как программист, вы должны знать много вещей, таких как структура данных, алгоритмы, управление памятью, объектно-ориентированное программирование, скрипты и так далее. А другой язык учит вас другому.
Как только вам будет легко работать с Java, вы можете перейти на другие языки программирования, такие как Scala, JavaScript или выбрать скриптовые языки, например, Python, которые не нужно компилировать.
Самая большая проблема в этой сфере — нужно продолжать учиться и развиваться, чтобы построить успешную карьеру программиста. Если вы любите программирование и осваиваете новые технологии и языки программирования, то эта сфера для вас.
Для того, чтобы быть успешным программистом, также важно развивать навык отладки программ, который основан на умении логически мыслить.
Если вы дружите с логикой и можете сделать вывод, основанный на ограниченной доступной информации, тогда вам не составит труда устранять проблемы и находить ошибки в коде.
Хороший опыт работы с такими интегрированными средами разработки (IDE), как Eclipse, NetBeans или IntelliJ IDEA и действительно отличные инструменты Java также помогут вам в написании кода и его отладке.
На этом всё. На мой взгляд, Java, безусловно, является прекрасным языком, с которого стоит начать, потому что он проще большинства других языков и сосредоточен непосредственно на самом написании кода, а не на управлении системами, такими как управление памятью.
Вкратце, вы определённо можете выбрать Java в качестве своего первого языка программирования, и, когда вы его освоите, попробуйте выучить ещё парочку языков, например, JavaScript или Python.
If-else в Java. Курс «Программирование на Java»
В Java оператор ветвления if-else имеет Си-подобный синтаксис: условное выражение заключается в круглые скобки, тело ветки – в фигурные.
if (логич_выражение) { выражение1; выражение2; … } else { выражениеN; … }
Если тело состоит из одного выражения, фигурные скобки можно не использовать.
if (логич_выражение) выражение1; else выражение2;
В случае множественного ветвления обычно используют вложение последующих веток if во внешние для них else с поднятием этого if к строке else.
if (…) { … } else if (…) { … } else if (…) { … } else { … }
Простыми логическими операторами являются ==, !=, <, <=, >, >=.
Логические операторы И, ИЛИ, логическое НЕ записываются соответственно &&, ||, !. В Java эти операторы применимы только к булевому типу данных, то есть нельзя писать, например, !var
или a < 3 || var
, если var – целое или любой другой отличный от boolean тип. То же самое касается циклов: while (true) {}
будет работать, while (1) {}
– нет.
При сравнении примитивных типов сравниваются их значения. Так в следующем коде ветка if выполнится:
int a = 3; int b = 3; if (a == b) { System.out.println(1); }
В случае ссылочных типов сравниваются ссылки. Чтобы быть равными, они должны указывать на один и тот же объект.
package info.younglinux.java; public class Logic { public static void main(String[] args) { Message a = new Message("Hello"); Message b = new Message("Hello"); Message c = b; if (a == b) { System.out.println("a == b"); } if (b == c) { System.out.println("b == c"); } } } class Message { private String m = ""; Message(String str) { this.m = str; } String getMessage() { return this.m; } }
В приведенной программе на экран будет выведено только b == c, так как обе переменные указывают на один и тот же объект. В то время как a и b – разные объекты.
В Java есть сокращенный вариант условного оператора для случая, когда есть две ветки – if и else, каждая включает только одно выражение, а результат выражений обоих веток может быть присвоен переменной одного типа. Такой оператор называется тернарным (ternary – тройной).
import java.util.Scanner; public class Ternary { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int a = scan.nextInt(); int b = a > 10 ? a : a + 10; System.out.println(b); } }
В выражении a > 10 ? a : a + 10;
проверяется условие, стоящее до знака вопроса. Если оно истинно, то переменной b присваивается результат выражения, находящегося между знаками вопроса и двоеточия. Если условие ложно, то присваивается результат выражения, находящегося после двоеточия.
Компиляция и запуск приложения из командной строки — Java программирование
Синтаксис javac:
javac [ключи] [исходники]
Чтобы получить список возможных ключей, выполните:
javac –help
Чтобы скомпилировать программу MyFirstApp
, запустите компилятор, указав имя исходного файла в командной строке следующим образом:
javac MyFirstApp.java
Компилятор javac создаст файл MyFirstApp.class
, содержащий версию байт-кода.
В процессе компиляции исходного кода каждый отдельный класс помещается в собственный выходной файл, называемый по имени класса и получающий расширение .class
.
По умолчанию компилятор записывает сгенерированный .class
в тот же каталог, где находится исходный класс .java
. Это хорошо для маленьких проектов, но при работе на больших проектах файлы .java
и .class
должны храниться отдельно.
Ключ -d позволяет указать компилятору, куда записывать сгенерированные .class
файлы.
Например, у нас есть такая структура папок:
Следующая команда, выполненная из project1 папки сгенерирует файл MyFirstApp.class
и запишет его в папку classes (предполагаем, что MyFirstApp
не содержит оператора package
):
cd project1
javac -d classes src/MyFirstApp.java
Теперь давайте рассмотрим пример компиляции класса com. company.lesson1.MyFirstApp
, находящегося в пакете com.company.lesson1
. Имеется такая структура каталогов:
Следующая команда, выполненная из src каталога, сгенерирует файл MyFirstApp.class
, и запишет его в каталог classes/com/company/lesson1:
cd myProject/src
javac -d ../classes com/company/lesson1/MyFirstApp.java
Если каталог classes/com/company/lesson1 не существует, то он будет создан при компиляции.
Если же не существует каталог classes, то вы получите ошибку компиляции.
Чтобы выполнить программу из командной строки, следует воспользоваться загрузчиком приложений Jаvа, который называется java.
Синтаксис java:
java [ключи] класс [аргументы]
Для получения списка возможных ключей, выполните:
java –help
Чтобы выполнить программу, передадим имя класса MyFirstApp
(предполагаем, что MyFirstApp
не содержит оператора package
) в качестве аргумента командной строки:
java MyFirstApp
Если класс MyFirstApp
находится в пакете, то выполняем команду:
java com.company.lesson1.MyFirstApp
Стоит заметить, что при запуске программы указывается только один класс без расширения .class
.
- В процессе компиляции исходного кода каждый отдельный класс помещается в собственный выходной файл, называемый по имени класса и получающий расширение
.class
. - По умолчанию компилятор записывает сгенерированный
.class
в тот же каталог, где находится исходный класс.java
. - Ключ
-d
указывает компилятору, куда записывать сгенерированные.class
файлы. - При компиляции могут быть созданы отсутствующие каталоги соответствующие пакету компилируемого класса.
- Если в ключе
-d
указан не существующий каталог, будет выброшена ошибка компиляции. - При запуске программы указывается только один класс без расширения
.class
. -d
может содержать относительные и абсолютные пути.
Целью создания C++ было расширение возможностей C, наиболее распространённого языка системного программирования. Ориентированный на ту же самую область применения, C++ унаследовал множество не самых лучших, с теоретической точки зрения, особенностей C[каких?]. Перечисленные выше принципы, которых придерживался автор языка, предопределили многие недостатки C++. В области прикладного программирования альтернативой C++ стал его язык-потомок, Java. Несмотря на преемственность по отношению к C++, Java строился на принципиально иной основе, его разработчики не были связаны требованиями совместимости с языком-предком и обеспечения максимально достижимой эффективности, благодаря чему они смогли кардинально переработать язык, отказаться от множества синтаксических средств, чтобы добиться идеологической целостности языка. Позже компания Microsoft предложила язык C#, представляющий собой ещё одну переработку C++ в том же направлении, что и Java. В дальнейшем появился язык Nemerle, в котором к средствам C# добавлены средствафункционального программирования. Ещё позже появилась попытка объединения эффективности C++ с безопасностью и скоростью разработки Java и C# — был предложен язык D, который пока не получил широкого признания. Java и C++ можно рассматривать как два языка-потомка C, разработанных из различных соображений и пошедших, вследствие этого, по разным путям. В связи с этим представляет интерес сравнение данных языков (всё, сказанное ниже про Java, можно с равным успехом отнести к языкам C# и Nemerle, поскольку в рассматриваемых деталях эти языки отличаются лишь внешне).
Отличия языков приводят к ожесточённым спорам между сторонниками двух языков о том, какой язык лучше. Споры эти во многом беспредметны, поскольку сторонники Java считают различия говорящими в пользу Java, а сторонники C++ полагают обратное. C++, в свою очередь, развивался, и ряд его недостатков устранён в последних версиях стандарта (например, появился механизм частичной спецификации шаблонов). Далеко не все программисты являются сторонниками одного из языков. По мнению большинства программистов, Java и C++ не являются конкурентами, потому что обладают различными областями применимости. Другие считают, что выбор языка для многих задач является вопросом личного вкуса. |
Java 8 и Scala: сравнение возможностей
Так все-таки, Java или Scala? Интернет полнится спорами о том, неужто Scala действительно лучше, чем Java, или «кто вам дал право так утверждать»? Урс Петер и Сандер ван ден Берг озаботились тем, чтобы провести подробное сравнение, из которого следует, что Java 8 – это все равно что улучшенный Scala. Парадокс? Урс Петер – старший консультант в компании Xebia. Он работает в ИТ уже более 10 лет и занимал ряд различных позиций: разработчик, архитектор, тимлид и мастер Scrum. В ходе карьеры он работал с самыми разными языками, техниками разработки ПО и инструментами для платформы JVM. Урс Петер – один из первых сертифицированных тренеров по Scala в Европе и действующий председатель Голландского общества энтузиастов по изучению Scala (DUSE). Сандер Ван дер Берг работает в сфере ИТ с 1999 года. Он был разработчиком в нескольких компаниях, в основном занимался решениями MDA/MDD. В качестве старшего консультанта в 2010 году перешел на работу в Xebia, где занялся внедрением гибкой архитектуры и продвижением Scala. Сандер интересуется языковым проектированием и занят в нескольких сообществах функциональных программистов. Сандер любит красивые решения сложных проблем, и потому предпочитает писать именно на Scala. Кроме того, Сандеру нравятся языки Clojure, Haskell и F#.Введение
Выход JDK 8 (новый комплект для разработки на Java) запланирован на 2013 год, и в Oracle уже вполне четко представляют себе, что в него войдет. Саймон Риттер, выступавший на конференции QCon в Лондоне в этом году, обрисовал новые возможности, которые будут представлены в пакете. В частности, нас ожидают: модульная организация (проект Jigsaw), конвергенция JRockit/Hotspot, аннотирование типов и проект Lambda. С точки зрения языка наиболее важным изменением является, пожалуй, проект Lambda. Он обеспечивает поддержку лямбда-выражений, виртуальных методов расширения, а также оптимизирует поддержку многоядерных платформ – в виде параллельных коллекций. Большинство этих возможностей уже доступны во многих других языках, работающих с виртуальной машиной Java – в частности, в Scala. Кроме того, многие подходы, взятые на вооружение в Java 8, удивительно похожи на подходы Scala. И значит, упражняясь со Scala, уже можно составить впечатление о том, каким будет язык Java 8. В этой статье мы изучим новые функции Java 8, ориентируясь как на предполагаемый новый синтаксис Java, так и Scala. Мы рассмотрим лямбда-выражения, функции высшего порядка, параллельные коллекции и виртуальные методы расширения, также называемые «типажами» (traits). Кроме того, мы расскажем о новых парадигмах, которые будут интегрированы в Java 8 – в частности, о функциональном программировании. Читатели смогут убедиться, что новые концепции, внедряемые в Java и уже доступные в Scala, – это не лишнее украшательство, они способны привести к настоящей смене парадигм. Благодаря им мы приобретем массу великолепных возможностей – не исключено, что это приведет к большим переменам в самом искусстве программирования.Лямбда-выражения/Функции
Ну наконец-то в Java 8 появятся лямбда-выражения! Правда, в рамках проекта «Lambda» эти выражения доступны уже с 2009 года (тогда они еще назывались «Java-замыканиями»). Прежде, чем перейти к обсуждению примеров кода, стоит объяснить, почему лямбда-выражения – такое полезное дополнение к инструментарию Java.Зачем нужны лямбда-выражения
Как правило, лямбда-выражения используются при разработке графических пользовательских интерфейсов (GUI). Вообще, программирование GUI строится вокруг соединения поведений с событиями. Например, если пользователь нажимает кнопку (событие), то программа должна выполнить определенное поведение. Поведение может заключаться, например, в сохранении какой-то информации в базе данных. В Swing, скажем, это делается при помощи ActionListener: Этот пример показывает, как использовать класс ButtonHandler в качестве замены обратного вызова. Класс ButtonHandler присутствует в коде только для того, чтобы содержать единственный метод: actionPerformed. Данный метод определен в интерфейсе ActionListener. Этот код можно упростить, воспользовавшись внутренними анонимными классами: Итак, код стал немного чище. Рассмотрев его внимательнее, мы видим, что по-прежнему создаем экземпляр класса только для того, чтобы вызвать единственный метод. Вот для решения именно таких проблем как раз и применяются лямбда-выражения.Лямбда-выражения в качестве функций
Лямбда-выражение – это функциональный литерал. Он определяет функцию с входными параметрами и тело функции. Синтаксис лямбда-выражений в Java 8 пока еще обсуждается, но, вероятно, будет выглядеть примерно так: А вот и конкретный пример: Это лямбда-выражение вычисляет разницу в длине двух строк. Этот синтаксис можно расширить, в частности, не определяя типы аргументов (такую ситуацию мы рассмотрим ниже). Кроме того, можно создавать многострочные определения, используя { and }, чтобы группировать выражения. Идеальный пример использования такого выражения – метод Collections.sort(). Он позволяет нам отсортировать коллекцию строк (Strings) по их длине: Итак, вместо того чтобы заполнять метод sort реализацией Comparator, как это делалось бы в современном языке Java, для достижения аналогичного результата нам достаточно просто передать приведенное выше лямбда-выражение.Лямбда-выражения в качестве замыканий
У лямбда-выражений есть ряд интересных свойств. Одно из них состоит в том, что они являются замыканиями. Замыкание обеспечивает для функции доступ к переменным, находящимся вне ее непосредственной лексической области видимости (лексического контекста). В примере показано, что лямбда-выражение имеет доступ к строке outer, определенной вне области видимости этого выражения. При реализации внутристрочных сценариев лямбда-выражения могут быть очень удобны.Выведение типа – и для лямбда-выражений
Выведение типа (type inference) – возможность, появившаяся в Java 7, – также применима и к лямбда-выражениям. В сущности, выведение типа заключается в том, что программист может обойтись без определения типа везде, где компилятор сам может вывести тип – то есть определить его дедуктивным методом. Если применить выведение типа с лямбда-выражением, предназначенным для сортировки, то получится такой код: Как видите, типы параметров s1 и s2 опущены. Поскольку компилятору известно, что в списке содержится коллекция строк (Strings), ему также известно, что лямбда-выражение, используемое в качестве компаратора (сравнительного механизма), должно иметь два параметра типа String. Следовательно, отпадает необходимость в явном определении типов, хотя, конечно, это не возбраняется. Основная польза от выведения типов – в сокращении шаблонного (boilerplate) кода. Если компилятор способен вывести тип за нас – зачем нам самим это делать?Да здравствуют лямбда-выражения, прощайте, анонимные внутренние классы
Рассмотрим, как лямбда-выражения и выведение типов позволяют упростить пример с обратным вызовом, который мы затронули в начале статьи: Вместо того чтобы определять класс для содержания нашего метода обратного вызова, мы просто передаем лямбда-выражение методу addActionListener. Таким образом, мы не просто сокращаем шаблонный код и улучшаем его читаемость, но и можем прямо выразить единственную инструкцию, которая нас интересует: код обработки события. Пока мы не слишком увлеклись примерами использования лямбда-выражений, давайте посмотрим, как аналогичные выражения реализованы в Scala.Лямбда-выражения в языке Scala
Функция – это основной первоэлемент функционального программирования. В Scala комбинируются объектно-ориентированные черты, известные всем, например, по языку Java, и функциональное программирование. В Scala базовым первоэлементом является как раз лямбда-выражение, называемое «функцией» или «функциональным литералом». В Scala функции являются «сущностями первого класса» (first-class citizens). Их можно присваивать финальным и нефинальным переменным (val или var, соответственно). В качестве аргумента функцию можно передавать другой функции, кроме того, их можно комбинировать для создания новых функций. В Scala функциональный литерал записывается следующим образом: Например, предыдущее лямбда-выражение на Java, вычисляющее разницу длины двух строк, в Scala будет записываться так: В Scala функциональные литералы также являются замыканиями. Они могут получать доступ к переменным, определенным вне их лексической области видимости. Результат этого примера равен 20. Как видите, мы присвоили функциональный литерал переменной myFuncLiteral. Синтаксическое и семантическое сходство лямбда-выражений из Java 8 и функций из Scala само по себе примечательно. Семантически они практически идентичны, а синтаксическая разница заключается только в представлении символа-стрелки (Java8: -> , Scala: => ), а еще проявляется в сокращенной нотации, которая здесь не рассматривается.Функции высшего порядка как многоразовые элементы конструкций
Важнейшее достоинство функциональных литералов заключается в том, что их можно передавать точно так же, как любые другие литералы, вроде строки (String) или произвольного объекта (Object). Такая ситуация открывает широчайшие возможности и позволяет работать с исключительно компактными, многоразовыми программными конструкциями.Наша первая функция высшего порядка
Когда мы передаем функциональный литерал методу, мы, в сущности, имеем дело с такой ситуацией: один метод принимает другой. Такие методы называются «функциями высшего порядка» (higher-order functions). Метод addActionListener из предыдущего примера кода Swing – именно такой. Мы также можем определять собственные функции высшего порядка, которые нам очень пригодятся. Рассмотрим простой пример: Здесь у нас есть метод measure, который измеряет время, необходимое для выполнения обратного вызова к функциональному литералу, называемому func. Сигнатура func такова, что он не принимает никаких параметров и возвращает результат обобщенного типа Т. Как видите, функции в Scala совсем не обязательно должны иметь параметры, хотя и могут их иметь – и зачастую будут их иметь. Теперь можно передать любой функциональный литерал (или метод) методу измерения: По сути, мы только что выполнили разделение обязанностей – отделили измерение длины вызова к методу от самих вычислений. Мы создали две многоразовые слабо связанные программные конструкции (измерительную часть и часть обратного вызова) – эту ситуацию можно сравнить с работой функции-перехватчика (interceptor).Переиспользование при помощи функций высшего порядка
Рассмотрим другой пример, в котором два многоразовых конструкта связаны несколько теснее. Метод doWithContact считывает контактную информацию из файла – например, vCard. Далее он предлагает эту информацию синтаксическому анализатору (парсеру), который преобразует ее в домен объекта-контакта. После этого такой объект передается handle, обратному вызову функционального литерала. Этот вызов выполняет с доменом объекта-контакта ту операцию, которая предписывается в функции. Метод doWithContact, как и функциональный литерал, возвращает тип Unit, аналогичный использованию void в Java. Теперь можно определить различные обратные вызовы, которые могут быть переданы методу doWithContact: Кроме того, передача обратного вызова может произойти внутристрочно:В чем польза функций высшего порядка
Видимо, аналогичный код на Java 8 будет выглядеть как-то так: Как видите, при помощи функций мы реализовали четкое разделение обязанностей: создание объекта домена происходит независимо от его обработки. Таким образом, к программе легко можно подключать новые способы обработки контактных доменных объектов, и при этом их не потребуется сочленять с логикой создания доменного объекта. Итак, используя функции высшего порядка, мы избавляем код от лишних повторений – таким образом, программист извлекает максимальную пользу из многократного использования кода практически на микроуровне.Коллекции и функции высшего порядка
Функции высшего порядка обеспечивают эффективный способ работы с коллекциями. Поскольку практически любая программа имеет дело с коллекциями, их обработка может иметь огромное значение.Фильтрация коллекций: до и после
Давайте рассмотрим типичный пример использования коллекций. Допустим, мы применяем определенное вычисление к каждому элементу коллекции. Например, у нас есть список фотографий (объектов Photo), и мы хотим выделить все фотографии определенного размера. Здесь у нас слишком много шаблонного кода. В частности, в нем выполняется создание результирующей коллекции и добавление новых элементов в список. В качестве альтернативы можно использовать класс Function, в который выносится все поведение функции: Получится примерно такой код. Данный пример написан с использованием Guava. Шаблон немного сократился, но код по-прежнему остается довольно беспорядочным и пространным. Чтобы в полной мере ощутить потенциал и красоту лямбда-выражений, можно перевести этот код на Java 8 или Scala. Scala: Java 8: Обе эти реализации красивы и очень лаконичны. Обратите внимание – в обоих вариантах применяется выведение типов: параметр p типа photo явно не определяется. Как мы уже говорили, при работе со Scala вы быстро убедитесь, что выведение типов – стандартная черта этого языка.Цепочки функций в Scala
Итак, мы сократили код уже минимум на шесть строк и даже улучшили его читаемость. Но самое интересное начинается после сцепления нескольких функций высшего порядка. Чтобы это проиллюстрировать, давайте создадим класс photo и добавим ему дополнительные свойства на языке Scala: Даже если вы не слишком хорошо знаете Scala, вы можете догадаться, что здесь произошло. Мы объявили класс Photo с тремя переменными экземпляра: name, sizeKb и rates. В переменной rates будут содержаться оценки, которые пользователи выставляют фотографии, – от 1 до 10. Теперь можно создать экземпляр класса Photo – это делается так: Имея список фотографий, достаточно просто определять различные вопросы, при этом мы будем сцеплять друг с другом по нескольку функций высшего порядка. Предположим, нам требуется извлечь имена всех файлов-изображений, размер которых превышает 10 Мб. Первый вопрос: как преобразовать список названий фотографий в список имен файлов? Для этого мы воспользуемся одной из наиболее мощных функций высшего порядка, которая называется map: Метод map преобразует каждый элемент коллекции в элемент того типа, который определен в функции, переданной этому методу. В этом примере у нас есть функция, которая получает объект Photo, а возвращает строку (String). Эта строка представляет собой имя файла изображения. Применяя функцию map, мы можем решить поставленную задачу, сцепив методы map и filter, где map идет вторым. Не стоит опасаться исключений NullPointerExceptions, поскольку каждый из методов (filter, map и т.д.) всегда возвращает коллекцию. А коллекция, даже если она пуста, не может быть null. Так, наша коллекция с фотографиями с самого начала была пустой, и в результате вычислений у нас, опять же, получится пустая коллекция. Сцепление функций также называется «композицией функций». При применении композиции функций можно задействовать API Collections, чтобы найти в них блоки для решения нашей проблемы. Рассмотрим более сложный пример: Задача: «Вернуть имена всех фотографий, чей средний рейтинг выше 6, отсортировав их по общей сумме присвоенных рейтингов». Для решения этой задачи воспользуемся методом sortBy, который ожидает функцию, принимающую в качестве ввода элемент типа «коллекция» (в данном случае – Photo). Далее этот метод возвращает объект типа Ordered (в данном случае – Int). Поскольку список (List) не имеет метода для нахождения среднего значения, определим функциональный литерал avg. Этот литерал вычислит среднее значение заданного списка целых чисел (Ints) в анонимной функции, которая будет передана методу filter.Цепочки функций в Java 8
Пока не совсем ясно, какие функции высшего порядка будут предлагаться в классах коллекций языка Java 8. Скорее всего, будут поддерживаться filter и map. Следовательно, первая из приведенных выше цепочек, вероятно, будет выглядеть так: Опять же стоит отметить, что в синтаксическом плане разница со Scala практически отсутствует. Потенциал функций высшего порядка, используемых с коллекциями, очень велик. Они не только очень лаконичны и удобочитаемы, но и позволяют значительно сокращать шаблонный код со всеми вытекающими из этого выгодами – меньше тестов, меньше ошибок. Но и это еще далеко не все…Параллельные коллекции
До сих пор мы еще не касались одного из самых важных преимуществ, связанных с использованием функций высшего порядка. Такие функции не только улучшают читаемость кода и делают его более кратким, но и добавляют очень важный уровень абстракции. Обратите внимание: во всех предыдущих примерах не было ни одного цикла. Кроме того, для фильтрации коллекций их не приходилось перебирать, ассоциировать (соотносить) или сортировать элементы. Итерация скрыта от пользователя коллекции, говоря иначе, – абстрагирована. Дополнительный уровень абстракции необходим для максимально эффективного использования многоядерных платформ, поскольку базовая реализация цикла может самостоятельно «определять», как именно перебирать коллекцию. Следовательно, перебор может происходить не только последовательно, но и параллельно. Эффективное использование параллельной обработки при работе с многоядерными платформами – это уже не просто приятная, но обязательная мелочь. Теоретически все мы можем писать собственный параллельный код. На практике – это не лучший вариант. Во-первых, написание отказоустойчивого параллельного кода с разделяемыми состояниями и получением промежуточных результатов, которые затем потребуется интегрировать, – крайне сложная задача. Во-вторых, нам не хотелось бы в итоге получить ряд совсем несхожих реализаций. Даже притом, что в Java 7 есть Fork/Join, проблему декомпозиции и пересборки данных приходится решать на стороне клиента, а это не тот уровень абстракции, который нам нужен. И, в-третьих, зачем изобретать велосипед, если решение описанных проблем уже найдено в рамках функционального программирования?Параллельные коллекции в Scala
Рассмотрим простой пример на Scala, где применяется параллельная обработка: Сначала определяем метод heavyComputation, который – как понятно из названия – занимается интенсивными вычислениями (heavy computation). На четырехъядерном ноутбуке приведенное вычисление выполняется примерно за 4 секунды. После этого мы инстанцируем коллекцию типа range (диапазон от 0 до 10) и инициируем метод par. Метод par возвращает параллельную реализацию, которая предлагает такие же интерфейсы, как и последовательный аналог. Метод par есть в большинстве типов коллекций языка Scala – и это все, что нужно о нем знать. Далее зададимся вопросом, какой выгоды в плане производительности можно добиться на четырехъядерном компьютере. Чтобы найти ответ, давайте повторно используем измерительный метод, встречавшийся нам выше: В данном случае довольно странным покажется тот факт, что параллельное исполнение всего в 2,5 раза быстрее последовательного, хотя мы и задействовали все четыре ядра. Причина в том, что при обеспечении параллелизма возникают дополнительные издержки: часть вычислительной мощности тратится на порождение новых потоков и интеграцию промежуточных результатов. Следовательно, не стоит использовать параллельные коллекции по умолчанию, их лучше применять только в ходе интенсивных вычислений.Параллельные коллекции в Java 8
Интерфейс, который предположительно будет использоваться в Java 8 для работы с параллельными коллекциями, практически такой же, как и в Scala: Парадигма точно такая же, как и в Scala. Единственное отличие заключается в том, что метод для создания параллельной коллекции называется parallel(), а не par.А теперь – все сразу
Подведем итог: как может выглядеть работа с функциями высшего порядка/лямбда-выражениями в комбинации с параллельными коллекциями? Для этого мы рассмотрим довольно объемный пример кода на языке Scala. Здесь скомбинированы многие идеи, которые мы обсуждали выше. Для работы с этим примером кода был выбран сайт, на котором предлагается коллекция пейзажных обоев. Мы напишем программу, которая будет извлекать url всех этих настольных изображений и параллельно загружать картинки. Кроме основных библиотек Scala, мы воспользуемся еще двумя – Dispatch для обеспечения http-коммуникации и FileUtils, бибилотеку Apache, которая упрощает решение некоторых задач. Здесь придется столкнуться с некоторыми феноменами языка Scala, которые не освещены в данной статье, но их назначение и так должно быть понятно.Объяснение кода
Метод scrapeWallpapers обрабатывает поток управления, в котором URL изображений выбираются из html-документа, после чего загружается каждое из изображений. При помощи fetchWallpaperImgURLsOfPage все URL обоев считываются из html, отображаемого на экране. Объект Http – это класс из HTTP-библиотеки dispatch, которая предоставляет предметно-ориентированный язык (DSL) для работы с библиотекой Apache httpclient. Метод as_tagsouped преобразует html in xml, а xml уже является в Scala встроенным типом данных. Далее мы получаем из html в виде xml соответствующие href тех изображений, которые хотим загрузить: Поскольку XML нативен в Scala, мы можем использовать xpath-подобное выражение \ для выбора интересующих нас узлов. После получения всех href нам понадобится отфильтровать URL всех интересующих нас изображений и превратить href-ы в URL-объекты. Для этого мы сцепим несколько функций высшего порядка из API Collection языка Scala, как делали это выше с map и filter. В результате имеем список URL изображений. Далее требуется выполнить параллельную загрузку всех изображений. Для достижения параллелизма мы преобразуем список изображений в параллельную коллекцию. Затем метод foreach запускает несколько потоков для одновременного перебора элементов коллекции. Каждый из этих потоков будет, в конце концов, вызывать метод copyToDir. Метод copyToDir работает при помощи библиотеки FileUtils, относящейся к Apache Common. Статический метод copyURLToFile класса FileUtil импортируется также статически – следовательно, его можно вызывать непосредственно. Для ясности общей картины мы также выведем на экран имя потока, выполняющего задачу. При параллельном исполнении мы увидим, что одновременно интенсивно работает сразу несколько потоков. Этот метод также показывает, что Scala в полной мере обеспечивает взаимодействие с имеющимися библиотеками Java. Итак, функциональные черты Scala и связанные с ними очевидные выгоды – в частности, применение функций высшего порядка к коллекциям и «бесплатный» параллелизм – позволяют параллельно выполнять синтаксический анализ, ввод-вывод и преобразование данных. Для этого достаточно всего лишь нескольких строк кода.Виртуальные методы расширения/типажи
Виртуальные методы расширения в Java напоминают типажи (traits) из Scala. Что же такое «типажи»? Типаж в Scala сразу предоставляет интерфейс и может также включать реализацию – такая структура предлагает массу возможностей. Подобно Java 8, Scala не поддерживает множественное наследование. Как в Java, так и в Scala подкласс может дополнять только один суперкласс. Но в случае с типажами наследование строится иначе: в классе могут «смешиваться» несколько типажей. Интересно отметить, что класс приобретает как тип и все методы, так и состояние такого типажа (типажей). Поэтому типажи также именуются «примесями», поскольку они добавляют в класс новые состояния и поведения. Однако встает вопрос: если типажи обеспечивают какую-то форму множественного наследования, не подвержены ли они пресловутой «проблеме ромба»? Ответ: нет, не подвержены. Scala определяет четкий набор правил старшинства (precedence rules), определяющих, какой код когда выполняется в иерархии множественного наследования. Эти правила не зависят от количества примесей. Работая с такими правилами, мы приобретаем все плюсы множественного наследования, но никаких связанных с ним проблем.Если у нас есть типаж
В следующем примере показан код, понятный всем, кто работал в Java: При всей его важности с точки зрения дизайна, в повседневной практике журналирование происходит как бы незаметно. Каждый класс, снова и снова, объявляет регистратор (логгер). А нам все время приходится проверять, активирован ли уровень журналирования, – это делается, например, с помощью isDebugEnabled(). Налицо нарушение правила DRY (Don’t Repeat Yourself) – «Не повторяйся». К тому же в Java нет возможности убедиться, объявил ли программист проверку на уровне лога и использует ли он подходящий логгер, ассоциированный с классом. Java-разработчики настолько привыкли к подобной практике работы без журналирования, что она уже считается паттерном. Типажи предлагают отличную альтернативу такому паттерну. Если поместить функционал журналирования в типаж, то впоследствии мы сможем смешать этот типаж с любым классом, в какой только захотим. Таким образом, класс получает доступ к сквозной функциональности журналирования – и при этом ничем не ограничиваются возможности наследования от другого класса.Журналирование в качестве типажа – решение проблемы журналирования
В Scala мы можем реализовать типаж Loggable следующим образом: Типаж в Scala определяется при помощи ключевого слова trait. В теле типажа может содержаться всё то же, что и в абстрактном классе, – например, поля или методы. Еще один интересный момент – использование self =>. Применяется он, поскольку регистратор должен журналировать класс, с которым смешивается типаж Loggable, а не сам типаж. Синтаксис self => – такая конструкция называется в Scala “self-type” – позволяет типажу получить ссылку на класс, с которым этот типаж смешивается. Обратите внимание на использование функции без параметров msg: => T, которая служит параметром ввода для метода отладки. Основная причина использования проверки isDebugEnabled() такая: нам необходимо убедиться, что занесенная в журнал строка String будет рассчитываться лишь в случае, когда активирован отладочный уровень. То есть, если метод debug будет принимать в качестве параметра ввода только строку String, то журнальное сообщение так или иначе будет создаваться независимо от того, активирован ли отладочный уровень, – а это нежелательно. Но, передавая вместо строки String функцию без параметров msg: => T, мы получаем именно то, что нужно. А именно: функция msg, возвращающая строку String для записи в регистрационный журнал, будет активирована лишь при условии, что проверка isDebugEnabled выполнена успешно. Если выполнить isDebugEnabled не удается, то функция msg так и не вызывается, и строка String не рассчитывается, поскольку в этом нет необходимости. Если мы хотим использовать типаж Loggable в классе Photo, то для смешивания типажа с классом применяется ключевое слово extends: Ключевое слово extends наводит на мысль, что класс Photo наследует от Loggable и, соответственно, не может дополнять никакой другой класс. Но это не так. Просто по правилам синтаксиса Scala необходимо, чтобы смешивание с классом или дополнение класса начиналось со слова extends. Если мы хотим смешать с классом несколько типажей, то с каждым типажом после первого используется ключевое слово with. Ниже будут приведены примеры работы с этим словом. Чтобы продемонстрировать, что описанный метод работает, применим метод save() к классу Photo:Добавление к классам дополнительных поведений
В предыдущей части мы говорили о том, что с классом может смешиваться несколько типажей. Итак, кроме функциональности журналирования, мы можем добавить классу Photo и другое поведение. Допустим, нам нужна возможность упорядочить фотографии Photos в зависимости от размера файла. Приятно отметить, что в языке Scala предлагается ряд готовых типажей. Среди них – типаж Ordered[T]. Несмотря на то, что типаж Ordered напоминает интерфейс Java Comparable, большое и очень важное отличие между ними заключается в том, что в случае со Scala мы располагаем готовой реализацией: В показанном выше примере с классом смешиваются два типажа. Кроме определенного выше Loggable, мы также смешиваем с классом типаж Ordered[Photo]. Типаж Ordered[T] требует реализации метода compare(type:T), и это очень напоминает работу с интерфейсом Java Comparable. Кроме compare, в типаже Ordered предлагается еще ряд разных методов. Эти методы позволяют сравнивать объекты разнообразными способами, и все они используют реализацию метода compare. В отличие от Java, символьные имена, такие, как > и и т.д. мы обязаны типажу Ordered, который реализует методы с этими символами. Классы, реализующие типаж Ordered, можно сортировать в любой коллекции Scala. Имея коллекцию, заполненную объектами Ordered, можно применять к этой коллекции ключевое слово sorted, сортирующее объекты по порядку, определенному в методе compare.Достоинства типажей
Из приведенных примеров становится ясно, что при помощи типажа можно изолировать обобщенную функциональность в виде модуля. При необходимости такую изолированную функциональность можно подключить к любому классу. Чтобы добавить к классу Photo функцию журналирования, мы смешали с ним типаж Loggable, а для функции упорядочивания – типаж Ordered. Эти типажи можно вновь использовать и в других классах. В этом заключается мощный механизм для создания модульного и «сухого» (DRY) кода. В ходе работы с ним мы обходимся лишь встроенными возможностями языка, не прибегая к дополнительным технологиям – например, аспектно-ориентированному программированию.Зачем использовать виртуальные методы расширения?
В спецификации Java 8 содержится черновое описание виртуальных методов расширения. Виртуальные методы расширения добавляют стандартные реализации для новых и/или имеющихся методов имеющихся интерфейсов. А зачем? При работе со многими уже существующими интерфейсами было бы очень полезно реализовать поддержку лямбда-выражений в форме функций высшего порядка. Давайте для примера рассмотрим интерфейс java.util.Collection. Было бы очень неплохо, если бы он включал метод forEach(lambdaExpr). Но если бы такой метод предоставлялся без стандартной реализации, то все классы, использующие его, должны были бы такую реализацию обеспечивать сами. Совершенно очевидно, что в таком случае наступил бы настоящий хаос совместимости. Именно поэтому команда разработчиков JDK решила прибегнуть к виртуальным методам расширения. С ними можно, например, добавить метод forEach к интерфейсу java.util.Collection вместе со стандартной реализацией. Следовательно, все использующие его классы будут автоматически наследовать и этот метод, и его реализацию. В таком случае API будет эволюционировать как бы сам по себе, а ведь именно для этого и придуманы виртуальные методы расширения. Но если реализующему классу недостаточно стандартной реализации, то ее просто можно переопределить.Сравнение виртуальных методов расширения и типажей
Итак, основной причиной для использования виртуальных методов расширения является эволюция API. К тому же работа с ними порождает приятный положительный эффект: обеспечивается своеобразное множественное наследование, проявляющееся только на уровне поведений. А в Scala типажи допускают множественное наследование не только поведений, но и состояния, и даже позволяют ссылаться на реализующий класс (в примере с типажом Loggable мы применили для этого поле self). С практической точки зрения типажи предлагают более широкий спектр возможностей, чем виртуальные методы расширения, но используют их по разным причинам. В Scala типажи были задуманы как модульные строительные блоки, которые обеспечивают беспроблемное множественное наследование. В свою очередь, виртуальные методы расширения должны в первую очередь обеспечивать эволюцию API, и уже во вторую – множественное наследование поведений.Типажи Loggable и Ordered в Java 8
Чтобы оценить, чего можно достичь при помощи виртуальных методов расширения, давайте попробуем реализовать типажи Ordered и Loggable в Java 8. Типаж Ordered можно полностью реализовать при помощи виртуальных методов расширения, так как в нем не используется никаких состояний. Как уже упоминалось выше, аналогом Ordered в Java является java.lang.Comparable. Реализации будет иметь следующий вид: К уже имеющемуся интерфейсу Comparable мы добавили новые методы сравнения («больше», «больше или равно», «меньше», «меньше или равно»), идентичные тем, что встречаются в типаже Ordered (>, >=, default, переадресует все вызовы к имеющемуся абстрактному методу сравнения. В результате существующие интерфейсы обогащаются новыми методами, а классы, реализующие Comparable, избавляются от необходимости реализовывать также и эти методы. Если бы класс Photo реализовывал Comparable, мы могли бы производить операции сравнения с новыми добавляемыми методами. Типаж Loggable реализуется при помощи виртуальных методов расширения не полностью, но почти полностью: В этом примере мы добавили к интерфейсу Loggable методы журналирования, в частности, debug, info и т.д. По умолчанию эти методы дЧерез четыре года Python заменит C и Java
, Текст: Валерия Шмырова
Язык Python, который сейчас находится на третьем месте в рейтинге TIOBE, демонстрирует быстрый рост индекса. Составители рейтинга полагают, что через три-четыре года он возглавит рейтинг, заменив C и Java. Основной причиной роста является простота использования языка для новичков.
Python заменит C и Java
Через три-четыре года Python заменит C и Java, став самым популярным языком программирования. К такому выводу пришли составители индекса TIOBE, который оценивает популярность различных языков. Индекс рассчитывается в ходе анализа результатов поисковых запросов, которые содержат название языка, на таких порталах как Google, Blogger, Wikipedia, YouTube, Baidu, Yahoo!, Bing, Amazon и т. д.
В настоящий момент Python занимает третье место в рейтинге TIOBE с показателем 8,5%. Аналитики отмечают, что это самый высокий балл Python за все время его присутствия в рейтинге. Результат показал годовой рост на 2,77%. Сейчас Python уступает только Java и C, показатели которых равны 15% и 13,3% соответственно.
В первую десятку рейтинга также входят C++, Visual Basic .NET, C#, JavaScript, PHP, SQL и Assembly.
Напомним, Python был создан нидерландским разработчиком Гвидо ван Россум (Guido van Rossum) в 1989 г. Ван Россум официально занимает в проекте пост «великодушного пожизненного диктатора» (BDFL). Python сейчас является одним из самых широко используемых в мире языков программирования, идеальным для новичков и в тоже время нашедшим применение в масштабных проектах, в том числе YouTube, Instagram и Dropbox. Сам Гвидо как раз и работает в Dropbox, после того как в 2012 г. ушел из Google.
Другие признаки роста
Еще одним показателем популярности Python является то, что в маркетплейсе для редактора исходного кода Visual Studio Code, разработанного Microsoft, приложение Python для редактора является самым популярным — сейчас количество его установок превышает 9 млн, хотя еще в апреле их было 8 млн.
Python поднимается вверх в рейтинге TIOBE
В настоящий момент в популярной системе вопросов и ответов о программировании Stack Overflow задается больше вопросов о Python, чем о Java, который лидировал до этого. В 2018 г. Stack Overflow поставил Python на седьмое место среди самых популярных языков программирования, написания скриптов и разметки, причем в этом списке Python опередил языки C#, Ruby и PHP.
Исследование, проведенное среди 12 млн ИТ-специалистов компанией Skillsoft, показало, что общее время тренировки Python разработчиками выросло в 2018 г. на 20% по сравнению с предыдущим годом и составила 200 тыс. часов. Профильный ресурс CodingDojo поставил владение Python на второе место в списке самых востребованных работодателями навыков разработчика.
Причины роста
Основной причиной роста популярности Python составители TIOBE считают расцвет, который переживает в настоящий момент разработка ПО. Данная сфера привлекает большое количество новичков, для которых Java — это слишком подробный язык.
«Чтобы полностью понять и запустить простую программу, такую как Hello world на Java, вам необходимо знать классы, статические методы и пакеты. В C это немного проще, но тогда вы столкнетесь с явным управлением памятью. В Python это всего лишь одна строка», — поясняют аналитики.
Важным фактором роста популярности Python стало то, что компании типа Netflix используют этот язык везде, где только возможно — для создания алгоритмов рекомендаций, управление сетями распространения контента и автоматизации функций безопасности. Сам по себе Python становится более гибким и полезным во многом благодаря популярным библиотекам, таким как TensorFlow и Numpy.
Строки. Часть 8 – форматирование строк (теория).
В JDK 5 был введен механизм форматирования строк, подобный тому, что есть в операторе printf языка C. Этот механизм реализует метод format() класса String и многие другие методы, например System.out.printf().Чтобы проще было понять о чем речь, перейдем сразу к практике и рассмотрим простой пример:
Число x можно вывести на консоль с помощью выражения System.out.println(x). В результате на экране отобразится число с максимальным количеством значащих цифр, допустимых для данного типа. Например, в результате выполнения приведенного ниже фрагмента кода на экран будет выведено число 3333.3333333333335.
В ряде случаев это создает проблемы. Так, например, если вы хотите вывести на экран сумму в долларах и центах, большое количество цифр затруднит восприятие.
Форматирование строк делает их восприятие более приятным и понятным. Посмотрим какой вывод генерирует данная программа:
Как видите такой вывод более приятен и понятен. Например, первый оператор printf форматирует число x таким образом (%.2f), что длина общего поля равна размеру всего числа, а десятичная часть занимает от этого только два числа (поля).
Второй оператор printf уже форматирует значение x в виде числа, размер поля которого составляет 8 цифр, а дробная часть равна двум цифрам (%8.2f). Можете посчитать и убедиться. Кроме того обратите внимание что между символом равно (=) и числом появился пробел, поскольку для всего поля числа отведено 8 символов и все не занятые поля заполняются пробелами и происходит выравнивание по правому краю. Следующий printf уже отвел под поле числа 16 символов (%16.2f), что тоже видно на выводе программы. И последним я продемонстрировал работу метода format() класса String. Они имеют абсолютно одинаковый синтаксис, так как их функционал основан на классе Formatter.
Теперь будем разбираться более подробно с синтаксисом форматирования строк.
В методах printf() и format() можно задавать произвольное количество параметров. Пример вызова с несколькими параметрами приведен ниже.
System.out.printf(«%s, в следующем году вам будет %d», name, age);
В данном случае значение переменной (параметра) name будет подставлено вместо спецификатора формата %s, а значение переменной (параметра) age – вместо спецификатора формата %d.
Каждый спецификатор формата, начинающийся с символа %, заменяется соответствующим параметром. Символ преобразования, которым завершается спецификатор формата, задает тип форматируемого значения: f — число с плавающей точкой; s — строка; d — десятичное число; и т.п. Символы преобразования описаны в таблице ниже:
На заметку! Преобразование s можно использовать для форматирования любого объекта. Если этот объект реализует интерфейс Formattable, вызывается метод formatTo(). В противном случае для преобразования объекта в строку применяется метод toString().
Для даты и времени параметр х может быть представлен следующими символами преобразования:
В составе спецификатора формата могут присутствовать флаги, управляющие форматом выходных данных. Назначение всех флагов описано в таблице ниже:
Например, запятая, используемая в качестве флага, формирует разделитель групп, который зависит от локали (формата) установленной в вашей ОС. Так, в результате выполнения на Windwos 8.1 в русской локали, приведенного ниже оператора на экран будет выведена строка 3 333,33.
System.out.printf(«%,.2f», 10000.0 / 3.0);
То есть в качестве разделителя разрядов используется пробел, заданный в настройках локали ОС.
На заметку! Ряд правил форматирования зависит от специфических условий конкретной страны или региона.
В одном спецификаторе формата можно использовать несколько флагов, например последовательность символов «%, (.2f» указывает на то, что при выводе будут использованы разделители групп, а отрицательные числа будут помещены в скобки). Например строка:
System.out.printf(«%, (.2f», -10000.0 / 3.0);
Сгенерирует вот такой вывод: (3 333,33)
Для создания форматированной строки без вывода ее можно использовать статический метод String.format(). Например:
String message = String.format(«%s, в следующем году вам будет %d», name, age);
В строке, определяющей формат, может задаваться индекс форматируемого параметра. Индекс должен следовать непосредственно за символом % и завершаться знаком $. Пример использования индекса приведен ниже.
System.out.printf(«%1$s %2$tB %2$te, %2$tY», «Дата:», new Date());
Данный код сформирует такой вывод: Дата: июня 11, 2015
Внимание! Индексы начинаются с единицы.
Вы также можете использовать флаг <, который означает, что форматированию подлежит тот же параметр, который был сформатирован последним. Так, приведенный ниже оператор дает тот же результат, что и рассмотренное ранее.
System.out.printf(«%s %tB %<te, %<tY», «Дата:», new Date());
Чтобы все стало чуть более понятно, то, кратко, общий синтаксис можно описать так:
%[аргумент_индекс][флаги][ширина][.точность]символ_преобразования
Спецификатор ширина управляет минимальным размером поля, при необходимости пустые поля заполняются пробелами. По умолчанию данные выравниваются по правому краю, но тип выравнивания можно переопределить, включив символ – в секцию флаги.
В отличие от ширины поле точность задает минимальное значение. И если ширина относится ко всем типам преобразований данных и работает одинаково для всех типов, то точность имеет разный смысл для разных типов. Для объектов String точность задет максимальное количество выводимых символов. Для вещественных чисел точность задает количество выводимых знаков после запятой (шесть по умолчанию), с округлением или добавлением завершающих нулей в случае необходимости. Так как целые числа не имеют дробной части, точность на них не распространяется, и при попытке применения этого спецификатора с целым числом будет вызвано исключение.
В заключение теории приведу диаграмму которая показывает синтаксис спецификатора формата:
P.S. В следующем разделе будет больше практики. Я разделил теорию и практику чтобы было удобней смотреть на таблицы символов преобразования и примеры на разных вкладках, а не мотать одну страницу вверх и вниз.
Глава 18. Синтаксис
В этой главе представлена грамматика для языка программирования Java.
Грамматика представлена по частям в предыдущих главах (§2.3) намного лучше для описания, но он не очень подходит в качестве основы для парсера. В грамматика, представленная в этой главе, является основой для справки выполнение. Обратите внимание, что это не грамматика LL (1), хотя во многих случаях это сводит к минимуму необходимость смотреть вперед.
В приведенной ниже грамматике используется следующие соглашения в стиле BNF:
[x] обозначает ноль или одно вхождение x .
{x} обозначает ноль или более случаев x .
(x | y) означает один из x или y .
Идентификатор:
IDENTIFIER
QualifiedIdentifier:
Идентификатор {.
Идентификатор}
QualifiedIdentifierList:
QualifiedIdentifier {,
QualifiedIdentifier}
CompilationUnit:
[[Аннотации] пакет
QualifiedIdentifier ;
]
{ImportDeclaration} {TypeDeclaration}
ImportDeclaration:
import
[ static
] Идентификатор {.
Идентификатор} [.
, *
] ;
Декларация типа:
ClassOrInterfaceDeclaration
;
ClassOrInterfaceDeclaration:
{Modifier} (ClassDeclaration | InterfaceDeclaration)
ClassDeclaration:
NormalClassDeclaration
EnumDeclaration
InterfaceDeclaration:
NormalInterfaceDeclaration
Declaration Type
реализует
TypeList] ClassBody
EnumDeclaration:
enum
Identifier [ реализует
TypeList] EnumBody
NormalInterfaceDeclaration:
interface
Identifier [TypeParameters] [TypeParameters] [
TypeList] 942e интерфейс Идентификатор AnnotationTypeBody 0 расширяет
Тип:
BasicType { []
}
ReferenceType { []
}
BasicType:
byte
short
char
int
long
float
двойной
логический
ReferenceType:
Идентификатор [TypeArguments] {.
Идентификатор [TypeArguments]}
TypeArguments:
<
TypeArgument {,
TypeArgument} >
TypeArgument:
ReferenceType
?
[( расширяет
| super
) ReferenceType]
NonWildcardTypeArguments:
<
TypeList >
TypeList:
ReferenceType {,
ReferenceType}
TypeArgumentsOrDiamond:
<>
ArgumentsOrDiamond:
<>
ArgumentsTypeArguments
<
TypeParameter {,
TypeParameter} >
TypeParameter:
Identifier [ extends
Bound]
Bound:
ReferenceType { &
ReferenceType}
Модификатор:
Annotation
public
protected
private
static
abstract
final
native
synchronized
transient
volatile
strictfp
Annotations:
Annotation {Annotation}
Annotation:
@
QualifiedIdentifier [ (
[AnnotationElement] )
]
AnnotationElement:
ElementValuePairs
ElementValuePair
ElementPairalue
ElementValuePair:
Идентификатор =
ElementValue
ElementValue:
Аннотация
Expression1
ElementValueArrayInitializer
ElementValueArrayInit ializer:
{
[ElementValues] [,
] }
ElementValues:
ElementValue {,
ElementValue}
ClassBody:
{
{ClassBodyDeclaration} }
ClassBodyDeclaration:
;
{Модификатор} MemberDecl
[ статическая
] Блок
MemberDecl:
MethodOrFieldDecl
недействительными
Идентификатор VoidMethodDeclaratorRest
Идентификатор ConstructorDeclaratorRest
GenericMethodOrConstructorDecl
ClassDeclaration
InterfaceDeclaration
MethodOrFieldDecl:
Идентификатор MethodOrFieldRest
MethodOrFieldRest:
FieldDeclaratorsRest ;
MethodDeclaratorRest
FieldDeclaratorsRest:
VariableDeclaratorRest {,
VariableDeclarator}
MethodDeclaratorRest:
FormalParameters { []
} [ throws
ListParameters | QualifiedIdentifierList] (блок | ;
)
ConstructorDeclaratorRest:
ФормальныеПараметров [ бросает
QualifiedIdentifierList] Блок
GenericMethodOrConstructorDecl:
TypeParameters GenericMethodOrConstructorRest
GenericMethodOrConstructorRest:
(тип | недействительных
) Идентификатор MethodDeclaratorRest
Идентификатор ConstructorDeclaratorRest
InterfaceBody:
{
{InterfaceBodyDeclaration} }
InterfaceBodyDeclaration:
;
{} Модификатор InterfaceMemberDecl
InterfaceMemberDecl:
InterfaceMethodOrFieldDecl
аннулируются Идентификатор VoidInterfaceMethodDeclaratorRest
InterfaceGenericMethodDecl ClassDeclaration
InterfaceDeclaration InterfaceMethodOrFieldDecl:
Идентификатор InterfaceMethodOrFieldRest
InterfaceMethodOrFieldRest:
ConstantDeclaratorsRest ;
InterfaceMethodDeclaratorRest
ConstantDeclaratorsRest:
ConstantDeclaratorRest {,
ConstantDeclarator}
ConstantDeclaratorRest:
{ []
} =
VariableInitializer
ConstantDeclarator:
Идентификатор ConstantDeclaratorRest
InterfaceMethodDeclaratorRest:
ФормальныеПараметры { []
} [ выбрасывает
QualifiedIdentifierList] ;
VoidInterfaceMethodDeclaratorRest:
FormalParameters [ выбрасывает
QualifiedIdentifierList] ;
InterfaceGenericMethodDecl:
TypeParameters (Type | void
) Идентификатор InterfaceMethodDeclaratorRest
FormalParameters:
(
[FormalParameterDecls] )
FormalParameterDecls... VariableDeclaratorId
VariableDeclaratorId:
Идентификатор { []
}
VariableDeclarators:
VariableDeclarator {,
VariableDeclaratorDeclarator}
VariableInitializer:
ArrayInitializer
Expression
ArrayInitializer:
{
[VariableInitializer {,
VariableInitializer} [,
]] }
Блок:
{
BlockStatements }
BlockStatements:
{BlockStatement}
BlockStatement:
LocalVariableDeclarationStatement
ClassOrInterfaceDeclaration
[Идентификатор
Declators VariableDataServer :
] Заявление
Выписка:
Блок
;
Идентификатор :
Заявление
Заявление ;
if
Заявление ParExpression [ else
Заявление]
assert
Expression [:
Expression] ;
коммутатор
ParExpression {
SwitchBlockStatementGroups }
при этом
Заявление ParExpression
do
Заявление при
ParExpression ;
для
(
ForControl )
Заявление
break
[Идентификатор] ;
продолжить
[Идентификатор] ;
возврат
[Выражение] ;
бросить
Выражение ;
синхронизировано
Блок ParExpression
try
Block (Улавливает | [Улавливает] Наконец)
try
Блок спецификации ресурса [Улавливает] [И наконец]
StatementExpression:
Выражение
Уловы:
CatchClause {CatchClause}
CatchClause:
catch
(
{VariableModifier} CatchType Identifier )
Блок
CatchType:
QualifiedIdentifier { |
QualifiedIdentifier}
Наконец:
наконец
Блок
ResourceSpecification:
(
Resources [;
] )
Resources:
Resource {;
Resource}
Resource:
{VariableModifier} ReferenceType VariableDeclaratorId =
Выражение
SwitchBlockStatementGroups:
{SwitchBlockStatementGroup}
SwitchBlockStatementGroup:
SwitchLabels BlockStatements
SwitchLabels:
SwitchLabel {SwitchLabel}
SwitchLabel: по умолчанию
case
Expression
EnumConstantName:
Идентификатор
ForControl:
ForVarControl
ForInit ;
[выражение] ;
[ForUpdate]
ForVarControl:
{VariableModifier} Тип VariableDeclaratorId ForVarControlRest
ForVarControlRest:
ForVariableDeclaratorsRest ;
[выражение] ;
[ForUpdate]
:
Выражение
ForVariableDeclaratorsRest:
[ =
VariableInitializer] {,
VariableDeclarator}
ForInit:
ForUpdate:
Выражение выражения
Выражение:
Выражение1 [AssignmentOperator Expression1]
Оператор присвоения:
=
+ =
- =
* =
/ =
& =
| =
^ =
% =
<< =
>> =
>>> =
Expression1:
Expression2 [Expression1Rest]
Expression1Rest:
?
Expression :
Expression1
Expression2:
Expression3 [Expression2Rest]
Expression2Rest:
{InfixOp Expression3}
instanceof
Type
InfixOp:
||
&&
|
^
и
==
! =
<
>
<=
> =
<<
>>
> >>
+
-
*
/
%
Expression3:
PrefixOp Expression3
(
(Expression | Type) )
Expression3
Primary {Selector} {PostfixOp }
PrefixOp:
++
-
!
~
+
-
PostfixOp:
++
-
Primary:
Literal
ParExpression
this
[Arguments]
super
SuperSuffix
new
Creator
NonWildcardTypeArguments (ExplicitGenericInvocationSuffix | this
Arguments)
Identifier {.
Идентификатор} [IdentifierSuffix]
BasicType { []
} .
класс
недействителен
.
class
Literal:
IntegerLiteral
FloatingPointLiteral
CharacterLiteral
StringLiteral
BooleanLiteral
NullLiteral
ParExpression:
(
Выражение )
Аргументы:
)
SuperSuffix:
Аргументы
.
Идентификатор [аргументы]
ExplicitGenericInvocationSuffix:
super
SuperSuffix
Identifier Arguments
Создатель:
NonWildcardTypeArguments CreatedName ClassCreatorRest
CreatedName (ClassCreatorRest | ArrayCreatorRest)
CreatedName:
Идентификатор [TypeArgumentsOrDiamond] {.
Идентификатор [TypeArgumentsOrDiamond]}
ClassCreatorRest:
Аргументы [ClassBody]
ArrayCreatorRest:
[
(]
{ []
} ArrayInitializer | Expression ]
{ [
] Expression
]
[
] []
})
Идентификатор Суффикс:
[
({ []
} .
класс
| Expression) ]
Аргументы
.
( класс
| ExplicitGenericInvocation | это
| супер
Аргументы |
новых
[NonWildcardTypeArguments] InnerCreator)
ExplicitGenericInvocation:
NonWildcardTypeArguments ExplicitGenericInvocationSuffix
InnerCreator:
Идентификатор [NonWildcardTypeArgumentsOrDiamond] ClassCreatorRest
Selector:
.
Идентификатор [Аргументы]
.
ExplicitGenericInvocation
.
это
.
супер
SuperSuffix
.
новый
[NonWildcardTypeArguments] InnerCreator
[
Expression ]
EnumBody:
{
[EnumConstants] [,
] [EnumBodyDeclarations] }
EnumConstants:
EnumConstant
EnumConstants ,
EnumConstant
EnumConstants] [Идентификаторы EnumBody] [
] [Идентификаторы EnumBody] [Объяснения]
[EnumConstantings]
EnumBodyDeclarations:
;
{ClassBodyDeclaration}
AnnotationTypeBody:
{[AnnotationTypeElementDeclarations] }
AnnotationTypeElementDeclarations:
AnnotationTypeElementDeclaration AnnotationTypeElementDeclarations AnnotationTypeElementDeclaration
AnnotationTypeElementDeclaration:
{} Модификатор AnnotationTypeElementRest
AnnotationTypeElementRest:
Идентификатор AnnotationMethodOrConstantRest ;
ClassDeclaration
InterfaceDeclaration
EnumDeclaration
AnnotationTypeDeclaration
AnnotationMethodOrConstantRest:
AnnotationMethodRest
ConstantDeclaratorsRest
ElementhodRest] [] Элемент
по умолчанию)Образец: Грамматика языка Java
Этот синтаксис основан на 1.0 и 1.1 спецификации:Источник: Спецификация языка Java (1.0Alpha3) [HEADING75 в javaspec_11] Я расширяю его, чтобы включить небольшие изменения, сделанные в Java2.0.
Для получения более общей информации следуйте этим указателям: [java.html] [java.glossary.html] Для получения информации о семантике и предопределенных классах следуйте этим указателям: [java.semantics.html] , [java.html] , [java.classes.html]
Примечание
Это упрощенная грамматика для модуля компиляции Java.Программа на Java состоит из одного или нескольких модулей компиляции.Обозначение
Здесь используется моя расширенная нотация BNF XBNF, где "|" указывает "или", "(...)" указывает приоритет. O (_) означает 0 или 1 вхождение, N (_) для одного или нескольких вхождений, L (_) для списка, разделенного запятыми, и # (_) для 0 или более случаев. Для получения дополнительной информации см. [intro_ebnf.html]Java импортирует C!
Большая часть синтаксиса Java основана на синтаксисе C и / или C ++.Следующее формализует использование терминов и определений. из синтаксиса C здесь. Он также меняет некоторые имена в Синтаксис C по сравнению с синтаксисом Java.
Лексемы
Цитированный текст означает буквальные терминалы. Следующие элементы определены как в C [Лексемы в c.syntax]Комментарии в Java
- // текст
Все символы от // до конца строки игнорируются.
- / * текст * /
Все символы от / * до * / игнорируются.
- / ** текст * /
Эти комментарии обрабатываются особым образом, когда они появляются
непосредственно перед любым заявлением.Их нельзя использовать
.другое место в коде. Эти комментарии указывают на то, что
заключенный текст должен быть включен в автоматически сгенерированный
документация как описание заявленного товара.
Компиляция
Программа на Java состоит из одного или нескольких модулей компиляции.Единица компиляции может идентифицировать свой пакет, импортировать любое количество других пакеты, классы или интерфейсы, и может объявлять любое количество классов и интерфейсов:
(пакет): обратите внимание, что файл может помещать элементы не более чем в один пакет. Пакеты
набор сравнительно несвязанных классов и интерфейсов, которые хранятся
в единственном каталоге, названном в честь пакета,
и импортированы с использованием символа '.' обозначение:
import mystuff.Fun;будет импортировать содержимое класса в файл Fun.class в каталог mystuff. Код для Fun должен быть в файле с
посылка mystuff
Заявления
Выписки
Заявления Java следуют правилам, очень похожим на правила C [Заявления в c.syntax] НапримерВыражения
Выражения подчиняются правилам, очень похожим на правила C [Выражение в c.syntax]Вот краткое описание Java Expression E без учета приоритета операторов:
- E :: = C. выражение.
Все выражения Java имеют одну из следующих форм:
- (C) | -E ==> Поле | Буквальный | E Infix E | Префикс E | E Postfix | Conditional_E | Другое_E.= "|" & = "|" | = "|" << = "|" >> = "|" >>> = "|" <"|"> "|" <= "|"> = "| "==" | "! =" | "." | ",".
- (Infix, C) | -Infix = C.infix ~ "->" | "<<<" | «<<< =». В Java есть левый круговой оператор сдвига, но нет явного оператора разыменования.
- Префикс :: = "++" | "-" | "-" | "~" | "!" .
- (Префикс, C) | -Prefix = C.infix ~ "*". - в Java нет явного отмены ссылки.
- Postfix :: = "++" | «-».
- Conditional_E :: = E "?" E ":" E.
- Other_E :: = E "[" E "]" | "(" E ")" | "(" Тип ")" E | E "(" O (Arg_List) ")".
- Arg_List :: = L (E).
- Литерал :: = Boolean | Объект | Идентификатор | Номер | Строка | Персонаж.
ClockWatcher timer = новый ClockWatcher (clock1) {int count; void tick () {count ++;}};
Anonymous_Interface = Имя_интерфейса "()" Set_Of_Abstract_Method_declarations.
Типы
Составные названия
Глоссарий
и элементы объявления с примером в Java
Синтаксис в java относится к набору правил, определяющих, как пишется и интерпретируется программа Java. Синтаксис в основном заимствован из C и C ++.
Элементы синтаксиса Java:
Файл Java может содержать следующие элементы:
- Декларация упаковки
- Операции импорта
- Декларация типа
- Поля декларации
- Декларация методов
- Декларация строителей
Пример общего синтаксиса программы JAVA:
Ниже приведен пример программы, которая содержит все вышеперечисленные элементы, которые помогут вам понять основной синтаксис файла «.java файл »:
пакет basicsyntax; //Упаковка import java.util.HashMap; // Импорт заявлений //Класс public class MyFirstClass { Строка name = "Ram"; //Поле // Конструктор в JAVA public MyFirstClass () { } // Метод в JAVA общедоступная строка getName () { вернуть this.name; } // Статический главный метод в JAVA public static void main (String [] args) { } }
Пояснения ко всем вышеперечисленным элементам приведены ниже:
1.Декларация посылки:
Первая строка программы показывает объявление пакета. Эта часть, чтобы быть более конкретным:
пакет basicsyntax;
Объявление пакета состоит из слова пакет, пробела и имени пакета. Файл .java должен находиться в структуре каталогов, которая соответствует имени пакета.
2. Заявления об импорте:
Программа может иметь один или несколько операторов импорта в зависимости от требований.Оператор импорта сообщает компилятору Java, что этот класс Java использует другой класс Java.
import java.util.HashMap;
3. Декларация типа:
Объявление типа может быть классом , абстрактным классом , интерфейсом , перечислением или аннотацией .
Здесь объявленный тип - это класс. Объявление типа начинается с открывающей скобки ({) и заканчивается закрывающей скобкой (}), как показано в программе:
public class MyFirstClass { }
4.Полевая декларация:
Объявление поля заканчивается точкой с запятой (;). Тип (класс / интерфейс / перечисление) может иметь более одного поля. Ниже приводится объявление одного поля:
Строка name = "Ram";
5. Декларация строителей:
Объявление конструктора предназначено для инициализации значения, присвоенного переменным класса. У класса может быть более одного конструктора:
public MyClass () { }
6. Заявление о методах:
Когда вы создаете экземпляр класса (объекта), у объекта могут быть методы, которые вы можете выполнять.Их также иногда называют «методами экземпляра», потому что им требуется экземпляр объекта, прежде чем вы сможете вызвать метод. Вот объявление метода из приведенного выше примера:
public String getName () { вернуть this.name; }
7. Основной статический метод:
Статический метод принадлежит классу, а не объектам класса, что означает, что вы можете вызывать статический метод, не имея объекта класса, которому принадлежит статический метод.
public static void main (String [] args) { }
Важность синтаксиса:
- Синтаксис помогает вам использовать или вызывать функцию, даже если вы не знаете всей ее реализации.
- Это помогает компилятору выполнить перекрестную проверку вызываемой функции, используемой в коде, поскольку он проверяет, совпадает ли синтаксис с используемым или нет.
- Это также помогает в некоторой степени решить ошибку компилятора.
Что важно помнить:
При работе с java-программами следует иметь в виду следующие моменты:
- Чувствительность к регистру: - Java чувствительна к регистру, что означает, что прописные и строчные буквы должны рассматриваться как разные.Например, идентификаторы Cat и cat будут иметь разное значение в Java.
- Имена классов: - Первая буква имени класса должна быть в верхнем регистре. Если имя класса состоит из нескольких слов, то первая буква каждого внутреннего слова должна быть в верхнем регистре. Например: класс MyFirstClass .
- Имена методов: - Первая буква имени метода должна быть в нижнем регистре. Если имя метода состоит из нескольких слов, то первая буква каждого внутреннего слова должна быть в верхнем регистре.Например: public void myGetMethod ()
- Имя файла программы - Имя класса и имя файла программы должны совпадать. Вы должны сохранить файл программы, используя имя класса (помните, что Java чувствителен к регистру) и добавить «.java» в конец имени файла при его сохранении. (если имя файла и имя класса не совпадают, ваша программа не будет компилироваться)
Например: Предположим, что «MyFirstProgram» - это имя класса. Затем файл следует сохранить как ‘MyFirstProgram.java ’ - public static void main (String args []) - Это обязательная часть каждой программы Java, обработка которой начинается с метода main ().
Краткий справочник по синтаксису Java
Краткий справочник по синтаксису Java PGSS Ядро компьютерных наукВ этом документе слова, заключенные в угловые скобки (например, < это >) - это вещи, которые следует заменить на то, что вы хочу, чтобы код делал.
Типы
Основные типы: char, int и двойной.
Идентификаторы
Имена переменных Java и имена функций могут иметь количество буквы, цифры и символы подчеркивания, но они должны начинаться с символа письмо. Регистр букв имеет значение.
Комментарии
// < stuffExplainingYourProgram >
Функции
public static < returnValueType > < functionName > (< parameterList >) { < переменная Декларация > < statementToDo > }
Объявления переменных базового типа
< имя_типа > < имя_переменной >;
Объявления переменных массива
< имя_типа > [] < имя_переменной > = новое < имя_типа > [< arrayLengthExpression >];
заявление о возврате
return < returnValueExpression >;
Заявление о переуступке
< variableToBeChanged > = < valueToGiveItExpression >;
if операторы
if (< условие >) { < statementToDoIfConditionTrue > }
if (< условие >) { < statementToDoIfConditionTrue > } еще { < statementToDoIfConditionFalse > }
if (< условие >) { < statementToDoIfConditionTrue > } else if (< otherCondition >) { < statementToDoIfOtherConditionTrue > } еще { < statementToDoIfNoneAreTrue > }
, а выписка
while (< условие >) { < statementToDoWhileConditionTrue > }
для выписки
for (< initializeAssignment >; < condition >; < updateAssignment >) { < statementToDoWhileConditionTrue > }
Введение в синтаксис Java для разработки под Android
Java - один из «официальных» языков, поддерживаемых Google для разработки под Android, второй - Kotlin.В то время как Google все больше отдает предпочтение последней, Java остается популярной из-за ее широкого использования за пределами Android-разработки. Это востребованный язык, и его изучение может быть чрезвычайно полезным для всех, кто хочет начать карьеру в сфере развития.
К счастью, существует множество учебных пособий, которые помогут вам разобраться в общих утверждениях и их действиях. Однако, прежде чем вы начнете декодировать Java, важно понять синтаксис Java.
Ява должна быть написана определенным образом - она включает в себя изрядное количество «украшений» и некоторые странные знаки препинания.Это может немного сбить с толку новичков и может стать препятствием при попытке следовать инструкциям. Однако, когда вы разберетесь с этими основами, вам будет намного легче читать и писать новые команды Java. И хотя все это может показаться немного произвольным, все эти правила и передовые практики существуют не зря. Таким образом, понимание синтаксиса Java может помочь вам предотвратить проблемы в будущем!
Давайте посмотрим на грамматику Java и на то, почему некоторые вещи изложены именно так.
Основы синтаксиса Java
На данный момент нас не обязательно интересует, как работает Java как таковая, а скорее ее основные правила написания строки кода.
Код Java чувствителен к регистру . Позже вы научитесь давать имена своим переменным. Вам необходимо обеспечить постоянное использование заглавных букв, иначе вы столкнетесь с ошибкой.
Самое важное правило синтаксиса Java: строки заканчиваются точкой с запятой. Этот знак препинания сообщает Java (и вам), что строка кода закончена и не предназначена для перехода к следующей строке.Вроде как точка! Некоторые языки (например, Kotlin) делают это необязательным, но опускают «;» в Java подчеркнут красный цвет - код не запускается!
Исключение из этого правила - когда вы открываете новые блоки кода. Если вы заканчиваете строку открытой фигурной скобкой ({), вы каким-то образом группируете следующие строки кода. Они будут продолжаться от предыдущей строки до закрытия}.
Строки, оканчивающиеся фигурными скобками, необязательно должны сопровождаться точкой с запятой, но код внутри них имеет нормальный формат.Вы можете использовать это при написании методов - фрагментов кода, которые вы можете вызывать в любой момент программы, - и «условных операторов», которые выполняются только при соблюдении определенных условий.
Кодовые блоки также должны иметь отступ. У вас могут быть блоки внутри блоков внутри блоков (!), А отступы быстро покажут нам логическую группировку нашего кода с первого взгляда. Некоторые другие языки программирования (например, Python) требуют, чтобы эти отступы вообще запускали код, полностью избавившись от фигурных скобок.
Еще одно исключение (извините) - это комментарий, который начинается с двух штрихов вперед и позволяет вам писать сообщения для себя или коллег в будущем, объясняющие назначение сегмента кода
Если что-то вышло вам не по голове, не обращайте внимания. не волнуйся. Просто помните об этом при чтении и написании кода в будущем. Сначала это может показаться довольно инопланетным, но на все есть причина!
Хотя поначалу это может показаться довольно чуждым, все есть по какой-то причине.
На данный момент помните, что каждая строка должна заканчиваться точкой с запятой, если только она не заканчивается фигурной скобкой.Блоки кода, содержащиеся в фигурных скобках, имеют отступ, а перед комментариями ставятся две косые черты.
camelCase
Еще одна вещь, о которой следует помнить, - это соглашение об именах для ваших переменных и методов. Когда вы создаете значение, представляющее что-то вроде «Здоровье игрока», вам нужно дать ему имя. В именах переменных не должно быть пробелов, а это значит, что вы рискуете встретить повторные фразы, такие как «здоровье игрока» или более длинные. Если бы у вас была целая страница с таким текстом, его было бы довольно сложно расшифровать довольно быстро! Разборчивый код - всегда лучший код.
Вместо этого мы используем соглашение, известное как «верблюжий регистр», где каждое новое слово начинается с заглавной буквы, чтобы его было легче понять. Таким образом, «Здоровье игрока» становится либо «playerHealth», либо «PlayerHealth». Первый (playerHealth) - это «нижний верблюжий футляр», а второй (PlayerHealth) - «верхний верблюжий футляр».
Как вы будете использовать это, зависит от вас (в некотором смысле, создание методов и переменных позволяет вам определять собственный синтаксис Java), но есть некоторые передовые практики, на которые стоит обратить внимание.Хорошо следовать подобным рекомендациям, так как это не даст вам запутаться между операторами Java и вашими собственными переменными, классами и методами (все это будет иметь смысл позже).
Простое практическое правило - использовать нижний верблюжий регистр для переменных и верхний регистр верблюда для ваших методов. Это гарантирует, что вы сможете различать эти два аспекта, а знание того, что именно так кодирует большинство других людей, также облегчит вам остановку переменных в образце кода.
Очень важно называть вещи логически, чтобы их функции было легко понять с первого взгляда.Избегайте использования сокращений или случайных слов - они только усложнят понимание вашего кода, если вы сделаете перерыв. Если когда-либо непонятно, что что-то делает, напишите комментарий, чтобы объяснить это! Не верьте, что ваша память останется с вами несколько месяцев спустя.
Даже главный файл Java в нашей программе, MainActivity, написан на языке camelCase! В именах файлов также не должно быть пробелов. Между тем, в activity_main.xml используется другое соглашение об именах, так как файлы в папке ресурсов не могут использовать заглавные буквы (я не устанавливаю правила!).Таким образом, мы используем подчеркивание, чтобы отделить эти слова.
Все это может показаться несколько произвольным, но цель синтаксиса Java - сделать код как можно более читабельным, избегая при этом предотвратимых ошибок. Очень умные люди десятилетиями тестировали и экспериментировали, прежде чем остановились на этом, так что это, вероятно, неплохо!
Приобретите хорошие привычки прямо сейчас, и вы сэкономите бесчисленное количество часов в будущем.
Связанные
Синтаксис Java | Автоматизация в тестировании
Главная страница курса | Что такое синтаксис? | Примеры кода
Как упоминалось в курсе основ программирования, каждый язык программирования имеет определенный синтаксис.Конкретный способ написания кода, чтобы компилятор мог его скомпилировать.
Вот код и комментарии, объясняющие базовый синтаксис Java.
// Это комментарий кода
// Вот так мы импортируем другую библиотеку или класс в наш класс.
// Итак, в этом случае мы хотим использовать тестовую библиотеку JUnit.
// В данном случае мне нужен класс Test.
import org.junit.Test;
// Нам нужно открыть наш класс. Мы начинаем с открытого класса, за которым следует имя нашего класса.
// Итак, в этом случае наш класс называется Syntax.общедоступный синтаксис класса
// Затем открываем фигурные скобки. Это означает, что все, что находится внутри этой фигурной скобки, является частью синтаксиса класса.
{
// Здесь у нас есть переменная. Но синтаксис следующий
// Мы начинаем с модификатора доступа, за которым следует Тип, а затем имя нашей переменной.
// Затем мы должны закончить строку. Это делается для того, чтобы компилятор знал, где заканчивается строка, в Java мы делаем это через точку с запятой
общедоступная строка testName;
// Здесь мы объявляем метод. Снова мы начинаем с модификатора, за которым следуют Тип и имя.// Отличие в скобках (). Они сообщают компилятору, что следующий код является методом
public void FakeTest ()
// Затем мы открываем фигурные скобки, как мы это делали с классом, чтобы сообщить компилятору, что код в этих фигурных скобках принадлежит методу
{
// Здесь мы делаем кое-что классное
// Затем мы закрываем скобку, чтобы сказать, что это конец нашего метода
}
// Затем мы закрываем нашу самую первую скобку, чтобы сообщить компилятору, что это конец нашего класса
}
Хорошая вещь в использовании IDE заключается в том, что если вы ошибаетесь в этом синтаксисе, она обычно вам это скажет.Таким образом, в IntelliJ он сделает класс красным и поместит волнистую красную линию под тем, что, по его мнению, является причиной.
В этом примере я добавил опечатку в "import" вверху и удалил фигурную скобку, закрывающую класс. В Java намного больше синтаксиса, но этого должно быть достаточно, чтобы вы начали.
Следующий урок
₽Java Syntax Puzzlers - DZone Java
Примерно 12 лет назад я начал вносить свой вклад в экосистему Eclipse, выполняя различные функции.Одним из самых интересных событий на тот момент была работа над инструментами разработчика и обработкой крайних случаев, чтобы другим не приходилось бороться. Хотя я тем временем ушел с поста коммиттера Eclipse, я все еще привязан к работе над инструментами повышения производительности в настоящее время в качестве члена Gradle Build Tool.
Во время работы над Eclipse я с любовью вспоминаю, как работал над различными частями Java Tooling (JDT), работая над рефакторингом и быстрыми исправлениями. И неудивительно, что работа над элементами, интенсивно использующими язык, оказалась с теми же проблемами, что и другие нетривиальные алгоритмы - переход от «это будет легко» к «почему я встаю в 3 часа ночи и читаю спецификацию языка Java?»
Открытие отчета об ошибке с фрагментом для воспроизведения: 10 мин.Работа над патчем: 2ч. Спросить, сможете ли вы закончить патч 11 лет спустя: бесценно. Я скучаю по работе над #eclipse #jdt, хотя https://t.co/vpLD73zOlC
- Бенджамин Маскалла (@bmuskalla) 27 марта 2019 г.
Работа над инструментами для конкретного языка открывает вам все виды крайних случаев и тонких деталей, которые может предложить язык. Некоторые из них хорошо известны и обычно считаются «непрофессиональными» (привет goto
). О других вообще ничего не известно. И, при всем уважении, мне очень нравится обнаруживать крайние случаи синтаксиса языка - много раз, чтобы сбить с толку моих коллег, которые думают, что знают синтаксис языка Java.И, учитывая, что я люблю хорошие головоломки (особенно головоломки Java), давайте попробуем головоломку, но используя только синтаксис Java, без какого-либо поведения во время выполнения.
Использование Java для фишинга
Начнем с широко известного факта об исходных файлах Java. Вам разрешено использовать Unicode в большинстве мест вашего кода. Хотя мы не можем использовать весь диапазон Unicode в именах ваших классов, вы можете добавить достаточно Unicode, чтобы подшутить над своими коллегами.
В качестве закуски в следующем (удаленном) сеансе сопряжения просто вставьте «Греческий вопросительный знак» ( U + 037E
) в код и наблюдайте, как ваш коллега пытается выяснить, что не так с этой простой точкой с запятой.Этот метод чаще всего используется в фишинговых письмах, чтобы URL-адрес выглядел как настоящий, но на самом деле указывает на совершенно другой домен.
Поскольку он даже не компилируется, ваш коллега может легко его распознать и исправить. Давайте начнем быть немного хитрее.
Угадайте, что печатает следующая программа?
Да, в контексте сообщения вы правильно догадались, что он печатает «1 равно 2». Только как? Как можно обмануть Java, заставив думать 1 == 2, даже с помощью магии Unicode? ВНУТРИ КОММЕНТАРИИ.Есть догадки? Фактически это не меняет выражения. При этом были повреждены следующие символы Unicode:
-
\ n
-
=
- закрывающая фигурная скобка}
-
>
- открывающаяся фигурная скоба{
Итак, на самом деле мы смотрим на следующий код:
.Как ни странно, большинство программистов, увидев этот комментарий, заподозрили бы что-то подозрительное.Но как насчет отступа, чтобы он больше не отображался в вашем редакторе?
Блоки блоков
Давайте перейдем к Спецификации языка Java и посмотрим, какие интересные фрагменты синтаксиса мы можем там найти.
Рассматривая возможности, которые у нас есть для реализации методов, Java определяет тело метода таким образом, чтобы оно содержало Block
элементов:
При внимательном рассмотрении определения «Блок» мы узнаем, что они могут содержать операторы (пока все хорошо), но также… ClassDeclaration
s.Теперь становится интересно. Посмотрим, насколько глубока кроличья нора.
Как ни странно, хотя эта функция на первый взгляд кажется совершенно бесполезной, это единственная функция, которую я использовал в реальном тестовом коде в прошлом. Во время работы над фреймворком, который в значительной степени полагался на рефлексию, встроенные определения классов очень пригодились для определения тестируемых классов и сохранения их вместе с тестом. Альтернатива размещению группы вложенных классов, разбросанных вместе с тестами, была хорошей причиной для того, чтобы переместить их ближе к тесту.Вы можете прочитать мне больше об особенностях локальных классов в JLS 14.3.
То и это
Отойдя от классов и ближе к действию, давайте посмотрим на параметры метода. Как вы сами можете столкнуться несколько раз, вы не можете называть вещи так же, как ключевые слова. Что ж, давайте посмотрим на следующий фрагмент.
Итак, мы создаем новый экземпляр KeywordParameter
и вызываем для него метод callMe
, передавая параметр int
.Но подождите, у метода есть два параметра. И один даже назван по ключевому слову. Это даже не должно компилироваться, верно? Это действительно так. Глядя на объявления методов JLS 8.4, мы можем найти определение для объявлений методов.
Мы видим, что первый параметр - это специальный необязательный параметр, не входящий в список формальных параметров. И на самом деле определено, что всегда будет иметь имя , это
:
Так называемый «параметр приемника» - это «необязательное синтаксическое устройство», представляющее объект, для которого он вызывается (так что это действительно то же самое, что вы ожидаете от на
).