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

Ссылки на методы Java 8, оператор с двойным двоеточием (::)

– Ссылки на методы Java 8, оператор с двойным двоеточием (::)

В Java 8 оператор двойного двоеточия (::) называется ссылками на методы. Обратитесь к следующим примерам:

Анонимный класс для печати списка.

List list = Arrays.asList("node", "java", "python", "ruby");
list.forEach(new Consumer() {       // anonymous class
    @Override
    public void accept(String str) {
        System.out.println(str);
    }
});

Анонимный класс -> Лямбда-выражения.

List list = Arrays.asList("node", "java", "python", "ruby");
list.forEach(str -> System.out.println(str)); // lambda

Лямбда-выражения -> Ссылки на методы.

List list = 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) {

        List list = 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) {

        List list = 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) {

        List list = 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 static  void sort(T[] a, Comparator 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);
    }

    static  R 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,
                                BiFunction func) {
        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 obj1 = () -> new HashMap();   // default HashMap() constructor
        Map map1 = obj1.get();

        // method reference
        Supplier obj2 = HashMap::new;
        Map map2 = obj2.get();

        // lambda
        Supplier obj3 = () -> new Invoice(); // default Invoice() constructor
        Invoice invoice1 = obj3.get();

        // method reference
        Supplier obj4 = Invoice::new;
        Invoice invoice2 = obj4.get();

    }

}

class Invoice {

    String no;
    BigDecimal unitPrice;
    Integer qty;

    public Invoice() {
    }

    //... generated by IDE
}

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) {

        List list = 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}

Сделано.

Рекомендации

Оригинал: “https://mkyong.com/java8/java-8-method-references-double-colon-operator/”