Рубрики
Без рубрики

Функции Java 8 с примерами

Функции Java 8 с примерами. Функции Java 1.8. Новые функции Java 8 с примерами методов forEach, по умолчанию и статических методов, лямбда-выражений, потока и т.д.

Автор оригинала: Pankaj Kumar.

Java 8 была выпущена 18 марта 2014 года. Это было давно, но до сих пор многие проекты выполняются на Java 8. Это потому, что это был крупный релиз с большим количеством новых функций. Давайте рассмотрим все интересные и основные функции Java 8 на примере кода.

Краткий обзор функций Java 8

Некоторые из важных функций Java 8 являются;

  1. Метод forEach() в итерационном интерфейсе
  2. стандартные и статические методы в интерфейсах
  3. Функциональные интерфейсы и Лямбда-выражения
  4. API потока Java для массовых операций с данными в коллекциях
  5. API времени Java
  6. Улучшения API сбора
  7. Улучшения API параллелизма
  8. Улучшения ввода-вывода Java

Давайте кратко рассмотрим эти функции Java 8. Я приведу некоторые фрагменты кода для лучшего понимания функций простым способом.

1. Метод forEach() в итерационном интерфейсе

Всякий раз, когда нам нужно пройти через коллекцию, нам нужно создать итератор, вся цель которого состоит в повторении, а затем у нас есть бизнес-логика в цикле для каждого из элементов Коллекции. Мы можем получить исключение ConcurrentModificationException, если итератор используется неправильно.

Java 8 представила для каждого метода в java.lang.Итерируемый интерфейс, так что при написании кода мы фокусируемся на бизнес-логике. Метод forEach использует функцию java.util..Объект потребителя в качестве аргумента, поэтому он помогает разместить нашу бизнес-логику в отдельном месте, которое мы можем повторно использовать. Давайте рассмотрим каждое использование на простом примере.

package com.journaldev.java8.foreach;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.lang.Integer;

public class Java8ForEachExample {

	public static void main(String[] args) {
		
		//creating sample Collection
		List myList = new ArrayList();
		for(int i=0; i<10; i++) myList.add(i);
		
		//traversing using Iterator
		Iterator it = myList.iterator();
		while(it.hasNext()){
			Integer i = it.next();
			System.out.println("Iterator Value::"+i);
		}
		
		//traversing through forEach method of Iterable with anonymous class
		myList.forEach(new Consumer() {

			public void accept(Integer t) {
				System.out.println("forEach anonymous class Value::"+t);
			}

		});
		
		//traversing with Consumer interface implementation
		MyConsumer action = new MyConsumer();
		myList.forEach(action);
		
	}

}

//Consumer implementation that can be reused
class MyConsumer implements Consumer{

	public void accept(Integer t) {
		System.out.println("Consumer impl Value::"+t);
	}
}

Количество строк может увеличиться, но для каждого метода помогает наличие логики итерации и бизнес-логики в отдельном месте, что приводит к более высокому разделению проблем и более чистому коду.

2. стандартные и статические методы в интерфейсах

Если вы внимательно прочтете сведения о каждом методе, вы заметите, что он определен в итерационном интерфейсе, но мы знаем, что интерфейсы не могут иметь тело метода. Начиная с Java 8, интерфейсы расширены, чтобы иметь метод с реализацией. Мы можем использовать по умолчанию и статическое ключевое слово для создания интерфейсов с реализацией метода. для каждой реализации метода в итерационном интерфейсе:

