В Java 8 оператор двойного двоеточия (::) называется ссылками на методы. Обратитесь к следующим примерам:
Анонимный класс для печати списка.
Listlist = Arrays.asList("node", "java", "python", "ruby"); list.forEach(new Consumer () { // anonymous class @Override public void accept(String str) { System.out.println(str); } });
Анонимный класс -> Лямбда-выражения.
Listlist = Arrays.asList("node", "java", "python", "ruby"); list.forEach(str -> System.out.println(str)); // lambda
Лямбда-выражения -> Ссылки на методы.
Listlist = Arrays.asList("node", "java", "python", "ruby"); list.forEach(System.out::println); // method references
Анонимный класс -> Лямбда-выражение -> Ссылка на метод
Примечание Как лямбда-выражение, так и ссылка на метод не делают ничего, кроме другого способа вызова существующего метода. С помощью ссылки на метод он становится более читабельным.
Существует четыре вида ссылок на методы:
- Ссылка на статический метод
имя_класса::имя_статического метода
- Ссылка на метод экземпляра конкретного объекта
Объект::имя метода экземпляра
- Ссылка на метод экземпляра произвольного объекта определенного типа
Содержащий тип::Имя метода
– - Ссылка на конструктор
Имя класса::новый
1. Статический метод
Лямбда-выражение.
(args) -> ClassName.staticMethodName(args)
Ссылка на метод.
ClassName::staticMethodName
1.1 В этом примере выводится список строк, ссылка метода на статический метод Простой принтер::печать
.
package com.mkyong; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; public class Java8MethodReference1a { public static void main(String[] args) { Listlist = Arrays.asList("A", "B", "C"); // anonymous class list.forEach(new Consumer () { @Override public void accept(String x) { SimplePrinter.print(x); } }); // lambda expression list.forEach(x -> SimplePrinter.print(x)); // method reference list.forEach(SimplePrinter::print); } } class SimplePrinter { public static void print(String str) { System.out.println(str); } }
1.2 В этом примере список строк преобразуется в список целых чисел, ссылка на метод статического метода Integer::parseInt
.
public static int parseInt(String s) throws NumberFormatException { return parseInt(s,10); }
package com.mkyong; import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; public class Java8MethodReference1b { public static void main(String[] args) { Listlist = Arrays.asList("1", "2", "3"); // anonymous class List collect1 = list.stream() .map(new Function () { @Override public Integer apply(String s) { return Integer.parseInt(s); } }) .collect(Collectors.toList()); // lambda expression List collect2 = list.stream() .map(s -> Integer.parseInt(s)) .collect(Collectors.toList()); // method reference List collect3 = list.stream() .map(Integer::parseInt) .collect(Collectors.toList()); } }
1.3 Этот пример объединяет два Целое число
и возвращает Строка
. Он передает статический метод ссылки на метод IntegerUtils::присоединяется
в качестве аргумента к другому методу, который принимает бифункцию
.
package com.mkyong; import java.util.function.BiFunction; public class Java8MethodReference1c { public static void main(String[] args) { // anonymous class String result1 = playTwoArgument(1, 2, new BiFunction() { @Override public String apply(Integer a, Integer b) { return IntegerUtils.join(a, b); } }); // 3 // lambda String result1 = playTwoArgument(1, 2, (a, b) -> IntegerUtils.join(a, b)); // 3 // method reference String result2 = playTwoArgument(1, 2, IntegerUtils::join); // 3 } private static R playTwoArgument(Integer i1, Integer i2, BiFunction func) { return func.apply(i1, i2); } } class IntegerUtils{ public static String join(Integer a, Integer b) { return String.valueOf(a + b); } }
2. Ссылка на метод экземпляра определенного объекта
Лямбда-выражение.
(args) -> object.instanceMethodName(args)
Ссылка на метод.
object::instanceMethodName
2.1 В этом примере сортируется список Сотрудников
по зарплате. Мы можем ссылаться на метод экземпляра сравните мою зарплату
конкретного объекта Поставщик компаратора
.
package com.mkyong; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; public class Java8MethodReference2 { public static void main(String[] args) { Listlist = Arrays.asList( new Employee("mkyong", 38, BigDecimal.valueOf(3800)), new Employee("zilap", 5, BigDecimal.valueOf(100)), new Employee("ali", 25, BigDecimal.valueOf(2500)), new Employee("unknown", 99, BigDecimal.valueOf(9999))); // anonymous class /*list.sort(new Comparator () { @Override public int compare(Employee o1, Employee o2) { return provider.compareBySalary(o1, o2); } });*/ ComparatorProvider provider = new ComparatorProvider(); // lambda // list.sort((o1, o2) -> provider.compareBySalary(o1, o2)); // method reference list.sort(provider::compareBySalary); list.forEach(x -> System.out.println(x)); } } class ComparatorProvider { public int compareByAge(Employee o1, Employee o2) { return o1.getAge().compareTo(o2.getAge()); } public int compareByName(Employee o1, Employee o2) { return o1.getName().compareTo(o2.getName()); } public int compareBySalary(Employee o1, Employee o2) { return o1.getAge().compareTo(o2.getAge()); } }
package com.mkyong; import java.math.BigDecimal; public class Employee { String name; Integer age; BigDecimal salary; // generated by IDE, getters, setters, constructor, toString }
Выход
Employee{name='zilap', age=5, salary=100} Employee{name='ali', age=25, salary=2500} Employee{name='mkyong', age=38, salary=3800} Employee{name='unknown', age=99, salary=9999}
3. Ссылка на метод экземпляра произвольного объекта определенного типа.
Утверждение немного запутанное, нуждается в небольшом объяснении, см. Примеры ниже:
Лямбда-выражение.
// arg0 is the first argument (arg0, rest_of_args) -> arg0.methodName(rest_of_args) // example, assume a and b are String (a, b) -> a.compareToIgnoreCase(b)
Ссылка на метод.
// first argument type arg0_Type::methodName // arg0 is type of ClassName ClassName::methodName // example, a is type of String String::compareToIgnoreCase
Для (Строка a, Строка b)
, где а
и b
– произвольные имена, а Строка
– ее произвольный тип. В этом примере используется ссылка на метод экземпляра метода Сравнение/| произвольного объекта
a (первый аргумент) определенного типа
Строка .
3.1 Ознакомьтесь с официальным примером в этом Ссылки на методы
String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" }; Arrays.sort(stringArray, String::compareToIgnoreCase);
Мы передали ссылку на метод Строка::compareToIgnoreCase
в качестве компаратора для Массивов.сортировка
.
объяснение Просмотрите сигнатуру метода Arrays.sort
:
public staticvoid sort(T[] a, Comparator super T> c) { }
В приведенном выше примере Массивы.сортировка
ожидает Компаратор<Строка>
. Компаратор
является функциональным интерфейсом, его абстрактный метод сравнивает
соответствует Бифункция<Строка, строка, целое число>
, она принимает два аргумента String
и возвращает int
.
@FunctionalInterface public interface Comparator{ int compare(T o1, T o2); // this matches BiFunction }
Просмотрите сигнатуру метода Bi-функции
:
@FunctionalInterface public interface BiFunction{ R apply(T t, U u); }
Дальнейшее чтение – Примеры бифункций Java 8
Приведенный ниже лямбда-код обеспечивает реализацию бифункции<Строка, строка, целое число>
, поэтому Arrays.sort
принимает приведенное ниже лямбда-выражение в качестве допустимого синтаксиса.
(String a, String b) -> a.compareToIgnoreCase(b) // return int // a is type of String // method reference String::compareToIgnoreCase
3.2 Давайте рассмотрим другой пример.
package com.mkyong; import java.util.function.BiPredicate; import java.util.function.Function; public class Java8MethodReference3a { public static void main(String[] args) { // lambda int result = playOneArgument("mkyong", x -> x.length()); // 6 // method reference int result2 = playOneArgument("mkyong", String::length); // 6 // lambda Boolean result3 = playTwoArgument("mkyong", "y", (a, b) -> a.contains(b)); // true // method reference Boolean result4 = playTwoArgument("mkyong", "y", String::contains); // true // lambda Boolean result5 = playTwoArgument("mkyong", "1", (a, b) -> a.startsWith(b)); // false // method reference Boolean result6 = playTwoArgument("mkyong", "y", String::startsWith); // false System.out.println(result6); } staticR playOneArgument(String s1, Function func) { return func.apply(s1); } static Boolean playTwoArgument(String s1, String s2, BiPredicate func) { return func.test(s1, s2); } }
3.3 Давайте рассмотрим другой пример, пользовательский объект.
package com.mkyong; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.function.BiFunction; public class Java8MethodReference3b { public static void main(String[] args) { Invoice obj = new Invoice("A001", BigDecimal.valueOf(1.99), 3); InvoiceCalculator formula = new InvoiceCalculator(); // lambda BigDecimal result = calculate(formula, obj, (f, o) -> f.normal(o)); // 5.97 // method reference BigDecimal result2 = calculate(formula, obj, InvoiceCalculator::normal); // 5.97 // lambda BigDecimal result3 = calculate(formula, obj, (f, o) -> f.promotion(o)); // 5.37 // method reference BigDecimal result4 = calculate(formula, obj, InvoiceCalculator::promotion); // 5.37 } static BigDecimal calculate(InvoiceCalculator formula, Invoice s1, BiFunctionfunc) { return func.apply(formula, s1); } } class InvoiceCalculator { public BigDecimal normal(Invoice obj) { return obj.getUnitPrice().multiply(BigDecimal.valueOf(obj.qty)); } public BigDecimal promotion(Invoice obj) { return obj.getUnitPrice() .multiply(BigDecimal.valueOf(obj.qty)) .multiply(BigDecimal.valueOf(0.9)) .setScale(2, RoundingMode.HALF_UP); } } class Invoice { String no; BigDecimal unitPrice; Integer qty; // generated by IDE, setters, gettes, constructor, toString }
Первый аргумент – это тип Калькулятор счетов-фактур
. Таким образом, мы можем ссылаться на метод экземпляра ( обычный или продвижение
) произвольного объекта ( f
) определенного типа Калькулятор счетов-фактур
.
(f, o) -> f.normal(o)) (f, o) -> f.promotion(o)) InvoiceCalculator::normal InvoiceCalculator::promotion
Понял? Больше никаких примеров 🙂
4. Ссылка на конструктор.
Лямбда-выражение.
(args) -> new ClassName(args)
Ссылка на метод.
ClassName::new
4.1 Ссылка на конструктор по умолчанию.
package com.mkyong; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; public class Java8MethodReference4a { public static void main(String[] args) { // lambda Supplier
4.2 Ссылка на конструктор, который принимает аргумент – Счет-фактура (большая десятичная цена единицы измерения)
package com.mkyong; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Function; public class Java8MethodReference4b { public static void main(String[] args) { Listlist = Arrays.asList( BigDecimal.valueOf(9.99), BigDecimal.valueOf(2.99), BigDecimal.valueOf(8.99)); // lambda // List invoices = fakeInvoice(list, (price) -> new Invoice(price)); // method reference List invoices = fakeInvoice(list, Invoice::new); invoices.forEach(System.out::println); } static List fakeInvoice(List list, Function func) { List result = new ArrayList<>(); for (BigDecimal amount : list) { result.add(func.apply(amount)); } return result; } } class Invoice { String no; BigDecimal unitPrice; Integer qty; public Invoice(BigDecimal unitPrice) { this.unitPrice = unitPrice; } //... generated by IDE }
Выход
Invoice{no='null', unitPrice=9.99, qty=null} Invoice{no='null', unitPrice=2.99, qty=null} Invoice{no='null', unitPrice=8.99, qty=null}
Сделано.
Рекомендации
- Ссылка на метод Java 8: Как его использовать
- Понимание Ссылок на Методы Java 8
- Перевод Лямбда-выражений
- Учебные пособия по Java – Ссылки на методы
- Java 8 Учебные пособия
- Примеры функций Java 8
- Примеры функций Java 8 Bi
- Примеры предикатов Java 8
- Примеры предикатов Java 8
- Примеры поставщиков Java 8
Оригинал: “https://mkyong.com/java8/java-8-method-references-double-colon-operator/”