Итерация
Вы можете выполнить итерацию несколькими способами. Три наиболее распространенных:
- Использование итератора.
- Использование цикла for-each.
- Использование цикла for.
- Использование API Java Stream.
Я объясню каждый из этих методов итерации списка Java в следующих разделах.
Итерация с использованием итератора
Вот пример:
List list = new ArrayList(); list.add("first"); list.add("second"); list.add("third"); Iterator iterator = list.iterator(); while(iterator.hasNext()) { Object next = iterator.next(); }
Вы получаете Iterator, вызывая метод iterator() интерфейса List.
Получив Iterator, вы можете продолжать вызывать его метод hasNext(), пока он не вернет false. Вызов hasNext() выполняется внутри цикла while.
Внутри цикла while вы вызываете метод Iterator next() интерфейса Iterator для получения следующего элемента, на который указывает Iterator.
Если список напечатан с использованием Java Generics, вы можете сохранить некоторые объекты внутри цикла while. Вот пример:
List list = new ArrayList<>(); list.add("first"); list.add("second"); list.add("third"); Iterator iterator = list.iterator(); while(iterator.hasNext()){ String obj = iterator.next(); }
Итерация с использованием цикла For-Each
Второй способ – использовать цикл for, добавленный в Java 5 (также называемый циклом «для каждого»):
List list = new ArrayList(); list.add("first"); list.add("second"); list.add("third"); for(Object element : list) { System.out.println(element); }
Цикл for выполняется один раз для каждого элемента списка. Внутри него каждый элемент, в свою очередь, связан с переменной obj.
Если список напечатан (List), вы можете изменить тип переменной внутри цикла:
List list = new ArrayList(); //add elements to list for(String element : list) { System.out.println(element); }
Итерация с помощью цикла For
Пример:
List list = new ArrayList(); list.add("first"); list.add("second"); list.add("third"); for(int i=0; i < list.size(); i++) { Object element = list.get(i); }
Цикл for создает переменную int и инициализирует ее равной 0. Затем он зацикливается до тех пор, пока int i меньше размера списка. Для каждой итерации переменная увеличивается.
Внутри цикла for пример обращается к элементам List с помощью метода get(), передавая переменную i в качестве параметра.
Опять же, если список набирается с использованием Java Generics, например, для String, то вы можете использовать универсальный тип List в качестве типа для локальной переменной, которая назначается каждому элементу List в ходе итерации:
List list = new ArrayList(); list.add("first"); list.add("second"); list.add("third"); for(int i=0; i < list.size(); i++) { String element = list.get(i); }
С использованием API Java Stream
Для итерации вы должны сначала получить поток из списка. Это выполняется путем вызова метода List stream(). Вот пример получения потока из списка:
List stringList = new ArrayList(); stringList.add("abc"); stringList.add("def"); Stream stream = stringList.stream();
Последняя строка этого примера вызывает метод List stream() для получения потока, представляющего элементы списка.
Как только вы получили поток, можете выполнить итерацию потока, вызвав его метод forEach():
List stringList = new ArrayList(); stringList.add("one"); stringList.add("two"); stringList.add("three"); Stream stream = stringList.stream(); stream .forEach( element -> { System.out.println(element); });
Вызов метода forEach() заставит Stream выполнить внутреннюю итерацию всех элементов потока и вызвать получателя, переданного в качестве параметра методу forEach() для каждого элемента в потоке.
Привет, Мир JNI
Далее, давайте посмотрим, как JNI работает на практике.
В этом уроке мы будем использовать C++ в качестве родного языка и G++ в качестве компилятора и компоновщика.
Мы можем использовать любой другой компилятор по вашему выбору, но вот как установить G++ на Ubuntu, Windows и Mac OS:
- Ubuntu Linux – выполнить команду “sudo apt-get install build-essential” в терминале
- Windows – Установка MinGW
- macOS – запустите команду “g++” в терминале, и если ее еще нет, она установит ее.
3.1. Создание класса Java
Давайте начнем создавать нашу первую программу JNI с реализации классического “Hello World”.
Для начала мы создадим следующий класс Java, который включает в себя собственный метод, который будет выполнять эту работу:
package com.baeldung.jni; public class HelloWorldJNI { static { System.loadLibrary("native"); } public static void main(String[] args) { new HelloWorldJNI().sayHello(); } // Declare a native method sayHello() that receives no arguments and returns void private native void sayHello(); }
Как мы видим, мы загружаем общую библиотеку в статический блок . Это гарантирует, что он будет готов, когда он нам понадобится и откуда бы он нам ни понадобился.
В качестве альтернативы, в этой тривиальной программе мы могли бы вместо этого загрузить библиотеку непосредственно перед вызовом нашего собственного метода, потому что мы больше нигде не используем собственную библиотеку.
3.2. Реализация метода в C++
Теперь нам нужно создать реализацию нашего собственного метода в C++.
В C++ определение и реализация обычно хранятся в файлах .h и .cpp соответственно.
Во-первых, для создания определения метода мы должны использовать флаг -h компилятора Java :
javac -h . HelloWorldJNI.java
Это приведет к созданию файла com_baeldung_jni_HelloWorldJNI.h со всеми собственными методами, включенными в класс, переданными в качестве параметра, в данном случае только один:
JNIEXPORT void JNICALL Java_com_baeldung_jni_HelloWorldJNI_sayHello (JNIEnv *, jobject);
Как мы видим, имя функции автоматически генерируется с использованием полного имени пакета, класса и метода.
Кроме того, кое-что интересное, что мы можем заметить, заключается в том, что мы получаем два параметра, передаваемых нашей функции; указатель на текущий JNIEnv; , а также объект Java, к которому прикреплен метод, экземпляр нашего класса HelloWorldJNI .
Теперь нам нужно создать новый файл .cpp для реализации функции sayHello . Здесь мы будем выполнять действия, которые выводят “Hello World” на консоль.
Мы назовем наш файл .cpp тем же именем, что и файл .h, содержащий заголовок, и добавим этот код для реализации собственной функции:
JNIEXPORT void JNICALL Java_com_baeldung_jni_HelloWorldJNI_sayHello (JNIEnv* env, jobject thisObject) { std::cout << "Hello from C++ !!" << std::endl; }
3.3. Компиляция И Связывание
На данный момент у нас есть все части, которые нам нужны, и есть связь между ними.
Нам нужно создать нашу общую библиотеку из кода C++ и запустить ее!
Для этого мы должны использовать компилятор G++, не забывая включать заголовки JNI из нашей установки Java JDK .
Версия Ubuntu:
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
Версия для Windows:
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
Версия для macOS;
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin com_baeldung_jni_HelloWorldJNI.cpp -o com_baeldung_jni_HelloWorldJNI.o
Как только мы скомпилируем код для нашей платформы в файл com_baeldung_jni_HelloWorldJNI.o , мы должны включить его в новую общую библиотеку. Что бы мы ни решили назвать, это аргумент, переданный в метод System.LoadLibrary .
Мы назвали наш “родной”, и мы загрузим его при запуске нашего Java-кода.
Затем компоновщик G++ связывает объектные файлы C++ в нашу мостовую библиотеку.
Версия Ubuntu:
g++ -shared -fPIC -o libnative.so com_baeldung_jni_HelloWorldJNI.o -lc
Версия для Windows:
g++ -shared -o native.dll com_baeldung_jni_HelloWorldJNI.o -Wl,--add-stdcall-alias
Версия для macOS:
g++ -dynamiclib -o libnative.dylib com_baeldung_jni_HelloWorldJNI.o -lc
И это все!
Теперь мы можем запустить нашу программу из командной строки.
Однако нам нужно добавить полный путь к каталогу, содержащему только что созданную библиотеку. Таким образом, Java будет знать, где искать наши родные библиотеки:
java -cp . -Djava.library.path=/NATIVE_SHARED_LIB_FOLDER com.baeldung.jni.HelloWorldJNI
Вывод на консоль:
Hello from C++ !!
Причины использования синтаксиса запроса
Зачем использовать синтаксис запроса? Этот вопрос возникает довольно часто. В конце концов, следующий код:
гораздо более лаконичен, чем этот:
Может быть, синтаксис API просто является самым кратким способом формирования синтаксиса запроса?
Нет. Синтаксис запроса позволяет использовать предложение let, которое дает возможность ввести и привязать переменную в области выражения и применять ее в последующих частях выражения. Можно воспроизвести тот же код только с помощью синтаксиса API, но, скорее всего, этот код будет трудночитаемым.
Поэтому возникает вопрос о том, можно ли просто использовать синтаксис запросов?
Ответом будет Да, если…
в существующей базе кода уже используется синтаксис запроса;
необходимо ограничить переменные в запросах из-за сложности;
вы предпочитаете синтаксис запросов, который не отвлекает внимание от базы кода.
Ответом будет Нет, если…
в существующей базе кода уже используется синтаксис API;
нет необходимости ограничивать переменные в запросах;
вы предпочитаете использовать синтаксис API, который не отвлекает внимание от базы кода.
Где всё началось
Когда мы начинаем сравнивать C # и Java, мы должны начать с их историй происхождения. Зачем? Что ж, в основном из-за их пересечения, которое объясняет множество сходств, с которыми вы сталкиваетесь сегодня между этими языками.
Команда Java начала свою работу в 1991 году в Sun Microsystems. Целью было создание портативного и высокопроизводительного языка, который гарантировал бы безопасность и надёжность. Чтобы упростить переход на новый язык для разработчиков, они основали его синтаксис на уже знакомом C / C ++. Принцип Java — WORA (писать один раз, запускать где угодно). Это означает, что после того, как вы напишете программу, она должна без проблем работать на любой платформе.
Теперь, в 2000 году, у Microsoft возникла идея изменить Java, чтобы она лучше соответствовала их потребностям. Естественно, Sun Microsystems этого не допустила. Чтобы избежать юридических проблем, Microsoft решила написать собственный язык, который был бы похож на Java, но имел бы столь необходимые преимущества. Они назвали это C #.
Создатели Java и основатели Sun Microsystems публично назвали новый язык имитацией Java . Однако битва C # и Java привела к тому, что языки разошлись во времени в разных направлениях. Сегодня мы видим несколько явных различий между C # и Java.
Как сортировать
Вы можете отсортировать с помощью метода Collections sort().
Сортировка сопоставимых объектов
Если список содержит объекты, которые реализуют интерфейс Comparable(java.lang.Comparable), то эти объекты могут сравнивать себя друг с другом. В этом случае вы можете отсортировать следующим образом:
List list = new ArrayList(); list.add("c"); list.add("b"); list.add("a"); Collections.sort(list);
Класс Java String реализует интерфейс Comparable, вы можете сортировать их в естественном порядке, используя метод Collections sort().
Сортировка с помощью компаратора
Если объекты в списке не реализуют интерфейс Comparable или если вы хотите отсортировать объекты в другом порядке, чем их реализация compare(), вам необходимо использовать реализацию Comparator(java.util.Comparator). Вот пример сортировки списка объектов Car с использованием Comparator.
Первый класс автомобилей:
public class Car{ public String brand; public String numberPlate; public int noOfDoors; public Car(String brand, String numberPlate, int noOfDoors) { this.brand = brand; this.numberPlate = numberPlate; this.noOfDoors = noOfDoors; } }
Вот код, который сортирует список вышеуказанных объектов Car:
List list = new ArrayList<>(); list.add(new Car("Volvo V40" , "XYZ 201845", 5)); list.add(new Car("Citroen C1", "ABC 164521", 4)); list.add(new Car("Dodge Ram" , "KLM 845990", 2)); Comparator carBrandComparator = new Comparator() { @Override public int compare(Car car1, Car car2) { return car1.brand.compareTo(car2.brand); } }; Collections.sort(list, carBrandComparator);
Также обратите внимание, что возможно реализовать Comparator, используя Lambda. Вот пример, который сортирует объекты List of Car с использованием трех различных лямбда-реализаций интерфейса Comparator, каждая из которых сравнивает экземпляры Car по своему полю:
List list = new ArrayList<>(); list.add(new Car("Volvo V40" , "XYZ 201845", 5)); list.add(new Car("Citroen C1", "ABC 164521", 4)); list.add(new Car("Dodge Ram" , "KLM 845990", 2)); Comparator carBrandComparatorLambda = (car1, car2) -> car1.brand.compareTo(car2.brand); Comparator carNumberPlatComparatorLambda = (car1, car2) -> car1.numberPlate.compareTo(car2.numberPlate); Comparator carNoOfDoorsComparatorLambda = (car1, car2) -> car1.noOfDoors - car2.noOfDoors; Collections.sort(list, carBrandComparatorLambda); Collections.sort(list, carNumberPlatComparatorLambda); Collections.sort(list, carNoOfDoorsComparatorLambda);
LINQ является выразительной методикой
Предположим, что имеющийся список домашних животных нужно преобразовать в словарь, чтобы находить питомца напрямую по его значению .
Это традиционный императивный код:
Цель написания кода заключается не только в создании нового и его добавления с помощью цикла, но также в преобразовании существующего списка в словарь! LINQ позволяет выполнить эту задачу, тогда как принудительный код — нет.
Это эквивалентное выражение LINQ:
Код, использующий LINQ, является весьма удобным, так как он создает равные условия как для достижения цели, как и для написания кода, сохраняя при этом логику. Еще одним преимуществом является краткость кода. Большие части базы кода можно сократить на треть, как показано выше. Неплохо, правда?
Super Low Level
Этот абзац для тех, кто прочел вышесказанное и подумал, что, наверное, это сложно — стать разработчиком, я ничего не понимаю, открыл книгу — вижу фигу и т.д.
Стыдно признать, но так было и со мной — читая «Философию Java» 7 лет назад как первую книгу по Java, я думал, что нахожусь в дремучем лесу, не зная его. Я был тревожен и переживал, что, программирование — это не мое. К счастью, мне посоветовали youtube канал одного парня, который рассказывал о программировании на java с самого нуля. Это канал — theNewBoston, и вот плейлист его курса. Можно еще попробовать курсы от Lynda.com.
Ну, и самое элементарное, что мне приходит сейчас в голову (кроме детских книжек по программированию) — это серия подробно иллюстрированных книг по разработке Head First от O’Reilly и сама книга «Изучаем Java» (Head First Java).
Если это вам тоже покажется непонятным, тут два варианта: либо вы плохо стараетесь/не хотите стараться понять/изучить, либо я разговариваю с котом (:
Где и как используются методы equals() и hashcode():
Метод equals() являются ли два объекта одного происхождения логически равными. Создатель класса сам определяет характеристики, по которым проверяется равенство объектов этого класса.
Объекты должны быть экземплярами одного класса и не должны быть null. Переопределяя метод equals(), обязательно соблюдение этих требований:
Рефлексивность: Любой объект должен быть equals() самому себе.
Симметричность: Если a.equals(b) == true, то и b.equals(a) должно возвращать true.
Транзитивность: Если два объекта равны какому-то третьему объекту, значит, они должны быть равны друг и другу. Если a.equals(b) == true и a.equals(c) == true, значит проверка b.equals(c) тоже должна возвращать true.
Постоянность: Результаты работы equals() должны меняться только при изменении входящих в него полей. Если данные двух объектов не менялись, результаты проверки на equals() должны быть всегда одинаковыми.
Сравнение с null для любого объекта a.equals(null) должно возвращать false.
Метод hashCode() возвращает для любого объекта 32-битное число типа int. Если два объекта равны (т.е. метод equals() возвращает true), у них должен быть одинаковый хэш-код. Проверка по hashCode() должна идти первой для повышения быстродействия. Если метод hashCode() вызывается несколько раз на одном и том же объекте, каждый раз он должен возвращать одно и то же число. Одинаковый хэш-код может быть у двух разных объектов. Методы equals и hashCode необходимо переопределять вместе.
Beginner
Я не пытаюсь с пеной во рту доказывать, что нужно помнить каждый метод I/O API, как «Отче наш»
Куда более важно понимать, как организована ООП-составляющая Java
Брюс Эккель — настоящий эстет этого дела, он достаточно увлеченно, со всеми нюансами и тонкостями описал это в своем труде «Философия Java» (и не только ООП!)
Когда я был еще сопляком интерном и ревностно смотрел на то, как многие коллеги пишут прекрасный код, мне все советовали «Философию Java» Брюса Эккеля. Для человека, который вообще пытался понять, какая же Java красавица, мне было сложно оценить ее величие в кругу философов. Я чувствовал, что нахожусь в кругу взрослых. Вроде бы и понимал верхушку айсберга, но чего-то постоянно не хватало. Мне на помощь пришел старый добрый Хортсманн, который хорошо был переведен на русский язык. Поэтому для любого начинающего Java разработчика, на мой взгляд, двухтомник Хортсманна — самое идеальное пошаговое руководство. Есть еще Шилдт. Выберите любой для вас удобный вариант.(кстати, серия книг Хорстманна «для нетерпеливых» — очень интересная, рекомендую)
Как правило, эти книги советуют любому начинающему. Еще есть небольшие туториалы от самой Sun/Oracle.
Это всё понятно, но у меня есть кое-что на десерт. Сама жемчужина познания Java, как это ни удивительно, совсем рядом. Более того, я, с чувством гордости и небольшой ухмылкой, скажу вам, что это знание находится прямо перед вашим носом, сразу после того, как вы установите ваш первый JDK. Угадали? Имя этой жемчужины — src.zip. Грубо говоря, сорсы . Исходный код Java SE. Да-да, именно, лучший способ изучения Java — исследовать элегантные sources самого языка.
Более того, я открыто заявляю, что именно sources в Java помогут научить:— писать красивую и понятную документацию— писать приятный и чистый код— понимать best practices и паттерны, которые используются повсеместно в JDK. Стоит только вспомнить Декоратор, который применяется в java.io— ну и, само собой, прикоснуться к таким легендам Java-вселенной как Brian Goetz, Joshua Bloch, Doug Lea, непосредственно изучая их код в JDK, и т.д
Именно сорсы для меня стали отправной точкой в понимании того, как именно должен быть организован подход к любому инструменту, который ты хочешь выучить досконально, будь то язык или фреймворк. Вы можете применить эту практику не только к изучению JDK. Если вас заинтересовала какая-то библиотека, и вы просто горите от любопытства, как же это всё устроено, не спешите искать туториалы и книги в интернете. Начните с того, доступен ли исходный код. Попробуйте найти интересующую вас либу на таких ресурсах как grepcode.com.
Вы также можете углубиться в изучение Java, если попросту будете использовать ваши примеры в Debug режиме. Наблюдая в дебаггере вашей любимой IDE за структурой объектов и потоков, которые будут выполняться в ваших примерах из книжек, вы можете существенно улучшить свое понимание внутренних процессов.
Заключение
Вот я и заканчиваю первую часть цикла. Я считаю, что этого материала вполне хватит, чтобы познакомиться конкретно с Java, настолько близко, насколько это вообще возможно. Конечно, капот JVM не был освещен здесь, об этом, я думаю, мы будем упоминать в последних статьях серии.
Для тех, кто в корне не согласен с тем, что я изложил здесь, я напомню великолепную цитату: «В жизни нет ничего лучше собственного опыта». Этот набор книг и ресурсов до сих пор остается эталонной рекомендацией для меня другим людям вот уже на протяжении 5 лет и постоянно, как вы видите, наполняется новыми интересными книгами. Считайте, что это проверенный материал.
Для тех, кто только ступает на путь Java программиста.
Внимание, минутка мотивации — читать под музыку из фильма Рокки. Мой юный zero, отбрось все домыслы о том, твое это или не твое, из-за денег ты туда идешь или изменить мир, самый тяжелый момент в карьере будущего junior java developer’a — это впервые устроиться на работу после успешного собеседования (об этом мы будем говорить в последней, седьмой части моей статьи)
Верь в себя, не слушай людей, которые говорят, что ты не потянешь. При грамотном подходе и невероятном желании/упорстве человек любого возраста и любой профессии может стать программистом (да и вообще космонавтом). В нашей стране всегда может быть плохо, экономика, разруха и так далее. Двигаться нужно не завтра или как только ты уволишься с прошлой работы, а сейчас! Удачи тебе и попутного ветра!
Мой юный zero, отбрось все домыслы о том, твое это или не твое, из-за денег ты туда идешь или изменить мир, самый тяжелый момент в карьере будущего junior java developer’a — это впервые устроиться на работу после успешного собеседования (об этом мы будем говорить в последней, седьмой части моей статьи). Верь в себя, не слушай людей, которые говорят, что ты не потянешь. При грамотном подходе и невероятном желании/упорстве человек любого возраста и любой профессии может стать программистом (да и вообще космонавтом). В нашей стране всегда может быть плохо, экономика, разруха и так далее. Двигаться нужно не завтра или как только ты уволишься с прошлой работы, а сейчас! Удачи тебе и попутного ветра!
В следующей части мы поговорим о чистоте кода, рефакторинге, javadoc, интересных тулзах по улучшению кода и основных незаметных проблемах в коде, которые возникают у каждого в процессе ежедневной работы.
Большое спасибо за внимание. Следующие части цикла:— Пособие для будущего Java разработчика
Элегантный код.— Пособие для будущего Java разработчика. Enterprise — часть 1.— Пособие для будущего Java разработчика. Enterprise — часть 2.— Пособие для будущего Java разработчика. Enterprise — часть 3.— Пособие для будущего Java разработчика. Новые горизонты.— Пособие для будущего Java разработчика. Собеседование и карьера
Следующие части цикла:— Пособие для будущего Java разработчика. Элегантный код.— Пособие для будущего Java разработчика. Enterprise — часть 1.— Пособие для будущего Java разработчика. Enterprise — часть 2.— Пособие для будущего Java разработчика. Enterprise — часть 3.— Пособие для будущего Java разработчика. Новые горизонты.— Пособие для будущего Java разработчика. Собеседование и карьера.
Маєте важливу новину про українське ІТ? Розкажіть спільноті. Це анонімно.І підписуйтеся на Telegram-канал редакції DOU