default void forEach(Consumer action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

Мы знаем, что Java не обеспечивает множественное наследование в классах , потому что это приводит к Алмазной проблеме . Итак, как теперь это будет обрабатываться с интерфейсами, поскольку интерфейсы теперь похожи на абстрактные классы?

Решение заключается в том, что компилятор создаст исключение в этом сценарии, и нам придется предоставить логику реализации в классе, реализующем интерфейсы.

package com.journaldev.java8.defaultmethod;

@FunctionalInterface
public interface Interface1 {

	void method1(String str);
	
	default void log(String str){
		System.out.println("I1 logging::"+str);
	}
	
	static void print(String str){
		System.out.println("Printing "+str);
	}
	
	//trying to override Object method gives compile-time error as
	//"A default method cannot override a method from java.lang.Object"
	
//	default String toString(){
//		return "i1";
//	}
	
}
package com.journaldev.java8.defaultmethod;

@FunctionalInterface
public interface Interface2 {

	void method2();
	
	default void log(String str){
		System.out.println("I2 logging::"+str);
	}

}

Обратите внимание, что оба интерфейса имеют общий метод log() с логикой реализации.

package com.journaldev.java8.defaultmethod;

public class MyClass implements Interface1, Interface2 {

	@Override
	public void method2() {
	}

	@Override
	public void method1(String str) {
	}

	//MyClass won't compile without having it's own log() implementation
	@Override
	public void log(String str){
		System.out.println("MyClass logging::"+str);
		Interface1.print("abc");
	}
	
}

Как вы можете видеть, Интерфейс 1 имеет реализацию статического метода, которая используется в Мой класс.long() реализация метода. Java 8 использует по умолчанию и статические методы в значительной степени в API сбора и методы по умолчанию добавляются, чтобы наш код оставался обратно совместимым.

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

Для получения более подробной информации об изменениях интерфейса в Java 8, пожалуйста, прочитайте Изменения интерфейса Java 8 .

3. Функциональные интерфейсы и лямбда-выражения

Если вы заметили приведенный выше код интерфейса, вы заметите аннотацию @functional Interface. Функциональные интерфейсы-это новая концепция, представленная в Java 8. Интерфейс с ровно одним абстрактным методом становится Функциональным интерфейсом. Нам не нужно использовать аннотацию @Functional Interface для обозначения интерфейса как функционального интерфейса.

Аннотация @Functional Interface-это средство, позволяющее избежать случайного добавления абстрактных методов в функциональные интерфейсы. Вы можете думать об этом так @Переопределите аннотацию, и лучше всего ее использовать. ява.ланг.Запускаемый с помощью одного абстрактного метода run() является отличным примером функционального интерфейса.

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

Runnable r = new Runnable(){
			@Override
			public void run() {
				System.out.println("My Runnable");
			}};

Поскольку функциональные интерфейсы имеют только один метод, лямбда-выражения могут легко обеспечить реализацию метода. Нам просто нужно предоставить аргументы метода и бизнес-логику. Например, мы можем написать вышеописанную реализацию, используя лямбда-выражение как:

Runnable r1 = () -> {
			System.out.println("My Runnable");
		};

Если у вас есть один оператор в реализации метода, нам также не нужны фигурные скобки. Например, приведенный выше интерфейс 1 анонимный класс может быть создан с помощью лямбда-кода следующим образом:

Interface1 i1 = (s) -> System.out.println(s);
		
i1.method1("abc");

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

Новый пакет java.util.function был добавлен с набором функциональных интерфейсов для предоставления целевых типов для лямбда-выражений и ссылок на методы. Лямбда-выражения-огромная тема, об этом я напишу отдельную статью в будущем.

Вы можете прочитать полный учебник в руководстве по лямбда-выражениям Java 8 .

4. Java Stream API для массовых операций с данными в коллекциях

В Java 8 добавлен новый java.util.stream для выполнения операций фильтрации/сопоставления/уменьшения подобных с коллекцией. Потоковый API позволит выполнять как последовательное, так и параллельное выполнение. Это одна из лучших функций для меня, потому что я много работаю с коллекциями и, как правило, с большими данными, нам нужно отфильтровать их в зависимости от некоторых условий.

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

package com.journaldev.java8.stream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamExample {

	public static void main(String[] args) {
		
		List myList = new ArrayList<>();
		for(int i=0; i<100; i++) myList.add(i);
		
		//sequential stream
		Stream sequentialStream = myList.stream();
		
		//parallel stream
		Stream parallelStream = myList.parallelStream();
		
		//using lambda with Stream API, filter example
		Stream highNums = parallelStream.filter(p -> p > 90);
		//using lambda in forEach
		highNums.forEach(p -> System.out.println("High Nums parallel="+p));
		
		Stream highNumsSeq = sequentialStream.filter(p -> p > 90);
		highNumsSeq.forEach(p -> System.out.println("High Nums sequential="+p));

	}

}

Если вы запустите приведенный выше пример кода, вы получите такой вывод:

High Nums parallel=91
High Nums parallel=96
High Nums parallel=93
High Nums parallel=98
High Nums parallel=94
High Nums parallel=95
High Nums parallel=97
High Nums parallel=92
High Nums parallel=99
High Nums sequential=91
High Nums sequential=92
High Nums sequential=93
High Nums sequential=94
High Nums sequential=95
High Nums sequential=96
High Nums sequential=97
High Nums sequential=98
High Nums sequential=99

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

Охватить все о потоковом API в этом посте невозможно, вы можете прочитать все о потоковом API в примере учебника Java 8 по потоковому API .

5. API времени Java

Всегда было трудно работать с датой, временем и часовыми поясами на java. В Java не было стандартного подхода или API для определения даты и времени в Java. Одним из приятных дополнений в Java 8 является пакет java.time , который упростит процесс работы со временем в java.

Просто взглянув на пакеты API Java Time, я чувствую, что они будут очень просты в использовании. В нем есть некоторые подпакеты java.time.format, которые предоставляют классы для печати и анализа дат и времени, а java.time.zone обеспечивает поддержку часовых поясов и их правил.

API нового времени предпочитает перечисления целочисленным константам для месяцев и дней недели. Одним из полезных классов является DateTimeFormatter для преобразования объектов DateTime в строки. Для получения полного руководства перейдите к примеру учебника Java Date Time API .

6. Улучшения API сбора данных

Мы уже видели для каждого метода() и API потока для коллекций. Некоторые новые методы, добавленные в API сбора, включают:

  • Итератор метод по умолчанию forEachRemaining(действие потребителя) для выполнения данного действия для каждого оставшегося элемента до тех пор, пока все элементы не будут обработаны или действие не вызовет исключение.
  • Коллекция метод по умолчанию removeIf(фильтр предикатов) для удаления всех элементов этой коллекции, удовлетворяющих данному предикату.
  • Коллекция spliterator() метод, возвращающий экземпляр Spliterator, который можно использовать для последовательного или параллельного обхода элементов.
  • Сопоставить Заменить () , вычислить() , объединить() методы.
  • Повышение производительности для класса HashMap с коллизиями ключей

7. Улучшения API параллелизма

Некоторые важные параллельные усовершенствования API включают:

  • ConcurrentHashMap вычисление(), для каждого(), для каждой записи(), для каждого ключа(), для каждого значения(), методы слияния(), сокращения() и поиска ().
  • CompletableFuture , который может быть явно завершен (установка его значения и статуса).
  • Исполнители newWorkStealingPool() метод создания пула потоков, крадущих работу, с использованием всех доступных процессоров в качестве целевого уровня параллелизма.

8. Улучшения ввода-вывода Java

Некоторые улучшения ввода-вывода, известные мне, заключаются в следующем:

  • Files.list(Путь к каталогу) , который возвращает лениво заполненный поток, элементами которого являются записи в каталоге.
  • Файлы.строки(Путь к пути) , который считывает все строки из файла в виде потока.
  • Files.find () , который возвращает поток, лениво заполненный путем поиска файлов в файловом дереве, коренящемся в данном начальном файле.
  • BufferedReader.lines () , которые возвращают поток, элементами которого являются строки, считываемые из этого BufferedReader.

Различные улучшения Java 8 Core API

Некоторые другие улучшения API, которые могут пригодиться, включают:

  1. ThreadLocal статический метод с начальным(Поставщик-поставщик) для простого создания экземпляров.
  2. Интерфейс компаратора был расширен множеством стандартных и статических методов для естественного упорядочения, обратного порядка и т.д.
  3. методы min(), max() и sum() в классах целочисленных, длинных и двойных оболочек.
  4. логические И(), логические() и логические методы Xor() в логическом классе.
  5. Zip – файл .stream() метод для получения упорядоченного потока по записям ZIP-файла. Записи отображаются в потоке в том порядке, в каком они отображаются в центральном каталоге ZIP-файла.
  6. Несколько полезных методов в математическом классе.
  7. добавлена команда jjs для вызова движка Nashorn.
  8. добавлена команда jdeps для анализа файлов классов
  9. Мост JDBC-ODBC был удален.
  10. Пространство памяти PermGen было удалено

Это все для функций Java 8 с примерами программ. Если я пропустил некоторые важные функции Java 8, пожалуйста, дайте мне знать в комментариях.