Предисловие: Java 8 была выпущена в течение некоторого времени, и все признаки указывают на то, что Java 8 является серьезным изменением в распределении. У уже много статей на гиках кода Java, которые вводят новые функции Java 8, такие как игра с Java 8 Lambdas и параллелизм, Java 8 Date Time Tupe API Учебник: интерфейс LocalDateTime и абстрактный класс против JDK 8 ERA. Эта статья также относится к какой -то другой информации, такой как: 15 должна прочитать учебники Java 8 и темная сторона Java 8. Эта статья составила приведенную выше информацию и собрала ее в справочный учебник по новым функциям Java 8. Я надеюсь, что вы что -то получите.
1. Введение
Нет сомнений в том, что Java 8 является самой важной версией Java со времен Java 5 (выпущена в 2004 году). Эта версия содержит более десятка новых функций в языках, компиляторах, библиотеках, инструментах и JVM. В этой статье мы узнаем эти новые функции и используем практические примеры, чтобы проиллюстрировать, какие сценарии подходят для использования.
Этот учебник содержит несколько типов проблем, с которыми часто сталкиваются разработчики Java:
язык
Компилятор
Библиотека
инструмент
Время выполнения (JVM)
2. Новые функции языка Java
Java 8 - главная версия Java. Некоторые люди считают, что, хотя разработчики Java ожидают эти новые функции, это также требует много усилий для обучения. В этом разделе мы представим большинство новых функций Java 8.
2.1 Lambda Expressions и функциональные интерфейсы
Выражения Lambda (также известные как закрытия) являются самыми большими и наиболее ожидаемыми языковыми изменениями в Java 8. Это позволяет нам передавать функции в качестве параметров методу или обрабатывать сам код как данные: функциональные разработчики очень знакомы с этими понятиями. Многие языки на платформах JVM (Groovy, Scala и т. Д.) Поддерживают Lambda выражения с момента их рождения, но у разработчиков Java нет выбора, кроме как использовать анонимные внутренние классы вместо выражений Lambda.
Дизайн Lambda занял много времени и много усилий сообщества, и, наконец, нашел компромиссное решение для реализации, которое могло бы достичь простой и компактной структуры языка. Самое простое выражение Lambda может быть составлено из списка параметров, разделенных запятыми, -> символом и блоком операторов, например:
Arrays.aslist ("a", "b", "d") .foreach (e -> system.out.println (e));
В приведенном выше коде тип параметра e получает рассуждение компилятора, и вы также можете явно указать тип параметра, например:
Arrays.aslist ("a", "b", "d") .foreach ((string e) -> system.out.println (e));
Если выражение лямбда требует более сложного блока операторов, вы можете приложить блок операторов с вьющимися скобками, аналогично телу функции в Java, например:
Arrays.aslist ("a", "b", "d") .foreach (e -> {System.out.print (e); System.out.print (e);});Выражения Lambda могут относиться к членам класса и локальным переменным (которые косвенно преобразуют эти переменные в окончательный), например, следующие два кодовых блока имеют точно такой же эффект:
String sepreator = ","; arrays.aslist ("a", "b", "d") .foreach ((string e) -> system.out.print (e + seperator));и
final String sepreator = ","; arrays.aslist ("a", "b", "d") .foreach (((String e) -> System.out.print (e + seperator));Выражения Lambda имеют возвращаемые значения, а тип возвращаемых значений также получен с помощью вывода компилятора. Если блок операторов в выражении Lambda имеет только одну строку, вам не нужно использовать оператор Return. Следующие два фрагмента кода имеют одинаковый эффект:
Arrays.aslist ("a", "b", "d") .sort ((E1, E2) -> e1.compareto (e2));и
Arrays.aslist ("a", "b", "d") .sort ((e1, e2) -> {int result = e1.compareto (e2); return result;});Чтобы сделать существующие функции хорошо совместимыми с выражениями Lambda, дизайнеры Lambda рассматривали много методов, поэтому они придумали концепцию интерфейса функции. Функциональный интерфейс относится к интерфейсу только с одной функцией, и такой интерфейс может быть неявно преобразован в выражение лямбды. java.lang.runnable и java.util.concurrent.allable - лучшие примеры функциональных интерфейсов. На практике функциональные интерфейсы очень хрупкие: до тех пор, пока разработчик добавляет функцию к интерфейсу, интерфейс больше не является функциональным интерфейсом, что приводит к неудаче компиляции. Чтобы преодолеть эту уязвимость уровня кода и явно указать, что интерфейс является функциональным интерфейсом, Java 8 предоставляет специальную аннотацию @functionalInterface (все связанные интерфейсы в библиотеке Java уже имеют это аннотацию), чтобы дать простое определение функционального интерфейса:
@FunctionalInterface public interface function {void method ();}Тем не менее, следует отметить, что метод по умолчанию и статический метод не уничтожат определение функционального интерфейса, поэтому следующий код является законным.
@FunctionalInterface public interface functionAldefaultmethods {void method (); по умолчанию void defaultmethod () {}}Lambda Expressions, как самая большая торговая точка Java 8, может привлечь больше разработчиков, чтобы присоединиться к платформе JVM и использовать концепцию функционального программирования в программировании Pure Java. Если вам нужно узнать больше о выражениях Lambda, вы можете обратиться к официальной документации.
2.2 По умолчанию и статические методы интерфейсов
Java 8 использует две новые концепции для расширения значения интерфейса: метод по умолчанию и статический метод. Метод по умолчанию делает интерфейс немного похожим на признаки, но цели, которые должны быть достигнуты, разные. Метод по умолчанию позволяет разработчикам добавлять новые методы к существующим интерфейсам без нарушения бинарной совместимости, то есть не заставляя классы, которые реализуют интерфейс для реализации вновь добавленного метода одновременно.
Разница между методом по умолчанию и абстрактным методом заключается в том, что необходимо реализовать абстрактный метод, а метод по умолчанию - нет. Методы по умолчанию, предоставленные интерфейсом, будут унаследованы или перезаписаны классом реализации интерфейса. Пример кода заключается в следующем:
Частный интерфейс Delaulable {// Интерфейсы теперь разрешают методы по умолчанию, реализатор может или // не может реализовать (переопределить) их. строка по умолчанию notrequired () {return "реализация по умолчанию"; }} частный статический класс defaultiMpl реализует Delaulable {} частное статический класс переопределяемые внедрения Defaulable {@Override public String notRequired () {return "overden реализация";}}Дефолетный интерфейс использует ключевое слово по умолчанию для определения метода по умолчанию notrequired (). Класс DefaultableImpl реализует этот интерфейс и по умолчанию наследует методы по умолчанию в этом интерфейсе; Класс ReplidableImpl также реализует этот интерфейс, но переопределяет методы по умолчанию интерфейса и обеспечивает другую реализацию.
Другая интересная особенность, принесенная Java 8, заключается в том, что статические методы могут быть определены на интерфейсах. Пример кода заключается в следующем:
Частный интерфейс DefaulableFactory {// теперь разрешают статические методы статические дефолбные create (поставщик <defaulable> поставщик) {return upplier.get ();}}Следующий фрагмент кода объединяет сценарии использования методов по умолчанию и статических методов:
public static void main (string [] args) {defaulable default = delaulablefactory.create (defaultableImpl :: new); System.out.println (defaultable.notrequired ()); defaulable = delaulablefactory.create (overdableImpl :: new);Вывод этого кода заключается в следующем:
Реализация по умолчанию
Переопределенная реализация
Поскольку реализация метода по умолчанию в JVM обеспечивает поддержку на уровне байткода, она очень эффективна. Метод по умолчанию позволяет улучшить интерфейсы, не разбивая существующую систему наследования. Применение этой функции в официальной библиотеке: добавить новые методы в интерфейс java.util.collection, такой как stream (), parallelstream (), foreach () и release () и т. Д.
Хотя методы по умолчанию имеют так много преимуществ, их следует использовать с осторожностью в реальной разработке: в сложных системах наследования методы по умолчанию могут вызвать неоднозначность и ошибки компиляции. Если вы хотите узнать более подробную информацию, пожалуйста, обратитесь к официальной документации.
2.3 Ссылка на метод
Ссылка на метод позволяет разработчикам напрямую ссылаться на существующие методы, конструкторы класса Java или объекты экземпляра. Ссылки на методы и выражения Lambda используются в сочетании друг с другом, что делает конструктор класса Java Class Compact и кратко, без большого сложного кода шаблона.
В примере Саймона класс CAR является примером различных ссылок на метод, которые могут помочь читателям различать четыре типа ссылок на метод.
Public Static Class Car {public Static Car Create (конечный поставщик <Car> поставщик) {return ufferier.get ();} public static void коллега (Final Car) {System.out.println («Collded» + Car.toString ());} public void lethy (final car fore) {System.out.println (»(« Следующий " + void voide (final car erese) {system.out.println (" следующий " + void void void void voidtring) {System.out.println ("ремонт" + this.tostring ());}}Тип ссылки для первого метода - это ссылка на конструктор, синтаксис - это класс :: новая или более общая форма: class <t> :: new. Примечание. Этот конструктор не имеет параметров.
окончательный автомобиль = car.create (car :: new); Окончательный список <AR> cars = arrays.aslist (car);
Тип эталона второго метода является эталоном статического метода, а синтаксис - класс :: static_method. Примечание. Этот метод принимает параметр типа автомобиля.
Cars.foreach (Car :: Collide);
Третий метод ссылается на тип - это ссылка на метод члена определенного класса, а синтаксис - это метод класса ::. Обратите внимание, что этот метод не определяет параметр:
Cars.foreach (Car :: Repair);
Четвертый метод, упомянутый тип, является ссылкой на метод элемента объекта экземпляра, а синтаксис - это method. Примечание. Этот метод принимает параметр типа автомобиля:
Финальная машина полиция = car.create (car :: new); cars.foreach (полиция :: follow);
Запустите приведенный выше пример, и вы можете увидеть следующий выход в консоли (экземпляр автомобиля может быть другим):
COMPADED COM.Javacodegeeks.java8.method.references.methodreferences $ com.javacodegeeks.java8.method.references.methodreferences$car@7a81197d
Если вы хотите понять и узнать более подробный контент, вы можете обратиться к официальной документации
2.4 Повторные комментарии
С момента введения аннотаций в Java 5 эта функция стала очень популярной и широко использовалась в различных структурах и проектах. Тем не менее, аннотации имеют большое ограничение: та же аннотация не может использоваться несколько раз в одном и том же месте. Java 8 нарушает это ограничение и вводит концепцию повторных аннотаций, позволяя использовать одну и ту же аннотацию несколько раз в одном и том же месте.
Определение повторных аннотаций в Java 8 с использованием @Erepeatable аннотации на самом деле не является улучшением на уровне языка, а уловка, сделанная компилятором, и базовая технология все же. Вы можете использовать следующий код, чтобы объяснить:
пакет com.javacodegeeks.java8.repeatable.annotation; импортировать java.lang.annotation.elementtype; импортировать java.lang.annotation.repeatable; Импорт java.lang.annotation.retention; импортировать java.lang.annotation.retentionpolicy; импортировать java.lang.annotation.target; public class repectingAnnotations {@Target (elementType.type) @retention (UnfententPolicy.Runtime) public @Interface Filters {filter [] value ();} @Target (elementType.type) @retention (artentionpolicy.runtime) @repeatable (filters.class) publice @Interface filter {string kvide (); @Filter ("filter1") @filter ("filter2") public interface Filterable {} public static void main (string [] args) {for (фильтр фильтра: фильтр.Как мы видим, класс фильтров здесь использует аннотацию @repeatable (filters.class), а фильтры - это контейнер, который хранит аннотации фильтров. Компилятор пытается заблокировать эти детали от разработчиков. Таким образом, фильтруемый интерфейс может быть аннотирован двумя аннотациями фильтров (здесь не упоминается информация о фильтрах).
Кроме того, API Reflection предоставляет новый метод: getAnnotationsbytype (), который может возвращать дублируемые аннотации определенного типа, например, например,
Filterable.class.getannoation (filters.class) вернет два экземпляра фильтра, а вывод содержимого в консоли выглядит следующим образом:
Фильтр1
Фильтр2
Если вы хотите узнать больше, вы можете обратиться к официальной документации.
2.5 Лучший вывод типа
Компилятор Java 8 добился больших улучшений в выводе типа. Во многих сценариях компилятор может вывести тип данных определенного параметра, что делает код более кратким. Пример кода заключается в следующем:
пакет com.javacodegeeks.java8.type.inerence; Общественное значение класса <t> {public static <t> t defaultValue () {return null; } public t getordefault (t value, t DefaultValue) {return (value! = null)? значение: defaultValue;}}Следующий код - это приложение значения типа <string>:
пакет com.javacodegeeks.java8.type.inerence; public class typeinference {public static void main (string [] args) {окончательное значение <string> value = new Value <> (); value.getordefault ("22", value.defaultValue ());}}Тип значения параметра.defaultValue () получен компилятором и не должен быть четко указан. В Java 7 этот код будет иметь ошибку компиляции, если не используется значение. <string> defaultValue ().
2.6 Расширьте сценарии применения аннотаций
Java 8 расширяет сценарии применения аннотаций. Теперь аннотации могут использоваться практически на любом элементе: локальные переменные, типы интерфейсов, суперкласс и классы реализации интерфейса, а также даже определения исключений функций. Вот несколько примеров:
пакет com.javacodegeeks.java8.annotation; импортировать java.lang.annotation.elementtype; Импорт java.lang.annotation.retention; импортировать java.lang.annotation.retentionpolicy; импортировать java.lang.annotation.target; импортировать java.util.arraylist; Импорт java.util.collection; Аннотации открытого класса {@retention (artententionpolicy.runtime) @Target ({elementType.type_use, elementtype.type_parameter}) public @Interface nempty {} public Static Holder <@nonmapty t> extends @nonempty obj «неиспользованный») public static void main (string [] args) {final holder <string> holder = new @nonempty holder <string> (); @Nonempty Collection <@nonempty String> Strings = new ArrayList <> (); }}Elementtype.type_user и elementtype.type_parameter - это две новые аннотации, добавленные в Java 8, чтобы описать сценарии использования аннотаций. Java Language
Ян также внес соответствующие изменения, чтобы определить эти недавно добавленные примечания.
3. Новые функции Java Compiler
3.1 Имя параметра
Чтобы получить названия параметров методов в программах Java во время выполнения, старшие поколения программистов Java должны использовать различные методы, такие как Paranamer Liberary. Java 8 наконец -то нормализует эту функцию, с поддержкой на языковом уровне (используя API отражения и параметр. GetName ()) и уровень байт -кода (используя новый компилятор Javac и параметр -Параметра).
пакет com.javacodegeeks.java8.parameter.names; импортировать java.lang.reflect.method; импортировать java.lang.reflect.parameter; public class parameternames {public static void main (string [] args) бросает исключение {method method = parameternames.class.getmethod ("main", string []. class); для (окончательный параметр параметра: method.getParameters ()) {System.out.println ("Parameter:" + parameter.getName ());}}}В Java 8 эта функция выключается по умолчанию, поэтому, если вы составляете приведенный выше код без параметра -Праметра и запустить его, будут выведены следующие результаты:
Параметр: arg0
Если используется параметр -parameters, будет выведен следующий результат (правильный результат):
Параметр: Args
Если вы используете Maven для управления проектами, вы можете настроить параметр -parameters в элементе конфигурации компилятора Maven-Compiler-Plugin:
<blicin> <groupid> org.apache.maven.plugins </GroupId> <ArtifactId> maven-compiler-plugin </artifactid> <sersive> 3.1 </version> <Конфигурация> <sompilererargument> -parameters </compilerargument> <source> 1.8 </source> <arget> 1,8 </8 </arget> </compilerargument> <source> 1.8 </target> <cary> 1,8 </8 </arget> </compilerargument> </8 </arget> <cary> </plugin> </plugin>.
4. Новые функции официальной библиотеки Java
Java 8 добавила множество новых классов инструментов (классы даты/времени) и расширенные существующие классы инструментов для поддержки современного одновременного программирования, функционального программирования и т. Д.
4.1 Необязательно
Наиболее распространенной ошибкой в приложениях Java являются исключения из нулевой стоимости. Перед Java 8 Google Guava представила класс опционов, чтобы решить NullPointerException, что избегает исходного кода, загрязняемого различными нулевыми проверками, чтобы разработчики могли писать более чистый код. Java 8 также добавляет необязательно официальной библиотеке.
Необязательно просто простая вещь: хранить значение типа T или NULL. Он предоставляет несколько полезных интерфейсов, чтобы избежать явной нулевой проверки, и вы можете обратиться к официальной документации Java 8 для получения более подробной информации.
Далее, давайте посмотрим на какой -то пример использования необязательного: значение, которое может быть пустым, или значение определенного типа:
Необязательный <string> fullName = intoipl.ofnullable (null); System.out.println («Полное имя установлено?» + FullName.ispresent ()); System.out.println ("Полное имя:" + fullname.orelseget (() -> "[none]")); System.out.println (fullname.map (s -> "Привет" + s + "!") .Orelse ("Эй, незнакомец!"));Если необязательный экземпляр содержит не-нулевое значение, метод iSpresent () возвращает true, в противном случае он возвращает false; Метод OrelSeget (), а необязательный экземпляр сохраняется нулевой, он может принять значение по умолчанию, сгенерированное выражением лямбды; Метод map () может преобразовать значение существующего необязательного экземпляра в новое значение; Метод Orelse () аналогичен методу OrelSeget (), но возвращает прошедшее значение по умолчанию при хранении NULL.
Выходные результаты приведенного выше кода следующие:
Полное имя установлено? Неверное полное имя: [нет] Эй, незнакомец!
Давайте посмотрим на другой простой пример:
Необязательный <string> firstname = optacto.of ("tom"); System.out.println («Имя установлено?» + Firstname.ispresent ()); System.out.println ("Имя:" + firstname.orelseget (() -> "[none]")); System.out.println (firstname.map (s -> "hey" + s + "!") .Orelse ("Эй, незнакомец!")); System.out.println ();Вывод этого примера:
Имя установлено? Правдивое имя: Том Эй, Том!
Если вы хотите узнать более подробную информацию, пожалуйста, обратитесь к официальной документации.
4.2 потоки
Недавно добавленный API потока (java.util.stream) вводит функциональное программирование сгенерированной среды в библиотеку Java. Это, безусловно, наибольшее улучшение библиотек Java, так что разработчики могут писать более эффективный, краткий и компактный код.
Steam API значительно упрощает операции сбора (мы увидим больше, чем просто коллекции позже). Во -первых, давайте посмотрим на этот класс под названием «Задача:
Общедоступные потоки класса {private enum status {open, закрыто}; Частный статический окончательный класс задание {частное состояние окончательного статуса; Приватные окончательные целочисленные точки; задача (окончательный статус статуса, окончательные целочисленные точки) {this.status = status; this.points = points;} public integer getPoints () {return Points;} public Status getStatus () {return Status;} @Override public String toString () {return string.format (" %s, %d]", статус, точки);}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}У класса задач есть концепция фракции (или псевдо-комплектации), и есть два других состояния: открытые или закрытые. Теперь предположим, что есть сбор задач:
Окончательная коллекция <sask> tasks = arrays.aslist (новая задача (status.open, 5), новая задача (status.open, 13), новая задача (status.closed, 8));
Во -первых, давайте посмотрим на вопрос: сколько точек открытого состояния в этой коллекции задач? Перед Java 8, чтобы решить эту проблему, вам необходимо использовать Foreach, чтобы зацикливаться на сборе задач; Однако в Java 8 вы можете использовать Steams для его решения: включить список серии элементов и поддержать последовательную и параллельную обработку.
// Рассчитать общие точки всех активных задач с использованием sum () окончательный длинный общий тотальный топонтсофентас = задачи.
Выход консоли для запуска этого метода:
Общее количество очков: 18
Здесь есть много знаний, о которых стоит поговорить. Во -первых, набор задач преобразуется в представление Steam; Во -вторых, операция фильтра на паровых фильтрах все закрытые задачи; В -третьих, операция Maptoint преобразует поток задач в целочисленную коллекцию на основе метода задачи :: getPoints каждого экземпляра задачи; Наконец, сумма рассчитывается методом SUM для получения конечного результата.
Прежде чем изучать следующий пример, вам нужно запомнить некоторые знания о парах (нажмите здесь для получения более подробной информации). Операции выше Steam можно разделить на промежуточные операции и поздние операции.
Промежуточные операции возвращают новый Steam - выполнение промежуточной операции (например, Filter) не выполнит фактическую операцию фильтрации, но создаст новый Steam и поместите элементы, которые соответствуют условиям в оригинальном Steam в недавно созданный Steam.
Поздние операции (такие как Foreach или Sum) будут пересекать пар и получить результаты или сопровождать результаты; После выполнения поздних операций линия обработки Steam была обработана и не может быть использована. Почти во всех случаях поздние операции немедленно пересекают пар.
Другая ценность Steam - это творческая поддержка параллельной обработки. Для приведенной выше сбора задач мы можем использовать следующий код для расчета суммы точек всех задач:
// Рассчитать общие точки всех задач окончательные двойные тотальные точки = tasks.stream (). Parallel (). Map (task -> task.getPoints ()) // или карта (задача :: getPoints). Reduce (0, integer :: sum); System.out.println («Общие точки (все tasks):» + TotalPoints);
Здесь мы используем параллельный метод для обработки всех задач параллельно и вычислять конечный результат, используя метод уменьшения. Выход консоли выглядит следующим образом:
Общие очки (все задачи): 26,0
Для сбора часто необходимо группировать элементы в соответствии с определенными условиями. Этот тип задачи может быть выполнена быстро, используя API, предоставленный Steam. Код заключается в следующем:
// Групповые задачи по их состоянию окончательная карта <Статус, список <task>> map = tasks.stream (). Collect (collectors.groupingby (task :: getStatus)); System.out.println (map);
Выход консоли заключается в следующем:
{Recken = [[закрыто, 8]], open = [[open, 5], [open, 13]]}
Последний пример вопроса о сборе задач: как рассчитать долю точек каждой задачи в коллекции в коллекции. Конкретный код обработки следующим образом:
// Рассчитайте вес каждой задачи (в процентах от общего количества точек) Окончательный сбор <string> result = tasks.stream () // Stream <string> .maptoint (task :: getPoints) // intstream .Aslongstream () // longstream .maptoDouble (points -> points / points) // doubleStream. Boxed () //maptOlong (points -> points) / // doubleStream .boxed () //maptoLONOL (points -> points) // // doubleStream .boxed () //maptOlong (points -> points) // // doubleStream .boxed (). * 100)) // longstream .maptoobj (процент -> процент + "%") // Stream <string> .collect (collectors.tolist ()); // list <string> system.out.println (result);
Результаты вывода консоли следующие:
[19%, 50%, 30%]
Наконец, как упоминалось ранее, API Steam может действовать не только в коллекциях Java, но и традиционные операции ввода -вывода (чтение данных из файла или сетевой линии по линии) могут извлечь выгоду из обработки Steam. Вот небольшой пример:
Окончательный путь пути = новый файл (имя файла) .topath (); try (stream <string> line = files.lines (path, standardcharsets.utf_8)) {lines.onclose (() -> system.out.println ("dode!")) .foreach (system.out :: println);}Поток метод Onclose возвращает эквивалентный поток с дополнительной ручкой. Эта ручка будет выполнена при вызове метода потока Close (). Поток API, Lambda Expressions и ссылки на методы, поддерживаемые методами интерфейса по умолчанию и статическими методами, являются ответом Java 8 на современную парадигму разработки программного обеспечения.
4.3 Date/Time API (JSR 310)
Java 8 представляет новый API даты времени (JSR 310) для улучшения обработки времени и дат. Управление временем и датой всегда было самой болезненной проблемой для разработчиков Java. java.util.date, а затем java.util.calendar не решили эту проблему (еще более запутанной разработчиками).
Из-за вышеупомянутых причин родилась сторонняя библиотека Joda-Time, которая может заменить API управления временем Java. Новое API управления временем и датой в Java 8 глубоко влияет Joda-Time и поглотил много сущности Joda-Time. Новый пакет Java.Time содержит все классы о дате, времени, часовом поясе, мгновенных (аналогично на сегодняшний день, но точнее на наносекунд), продолжительность (продолжительность) и операции по часам. Недавно спроектированный API серьезно рассматривает инвариантность этих классов (лекции, изученные от java.util.calendar), и возвращает новый объект, если необходимо изменить экземпляр.
Давайте посмотрим на ключевые классы и их соответствующие примеры использования в пакете Java.Time. Во -первых, класс часов использует часовой пояс для возврата текущего времени и даты наносекунды. Часы могут заменить System.currentTimeMillis () и Timezone.getDefault ().
// Получить системные часы как смещение UTC Окончание часы часов = clock.systemutc (); System.out.println (clock.instant ()); System.out.println (clock.millis ());
Вывод этого примера:
2014-04-12T15: 19: 29.282Z 1397315969360
Во -вторых, сосредоточьтесь на классах LocalDate и LocalTime. LocalDate содержит только дату в календарной системе ISO-8601; LocalTime содержит только временную часть в календарной системе. Объекты обоих классов могут быть построены с использованием тактовых объектов.
// Получить локальную дату и локальное время finaldate date = localdate.now (); final localdate date fromclock = localdate.now (clock); System.out.println (DateFromClock); // Получить локальную дату и локальное время окончательное время localtime = localtime.now (); final localtime timefromclock = localtime.now (clock); system.out.println (время); System.out.println (TimeFromClock);
Выходные результаты приведенного выше примера следующие:
2014-04-12 2014-04-12 11: 25: 54,568 15: 25: 54,568
Класс LocalDateTime содержит информацию о LocalDate и LocalTime, но не содержит информацию часового пояса в календарной системе ISO-8601. Вот несколько примеров о LocalDate и LocalTime:
// Получить локальную дату/время окончательно localDateTime dateTime = localDateTime.now (); final LocalDateTime DateTimeFromClock = localDateTime.now (часы); System.out.println (DateTime); System.out.println (DateTimeFromClock);
Выходные результаты приведенного выше примера следующие:
2014-04-12T11: 37: 52,309 2014-04-12T15: 37: 52,309
Если вам нужна информация о данных/времени для определенного часового пояса, вы можете использовать ZoneDateTime, которая содержит дату и время системы дат ISO-8601 и имеет информацию о часовом поясе. Вот несколько примеров использования разных часовых поясов:
// Получить зонированную дату/время окончательного ZONEDDATETIME ZONEDDATETIME = ZONEDDATETIME.NOW (); final ZonedDateTime ZoneDateTimeFromClock = ZONEDDATETIME.NOW (часы); final ZonedDateTime ZodeDateTimeFromzone = ZONEDDATETIME.NOW (ZONEID.OF ("America/Los_angeles")); System.out.println (ZonedDateTime); System.out.println (ZonedDateTimeFromClock); System.out.println (ZonedDateTimeFromClock); System.out.println (ZonedDateTimeFromzone);Вывод этого примера:
2014-04-12T11: 47: 01.017-04: 00 [America/new_york] 2014-04-12T15: 47: 01.017z 2014-04-12T08: 47: 01.017-07: 00 [America/Los_angeles]
Наконец, давайте посмотрим на класс продолжительности, который удерживает время до секунд и наносекунд. Это позволяет легко рассчитать разницу между двумя датами, пример кода заключается в следующем:
// Получить продолжительность между двумя датами окончательного LocalDateTime от = localDateTime.of (2014, Month.April, 16, 0, 0, 0); Final LocalDateTime to = localDateTime.of (2015, месяц. April, 16, 23, 59, 59); окончательная продолжительность длительности = продолжительность. Между (от); duration.todays ()); System.out.println («Продолжительность в часы:» + duration.tohours ());
Этот пример используется для расчета количества дней и часов в период с 16 апреля 2014 года по 16 апреля 2015 года, и результат заключается в следующем:
Продолжительность в дни: 365 Продолжительность в часах: 8783
Общее впечатление от новой даты и времени Java 8 относительно положительно, отчасти из-за положительного воздействия Joda-Time, и отчасти потому, что официальный, наконец, слушал потребности разработчиков. Если вы хотите узнать более подробную информацию, вы можете обратиться к официальной документации.
4.4 Nashorn Javascript Engine
Java 8 предоставляет новый двигатель Nashorn JavaScript, позволяющий нам разработать и запускать приложения JS на JVM. Nashorn Javascript Engine - еще одна версия реализации javax.script.scriptengine. Этот тип двигателя скрипта следует тем же правилам и позволяет Java и JavaScript использовать интерактивное использование. Пример кода заключается в следующем:
Scriptenginemanager Manager = new ScriptengineManager ();; Scriptengine Engine = Manager.getEngineByName ("javaScript"); System.out.println (Engine.getClass (). GetName ()); System.out.println ("Результат:" + Engine.eval ("function f () {return 1;}; f () + 1;Вывод этого кода заключается в следующем:
jdk.nashorn.api.scripting.nashornscriptengine Результаты: 2
4.5 BASE64
Поддержка кодирования Base64 была добавлена в официальную библиотеку Java 8, так что кодирование BASE64 может быть выполнено без использования сторонней библиотеки. Пример кода заключается в следующем:
пакет com.javacodegeeks.java8.base64; импортировать java.nio.charset.standardcharsets; импортировать java.util.base64; открытый класс base64s {public static void main (string [] args) {final String text = "base64 Наконец -то в Java 8!"; final String oncoded = base64.getencoder (). EncodetoString (text.getBytes (standardcharsets.utf_8)); System.out.println (кодировка); Окончательная строка decoded = new String (base64.getDecoder (). Decode (кодированный), standardcharsets.utf_8); System.out.println (decoded);}}Вывод этого примера заключается в следующем:
Qmfzzty0igzpbmfsbhkgaw4gsmf2ysa4iq ==
Base64 Наконец -то в Java 8!
Новая Base64API также поддерживает кодирование и декодирование URL и шахт.
(Base64.getUrlencoder () / base64.geturldecoder (), base64.getmimeencoder () / base64.getmimedecoder ()).
4.6 Параллельные массивы
Версия Java8 добавила много новых методов для поддержки обработки параллельных массивов. Наиболее важным методом является Parallelsort (), который может значительно ускорить сортировку массива на многоядерных машинах. Следующий пример демонстрирует метод серии Parallelexxxx:
пакет com.javacodegeeks.java8.parallel.arrays; импорт java.util.arrays; импорт java.util.concurrent.threadlocalrandom; открытый класс Parallelarrays {public static void main (string [] args) {long [] arrayoflong = new Long [20000]; Arrays.parallelSetAll( arrayOfLong, index -> ThreadLocalRandom.current().nextInt( 1000000 ) );Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );System.out.println();Arrays.parallelSort( arrayOfLong );Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) );System.out.println();}}上述这些代码使用parallelSetAll()方法生成20000个随机数,然后使用parallelSort()方法进行排序。这个程序会输出乱序数组和排序数组的前10个元素。上述例子的代码输出的结果是:
Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378 Sorted: 39 220 263 268 325 607 655 678 723 793
4.7 并发性
基于新增的lambda表达式和steam特性,为Java 8中为java.util.concurrent.ConcurrentHashMap类添加了新的方法来支持聚焦操作;另外,也为java.util.concurrentForkJoinPool类添加了新的方法来支持通用线程池操作(更多内容可以参考我们的并发编程课程)。
Java 8还添加了新的java.util.concurrent.locks.StampedLock类,用于支持基于容量的锁――该锁有三个模型用于支持读写操作(可以把这个锁当做是java.util.concurrent.locks.ReadWriteLock的替代者)。
在java.util.concurrent.atomic包中也新增了不少工具类,列举如下:
DoubleAccumulator
DoubleAdder
LongAccumulator
LongAdder
5. 新的Java工具
Java 8提供了一些新的命令行工具,这部分会讲解一些对开发者最有用的工具。
5.1 Nashorn引擎:jjs
jjs是一个基于标准Nashorn引擎的命令行工具,可以接受js源码并执行。例如,我们写一个func.js文件,内容如下:
function f() { return 1; }; print( f() + 1 );可以在命令行中执行这个命令:jjs func.js,控制台输出结果是:
2
如果需要了解细节,可以参考官方文档。
5.2 类依赖分析器:jdeps
jdeps是一个相当棒的命令行工具,它可以展示包层级和类层级的Java类依赖关系,它以.class文件、目录或者Jar文件为输入,然后会把依赖关系输出到控制台。
我们可以利用jedps分析下Spring Framework库,为了让结果少一点,仅仅分析一个JAR文件:org.springframework.core-3.0.5.RELEASE.jar。
jdeps org.springframework.core-3.0.5.RELEASE.jar
这个命令会输出很多结果,我们仅看下其中的一部分:依赖关系按照包分组,如果在classpath上找不到依赖,则显示”not found”.
org.springframework.core-3.0.5.RELEASE.jar -> C:/Program Files/Java/jdk1.8.0/jre/lib/rt.jarorg.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)-> java.io -> java.lang -> java.lang.annotation -> java.lang.ref -> java.lang.reflect -> java.util -> java.util.concurrent -> org.apache.commons.logging not found-> org.springframework.asm not found-> org.springframework.asm.commons not foundorg.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)-> java.lang -> java.lang.annotation -> java.lang.reflect -> java.util
更多的细节可以参考官方文档。
6. JVM的新特性
使用Metaspace(JEP 122)代替持久代(PermGen space)。在JVM参数方面,使用-XX:MetaSpaceSize和-XX:MaxMetaspaceSize代替原来的-XX:PermSize和-XX:MaxPermSize。
7. Заключение
通过为开发者提供很多能够提高生产力的特性,Java 8使得Java平台前进了一大步。现在还不太适合将Java 8应用在生产系统中,但是在之后的几个月中Java 8的应用率一定会逐步提高(PS:原文时间是2014年5月9日,现在在很多公司Java 8已经成为主流,我司由于体量太大,现在也在一点点上Java 8,虽然慢但是好歹在升级了)。作为开发者,现在应该学习一些Java 8的知识,为升级做好准备。