Стратегия таможенного оформления Java8

Java
Стратегия таможенного оформления Java8

Нравится + Избранное, чтобы узнать серию, статьи включены в GitHubJavaEgg, N-линия Интернет-разработка основных навыков спектра оружия

Java8 была выпущена еще в марте 2014 года, 6 лет, у вас есть полное представление о ней?

Эта статья переписана на моем плохом английском и безбожном копировании и копировании.Я не копался в исходниках.Я просто имею общее представление о Java8,которым можно пользоваться.Пример кода тоже есть на github.

Что нового в JDK 8

  • Язык программирования Java

    • Лямбда-выражения: новая языковая функция, позволяющая рассматривать функции как параметры метода или код как данные.
    • ссылка на метод: Ссылки на методы содержат легко читаемые лямбда-выражения для уже названных методов.
    • метод по умолчанию: используйте ключевое слово по умолчанию, чтобы определить методы по умолчанию (методы с реализацией) для интерфейсов.
    • Дублировать аннотацииПредоставляет возможность применять одну и ту же аннотацию несколько раз к одному и тому же объявлению или использованию типа.
    • введите аннотациюПредоставляет возможность применять аннотации везде, где используется тип, а не только в объявлениях.
    • Улучшенная Java8вывод типа
    • Отражение параметра метода
    • java.util.function: Новый пакет, который содержит ссылки на выражения и методы лямбда, чтобы обеспечить общую интерфейсную функцию целевого типа
  • Коллекции

    • java.util.streamдобавлено в пакетStream API, для поддержки функциональных операций над потоками элементов
    • Улучшена ключевая проблема конфликтаHashMap
  • Компактные профили

  • Безопасность

  • JavaFX

  • Инструменты (в том числе некоторые вызовы движка Nashorn, запуск приложений JavaFX и т. д.)

  • Интернационализация

    • Усовершенствования Unicode, включая поддержку Unicode 6.2.0.
    • Предоставляет новые API календаря и локали.
  • Развертывание

  • пакет даты и времени (Date-Time Package): обеспечивает более полное управление временем и датой

  • Сценарии: Java 8 предоставляет новый движок javascript Nashorn (заменяющий движок javascript Nashorn), который позволяет нам запускать определенные приложения javascript на JVM.

  • Улучшить ввод-вывод и NIO

  • Улучшатьjava.langиjava.util

    • Поддерживает параллельную сортировку массивов
    • Поддержка кодирования и декодирования Base64
    • Поддержка неподписанных операций
    • Необязательный класс: сводит к минимуму исключения нулевого указателя
  • JDBC

    • Мост JDBC-ODBC удален.
    • JDBC 4.2 представляет новые функции
  • Java DB (база данных Java)

  • Сеть

    • недавно добавленныйjava.net.URLPermission
  • одновременно (Concurrency)

    • CompletableFutureулучшенный предыдущийFuture
    • java.util.concurrent.ConcurrentHashMapПоддержка операций агрегирования на основе недавно добавленных функций потоков и лямбда-выражений.
    • java.util.concurrent.atomicПредоставляет набор классов атомарных переменных, классов инструментов, которые поддерживают неблокирующие, потокобезопасные операции для одной переменной.
    • java.util.concurrent.ForkJoinPoolИспользуется для дополнения ExecutorService
    • java.util.concurrent.locks.StampedLockПредоставляет функциональные блокировки с тремя режимами управления доступом для чтения/записи.
  • JVM: PermGen удален, заменен Metaspace

Java8 особенно эффективен в лямбда-выражениях и потоках, благодаря которым было добавлено и улучшено множество пакетов.

Добавлен:java.lang.invoke,java.util.function,java.util.stream

Исправлять:

modify-class.png


1. Лямбда-выражения

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

  • Анонимные - Анонимные функции (т.е. функции без имени функции), в отличие от обычных методов, имеющих явное имя, "пишите меньше, думайте больше"
  • Функции. Лямбда-функции не принадлежат к определенному классу, подобно методам, но имеют список параметров, тело функции и тип возвращаемого значения.
  • Передача — лямбда-выражения могут передаваться в качестве параметров методам или храниться в переменных.
  • Краткость — не нужно писать много шаблонного кода, такого как анонимные классы.

Лямбда-выражения позволяют инкапсулировать одну единицу поведения и передать ее другому коду. Если вы хотите выполнить действие над каждым элементом коллекции, когда процесс завершается или когда процесс сталкивается с ошибкой, вы можете использовать лямбда-выражение.

1. Зачем использовать лямбда-выражения

Lambda — это анонимная функция, мы можем понимать лямбда-выражение как фрагмент кода, который можно передать (Передайте код как данные——Поведенческая параметризация). Вы можете писать более чистый и гибкий код. Как более компактный стиль кода, возможности языковых выражений Java были улучшены.

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

hello-lambda

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

(parameters) -> expressionили(parameters) ->{ statements; }

Лямбда-выражения вводят новый элемент синтаксиса и оператор в языке Java. Этот оператор"->", оператор называетсяЛямбда-операторили оператор порезки головы. Он делит лямбду на две части:

  • Слева: указаны все параметры, необходимые для лямбда-выражения.

  • Справа: указывает тело лямбда, которое является функцией, выполняемой лямбда-выражением.

например (демонстрация ошибки):

(Integer i) -> return "hello"+i;   //错误的Lambda,return是一个控制流语句,需要{}
(String s) -> {"hello";}    //“hello”是一个表达式,不是语句,不需要{},可以写成{return “hello”;}

например (правильная демонстрация):

  1. Нет параметров, нет возвращаемого значения, телу Lambda нужен только один оператор

    Runnable runnable = () -> System.out.println("hello lambda");
    
  2. Лямбда требует параметр

    Consumer<String> consumer = (args) -> System.out.println(args);
    

    Когда Lambda нужен только один параметр, круглые скобки параметра можно опустить.

    Consumer<String> consumer = args -> System.out.println(args);
    
  3. Lambda принимает два параметра и имеет возвращаемое значение

    BinaryOperator<Long> binaryOperator = (Long x,Long y) -> {
    	System.out.println("实现函数接口方法");
    	return x +y;
    };
    

    Тип данных параметра можно опустить, что улучшено в Java 8.вывод типа, а когда тело Lambda содержит только один оператор, return и фигурные скобки можно опустить.

    BinaryOperator<Long> binaryOperator = (x, y) -> x + y;
    

вывод типа

Все типы параметров в приведенных выше лямбда-выражениях выводятся компилятором. Программа по-прежнему может быть скомпилирована без указания типа в лямбда-выражении, потому что javac определяет тип параметра в фоновом режиме на основе контекста программы. Тип лямбда-выражения зависит от контекста и определяется компилятором. Это называется "вывод типа". Представлено в Java7алмазный оператор(<>), заключается в использовании дженериков для вывода типа из контекста.

List<String> list = new ArrayList<>();

3. Пример лямбда-выражения

Пример, предоставленный официальным лицом, предполагает, что вы хотите разработать социальное программное обеспечение, PM, которого нужно ударить, меняется каждый день.Сегодня вам нужно запросить информацию о взрослых пользователях, завтра вам нужно запросить информацию о пользователе для взрослых женщины, а послезавтра нужно искать разные странности.Условный запрос.

Программист в это время: От простого метода сравнения обхода пользователя до общего метода поиска, заводской режим использовался позже.Когда 7-й день, ты был нетерпелив, Мэдд, каждое условие - одно предложение, я написал 7 классов, которые я не не хочу делатьCtrlCV工程师, то лямбда-выражение — ваш лучший выбор.

Поведенческая параметризацияЭто шаблон разработки программного обеспечения, который помогает вам справляться с часто меняющимися требованиями.

В официально предоставленной демонстрации шаг за шагом рассказывается о преимуществах использования Java8 (от параметризации значений до параметризации поведения).код

import java.util.List;
import java.util.ArrayList;
import java.time.chrono.IsoChronology;
import java.time.LocalDate;
public class Person {
    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    Person(String nameArg, LocalDate birthdayArg,
           Sex genderArg, String emailArg) {
        name = nameArg;
        birthday = birthdayArg;
        gender = genderArg;
        emailAddress = emailArg;
    }

    public int getAge() {
        return birthday
                .until(IsoChronology.INSTANCE.dateNow())
                .getYears();
    }

    public void printPerson() {
        System.out.println(name + ", " + this.getAge());
    }

    public Sex getGender() {
        return gender;
    }

    public String getName() {
        return name;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public LocalDate getBirthday() {
        return birthday;
    }

    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }

    public static List<Person> createRoster() {
        List<Person> roster = new ArrayList<>();
        roster.add(new Person(
                        "Fred",
                        IsoChronology.INSTANCE.date(1980, 6, 20),
                        Person.Sex.MALE,
                        "fred@example.com"));
        roster.add(new Person(
                        "Jane",
                        IsoChronology.INSTANCE.date(1990, 7, 15),
                        Person.Sex.FEMALE, "jane@example.com"));
        roster.add(new Person(
                        "George",
                        IsoChronology.INSTANCE.date(1991, 8, 13),
                        Person.Sex.MALE, "george@example.com"));
        roster.add(new Person(
                        "Bob",
                        IsoChronology.INSTANCE.date(2000, 9, 12),
                        Person.Sex.MALE, "bob@example.com"));
        return roster;
    }
}

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

public class RosterTest {
    interface CheckPerson {
        boolean test(Person p);
    }

    /**
     * 1. eg:输出年龄大于20岁的成员
     *   匹配符合某一特征的成员的方法
     *   如果老板要年龄在某一区间的成员呢?接着换方法
     */
    public static void printPersonsOlderThan(List<Person> roster, int age) {
        for (Person p : roster) {
            if (p.getAge() >= age) {
                p.printPerson();
            }
        }
    }

    /**
     * 2. eg:输出年龄在14到30岁之间的成员
     * 		更全面的匹配方法
     * 		如果老板只要男性成员呢?
     */
    public static void printPersonsWithinAgeRange(
            List<Person> roster, int low, int high) {
        for (Person p : roster) {
            if (low <= p.getAge() && p.getAge() < high) {
                p.printPerson();
            }
        }
    }

    /**
     * 3. eg:老板又提出了各种复杂的需求,不要处女座的、只要邮箱是163的,怎么搞?
     * 方法1:在本地类中指定搜索条件代码,通过接口方式,不同的需求对应不同的实现类,
     *		 每次都要新建实现类,写大量的代码
     * 方法2:在匿名类中指定搜索条件代码,不需要写各种实现,但是还要写个interface CheckPerson,
     *       而且匿名类写起来也挺麻烦
     * 方法3:Lambda表达式是懒人的不二之选,CheckPerson是一个只包含一个抽象方法的接口,
     *	     比较简单,Lambda可以省略其实现
     */
    public static void printPersons(
            List<Person> roster, CheckPerson tester) {
        for (Person p : roster) {
            if (tester.test(p)) {
                p.printPerson();
            }
        }
    }

    /**
     * 4. eg: 搞这么久,还得写一个接口,而且是只有一个抽象方法,还是不爽?
     * 			你也可以使用标准的函数接口来代替接口CheckPerson,从而进一步减少所需的代码量
     * 			java.util.function包中定义了标准的函数接口
     * 			我们可以使用JDK8提供的 Predicate<T>接口来代替CheckPerson。
     *			该接口包含方法boolean test(T t)
     */
    public static void printPersonsWithPredicate(
            List<Person> roster, Predicate<Person> tester) {
        for (Person p : roster) {
            if (tester.test(p)) {
                p.printPerson();
            }
        }
    }

    /**
     * 5. Lambda表达式可不只是能够简化匿名类
     * 		简化 p.printPerson(), 
     * 		使用Consumer<T>接口的void accept(T t)方法,相当于入参的操作
     */
    public static void processPersons(
            List<Person> roster,
            Predicate<Person> tester,
            Consumer<Person> block) {
        for (Person p : roster) {
            if (tester.test(p)) {
                block.accept(p);
            }
        }
    }

    /**
     * 6. eg: 老板说了只想看到邮箱
     * Function<T,R>接口,相当于输入类型,mapper定义参数,block负责方对给定的参数进行执行
     */
    public static void processPersonsWithFunction(
            List<Person> roster,
            Predicate<Person> tester,
            Function<Person, String> mapper,
            Consumer<String> block) {
        for (Person p : roster) {
            if (tester.test(p)) {
                String data = mapper.apply(p);
                block.accept(data);
            }
        }
    }

    // 7. 使用泛型
    public static <X, Y> void processElements(
            Iterable<X> source,
            Predicate<X> tester,
            Function<X, Y> mapper,
            Consumer<Y> block) {
        for (X p : source) {
            if (tester.test(p)) {
                Y data = mapper.apply(p);
                block.accept(data);
            }
        }
    }

    public static void main(String[] args) {
        List<Person> roster = Person.createRoster();

        /**
         * 1. 输出年龄大于20岁的成员
         */
        System.out.println("Persons older than 20:");
        printPersonsOlderThan(roster, 20);
        System.out.println();

        /**
         * 2. 输出年龄在14到30岁之间的成员
         */
        System.out.println("Persons between the ages of 14 and 30:");
        printPersonsWithinAgeRange(roster, 14, 30);
        System.out.println();

        /**
         * 3. 输出年龄在18到25岁的男性成员
         * (在本地类中指定搜索条件)
         *   您可以使用一个匿名类而不是一个本地类,并且不必为每个搜索声明一个新类
         */
        System.out.println("Persons who are eligible for Selective Service:");
        class CheckPersonEligibleForSelectiveService implements CheckPerson {
            public boolean test(Person p) {
                return p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25;
            }
        }

        // 这个其实就是通过行为参数化传递代码
        printPersons(
                roster, new CheckPersonEligibleForSelectiveService());

        System.out.println();

        // 3. 在匿名类中指定搜索条件代码
        System.out.println("Persons who are eligible for Selective Service " +
                "(anonymous class):");
        printPersons(
                roster,
                new CheckPerson() {
                    public boolean test(Person p) {
                        return p.getGender() == Person.Sex.MALE
                                && p.getAge() >= 18
                                && p.getAge() <= 25;
                    }
                }
        );

        System.out.println();

        // 3: 使用Lambda表达式简化代码,一个箭头
        System.out.println("Persons who are eligible for Selective Service " +
                "(lambda expression):");

        printPersons(
                roster,
                (Person p) -> p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25
        );

        System.out.println();

        // 4. 使用Lambda的标准功能接口
        System.out.println("Persons who are eligible for Selective Service " +
                "(with Predicate parameter):");

        printPersonsWithPredicate(
                roster,
                p -> p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25
        );

        System.out.println();

        //5.使用Predicate和Consumer参数
        System.out.println("5. Persons who are eligible for Selective Service " +
                "(with Predicate and Consumer parameters):");

        processPersons(
                roster,
                p -> p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25,
                p -> p.printPerson()
        );

        System.out.println();

        // 6. 通过Function<T,R> 指定输出类型
        System.out.println("Persons who are eligible for Selective Service " +
                "(with Predicate, Function, and Consumer parameters):");

        processPersonsWithFunction(
                roster,
                p -> p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25,
                p -> p.getEmailAddress(),
                email -> System.out.println(email)
        );

        System.out.println();

        // 7. 使用泛型
        System.out.println("Persons who are eligible for Selective Service " +
                "(generic version):");

        processElements(
                roster,
                p -> p.getGender() == Person.Sex.MALE
                        && p.getAge() >= 18
                        && p.getAge() <= 25,
                p -> p.getEmailAddress(),
                email -> System.out.println(email)
        );

        System.out.println();

        // 8: 使用接受Lambda表达式的批量数据操作
        System.out.println("Persons who are eligible for Selective Service " +
                "(with bulk data operations):");

        roster.stream()
                .filter(
                        p -> p.getGender() == Person.Sex.MALE
                                && p.getAge() >= 18
                                && p.getAge() <= 25)
                .map(p -> p.getEmailAddress())
                .forEach(email -> System.out.println(email));
        System.out.println();

        /**
         *  9. 按年龄排序。Java 8 之前需要实现 Comparator 接口
         *  接口比较器是一个功能接口。因此,
         *  可以使用lambda表达式来代替定义并创建一个实现了Comparator的类的新实例:
         */
        Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);

        Arrays.sort(rosterAsArray,
                (a, b) -> Person.compareByAge(a, b)
        );

        for (Person person : roster) {
            person.printPerson();
        }

        /**
         *  这种比较两个Person实例的出生日期的方法已经作为Person. 
         *	comparebyage存在。你可以在lambda表达式中调用这个方法
         */

        Arrays.sort(rosterAsArray,
                (a, b) -> Person.compareByAge(a, b)
        );
}

2. Функциональный интерфейс

1. Что такое функциональный интерфейс

  • Интерфейс, который содержит только один абстрактный метод, называется функциональным интерфейсом, а абстрактный метод также называется функциональным методом. Известные Comparator, Runnable и Callable относятся к функциональным интерфейсам.
  • Такой интерфейс настолько прост, что его не стоит определять в программе, поэтому JDK8java.util.functionНесколько стандартных функциональных интерфейсов определены в , которые мы можем использовать.Package java.util.function
  • Объекты этого интерфейса можно создавать с помощью лямбда-выражений. (Если лямбда-выражение выдает проверенное исключение, это исключение необходимо объявить в абстрактном методе целевого интерфейса).
  • Мы можем использовать на любом функциональном интерфейсе@FunctionalInterfaceаннотация, это проверит, является ли это функциональным интерфейсом, и javadoc также будет содержать объявление о том, что интерфейс является функциональным интерфейсом.

2. Пользовательский функциональный интерфейс

@FunctionalInterface    //@FunctionalInterface标注该接口会被设计成一个函数式接口,否则会编译错误
public interface MyFunc<T> {
    T getValue(T t);
}
public static String toUpperString(MyFunc<String> myFunc, String str) {
    return myFunc.getValue(str);
}

public static void main(String[] args) {
    String newStr = toUpperString((str) -> str.toUpperCase(), "abc");
    System.out.println(newStr);
}

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

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

3. Java имеет четыре встроенных основных функциональных интерфейса.

функциональный интерфейс Тип параметра возвращаемый тип использовать
Consumer<T> T void Применить операцию к объекту типа T, содержащему метод: void accept(T t)
Supplier<T> никто T Возвращает объект типа T, содержащий метод: T get();
Function<T,R> T R Применяет операцию к объекту типа T и возвращает результат. Результатом является объект типа R. Включить метод: R apply(T t);
Predicate<T> T boolean Определяет, удовлетворяет ли объект типа T ограничению, и возвращает логическое значение. Содержит булев метод test(T t);
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/*
 * Java8 内置的四大核心函数式接口
 * Consumer<T> : 消费型接口  void accept(T t);
 * Supplier<T> : 供给型接口   T get();
 * Function<T, R> : 函数型接口  R apply(T t);
 * Predicate<T> : 断言型接口   boolean test(T t);
 */
public class FunctionalInterfaceTest {

    //Predicate<T> 断言型接口:将满足条件的字符串放入集合
    public List<String> filterStr(List<String> list, Predicate<String> predicate) {
        List<String> newList = new ArrayList<>();
        for (String s : list) {
            if (predicate.test(s)) {
                newList.add(s);
            }
        }
        return newList;
    }

    @Test
    public void testPredicate() {
        List<String> list = Arrays.asList("hello", "java8", "function", "predicate");
        List<String> newList = filterStr(list, s -> s.length() > 5);
        for (String s : newList) {
            System.out.println(s);
        }
    }

    // Function<T, R> 函数型接口:处理字符串
    public String strHandler(String str, Function<String, String> function) {
        return function.apply(str);
    }

    @Test
    public void testFunction() {
        String str1 = strHandler("测试内置函数式接口", s -> s.substring(2));
        System.out.println(str1);

        String str2 = strHandler("abcdefg", s -> s.toUpperCase());
        System.out.println(str2);
    }

    //Supplier<T> 供给型接口 :产生指定个数的整数,并放入集合
    public List<Integer> getNumList(int num, Supplier<Integer> supplier) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            Integer n = supplier.get();
            list.add(n);
        }
        return list;
    }

    @Test
    public void testSupplier() {
        List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));

        for (Integer num : numList) {
            System.out.println(num);
        }
    }

    //Consumer<T> 消费型接口 :修改参数
    public void modifyValue(Integer value, Consumer<Integer> consumer) {
        consumer.accept(value);
    }

    @Test
    public void testConsumer() {
        modifyValue(3, s -> System.out.println(s * 3));
    }
}

Package java.util.functionЕсть много других методов эволюции, доступных в пакете.

java8-function.png

?> Tip

Типы Java являются либо ссылочными типами (Byte, Integer, Object, List), либо примитивными типами (int, double, byte, char). Но дженерики могут привязываться только к ссылочным типам. Преобразуйте примитивный тип в соответствующий ссылочный тип, называемыйкоробка, вместо этого преобразуйте ссылочный тип в соответствующий примитивный тип, называемыйРаспаковка. Конечно, Java предоставляет механизм автоупаковки, помогающий нам выполнять эту операцию.

List<Integer> list = new ArrayList();
	for (int i = 0; i < 10; i++) {
	list.add(i);    //int被装箱为Integer
}

Но за это приходится платить с точки зрения производительности. Упакованное значение, по сути, оборачивает примитивный тип и сохраняет его в куче. Таким образом, упакованное значение требует больше памяти и дополнительного поиска в памяти, чтобы получить упакованное исходное значение.

из вышеуказанного пакета функцийIntPredicate, DoubleConsumer, LongBinaryOperator, ToDoubleFuncation и т. д. — это операции, которые позволяют избежать автоматической упаковки.. Как правило, имя функционального интерфейса для определенного типа входного параметра имеет префикс соответствующего типа примитива.


3. Ссылка на метод

  • Ссылка на метод относится к методу, который ссылается на метод по его имени.

  • Когда операция, которая должна быть передана в тело Lambda, уже имеет реализованный метод, вы можете использовать ссылку на метод (список параметров абстрактного метода должен соответствовать списку параметров метода ссылки на метод!)

  • Ссылки на методы используются только для поддержки сокращения Lambda (можно понять, что ссылки на методы — это еще одна форма лямбда-выражения, сокращение записи)

использовать::оператор будетимя методаиобъект или классимя отделено

1. eg

BinaryOperator<Double> binaryOperator = (x,y)->Math.pow(x,y);
//等价于
BinaryOperator<Double> binaryOperator1 = Math::pow;

2. Типы ссылок на методы

Java 8 предоставляет 4 ссылки на методы

Kind Example
ссылка на статический метод ContainingClass::staticMethodName
ссылка на метод экземпляра конкретного объекта containingObject::instanceMethodName
ссылка на метод экземпляра произвольного объекта определенного типа ContainingType::methodName
Ссылка на конструктор ClassName::new

1. Ссылки на статические методы

//比较年龄的方法在Person.compareByAge的已经存在,所以可以使用方法引用
Arrays.sort(rosterAsArray, Person::compareByAge);
//---------------------
@Test
public void test3(){
    BiFunction<Double,Double,Double> bif = (x,y)->Math.max(x,y);
    System.out.println(bif.apply(22.1,23.2));

    System.out.println("===等价于===");

    BiFunction<Double,Double,Double> bif1 = Math::max;
    System.out.println(bif1.apply(22.1,23.2));
}

@Test
public void test4(){
    Comparator<Integer> com = (x, y)->Integer.compare(x,y);
    System.out.println(com.compare(1,2));

    System.out.println("===等价于===");
    Comparator<Integer> com1 = Integer::compare;
    System.out.println(com1.compare(1,2));
}

2. Метод экземпляра ссылается на определенные объекты

class ComparisonProvider {
    public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }
        
    public int compareByAge(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);
//------------------------
@Test
public void test2() {
    Person person = new Person("Tom", IsoChronology.INSTANCE.date(1995, 6, 20), Person.Sex.MALE, "tom@qq.com");

    Supplier<String> sup = () -> person.getName();
    System.out.println(sup.get());

    System.out.println("===等价于===");

    Supplier<String> sup1 = person::getName;
    System.out.println(sup1.get());
}

3. Ссылка метода экземпляра на произвольный объект определенного типа

String[] stringArray = { "Barbara", "James", "Mary", "John",
    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
//-------------------
@Test
public void test5(){
    BiPredicate<String,String> bp = (x,y)->x.equals(y);
    System.out.println(bp.test("Java情报局","Java情报局1"));
    System.out.println("===等价于===");

    BiPredicate<String,String> bp1 = String::equals;
    System.out.println(bp.test("Java情报局","Java情报局"));
}

4. Ссылка на конструктор

Копирует элементы из одной коллекции в другую.

public static <T, SOURCE extends Collection<T>, DEST extends Collection<T>>
    DEST transferElements(
        SOURCE sourceCollection,
        Supplier<DEST> collectionFactory) {
        
        DEST result = collectionFactory.get();
        for (T t : sourceCollection) {
            result.add(t);
        }
        return result;
}

Поставщик — это функциональный интерфейс, вы можете вызвать метод TransferElements с помощью лямбда-выражения.

Set<Person> rosterSetLambda =
    transferElements(roster, () -> { return new HashSet<>(); });

Используйте ссылки на конструктор вместо лямбда-выражений

Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);
//Java编译器可以推断出要创建包含Person类型元素的HashSet集合,可简写
Set<Person> rosterSet = transferElements(roster, HashSet::new);
Function<Integer,MyClass> fun = (n) -> new MyClass(n);
//等价于
Function<Integer,Person> fun = MyClass::new;
// 带两个参数的构造器引用就要用BiFunction,多个参数的话,还可以自定义一个这样的函数式接口
@Test
public void test6(){
    Supplier<Person> sup = ()->new Person("Tom", IsoChronology.INSTANCE.date(1995, 6, 20), Person.Sex.MALE, "tom@qq.com");
    System.out.println(sup.get());

Ссылки конструктора также могут создавать массивы

@Test
public void test7(){
    Function<Integer,String[]> fun = args -> new String[args];
    String[] strs = fun.apply(6);
    System.out.println(strs.length);
    
    System.out.println("===等价于===");
    
    Function<Integer,String[]> fun1 = String[]::new;
    String[] strs1 = fun1.apply(6);
    System.out.println(strs1.length);
}

4. Поток – функциональная обработка данных

Поток является ключевой абстракцией для работы с коллекциями в Java 8. Он может указывать операцию, которую вы хотите выполнить с коллекцией, и может выполнять очень сложные операции, такие как поиск, фильтрация и сопоставление данных. Использование Stream API для работы с данными коллекции аналогично выполнению запросов к базе данных с использованием SQL. Также можно использовать Stream API для параллельного выполнения операций. короче,Stream API обеспечивает эффективный и простой в использовании способ обработки данных..

1. Что такое поток

Потоки — это каналы данных, которые работают с последовательностями элементов, сгенерированных источниками данных (коллекциями, массивами и т. д.).

"Коллекции — это данные, потоки — это вычисления!"

?>tip

  • Сам поток не хранит элементы

  • Stream не изменяет исходный объект. Вместо этого они возвращают новый поток, содержащий результат

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

Потоковые операции имеют две важные характеристики.

  • Конвейеризация — многие потоковые операции сами возвращают поток, так что несколько операций могут быть объединены в цепочку для формирования большого конвейера.
  • Внутренняя итерация — в отличие от итераторов, которые отображают набор итераций, все потоковые итерации выполняются за кулисами.

2. Три шага работы с потоком

  1. Создать потокИсточник данных (например: коллекция, массив), получить поток
  2. Промежуточная операция(цепочка промежуточных операций, которая обрабатывает данные источника данных для формирования конвейера потока)
  3. Завершить операцию(завершающая операция, выполняющая цепочку промежуточных операций и дающая результат)

2.1. Создать поток

Интерфейс Collection в Java 8 был расширен и теперь предоставляет два метода получения потоков:

  • default Stream<E> stream(): вернуть поток последовательности

  • default Stream<E> parallelStream(): возвращает параллельный поток

создать поток из массива

Статический метод stream() массива в Java8 может получить поток массива:

  • статический поток потока (массив T []): возвращает поток

Перегруженная форма, способная обрабатывать массивы соответствующих примитивных типов:

  • public static IntStream stream(int[] array)

  • public static LongStream stream(long[] array)

  • public static DoubleStream stream(double[] array)

создать поток из значения

Статический метод Stream.of() можно использовать для создания потока путем отображения значений. Он может принимать любое количество аргументов.

  • public static Stream of(T... values): возвращает поток
Создание потоков из функций: создание бесконечных потоков

Бесконечные потоки можно создавать с помощью статических методов Stream.iterate() и Stream.generate().

  • повторять

    • public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
  • генерировать

    • public static<T> Stream<T> generate(Supplier<T> s) :
//创建 Stream
@Test
public void test1(){
  //1. Collection 提供了两个方法  stream() 与 parallelStream()
  List<String> list = new ArrayList<>();
  Stream<String> stream = list.stream(); //获取一个顺序流
  Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

  //2. 通过 Arrays 中的 stream() 获取一个数组流
  Integer[] nums = new Integer[10];
  Stream<Integer> stream1 = Arrays.stream(nums);

  //3. 通过 Stream 类中静态方法 of()
  Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);

  //4. 创建无限流
  //迭代
  Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
  stream3.forEach(System.out::println);

  //生成
  Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
  stream4.forEach(System.out::println);
}

2.2. Промежуточные операции Stream

Несколько промежуточных операций могут быть связаны для формирования конвейера.Если в конвейере не будет запущена операция завершения, промежуточные операции не будут выполнять никакой обработки! И когда операция завершается, она обрабатывается сразу, называется«Ленивая оценка».

2.2.1 Скрининг и нарезка
метод описывать
filter(Predicate p) Получить Lambda, исключающую определенные элементы из потока
distinct() Фильтр для удаления повторяющихся элементов с помощью hashCode() и equals() элементов, сгенерированных потоком
limit(long maxSize) Усекает поток, чтобы он не превышал заданное количество элементов
skip(long n) Пропускает элементы, возвращая поток с отброшенными первыми n элементами. Возвращает пустой поток, если в потоке меньше n элементов. Дополнительно к limit(n)
List<Person> persons = Person.createRoster();

//内部迭代:迭代操作 Stream API 内部完成
@Test
public void test2(){
  //所有的中间操作不会做任何的处理
  Stream<Person> stream = persons.stream()
    .filter((e) -> {
      System.out.println("测试中间操作");
      return e.getAge() <= 35;
    });

  //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
  stream.forEach(System.out::println);
}

//外部迭代
@Test
public void test3(){
  Iterator<Person> it = persons.iterator();

  while(it.hasNext()){
    System.out.println(it.next());
  }
}

@Test
public void test4(){
  persons.stream()
    .filter((p) -> {
      System.out.println("大于25岁的成员:"); // &&  ||
      return (p.getAge()) >= 25;
    }).limit(3)
    .forEach(System.out::println);
}

@Test
public void test5(){
  persons.parallelStream()
    .filter((e) -> e.getAge() >= 20)
    .skip(2)
    .forEach(System.out::println);
}

@Test
public void test6(){
  persons.stream()
    .distinct()
    .forEach(System.out::println);
}
2.2.2 Картирование
метод описывать
map(Function f) Принимает функцию в качестве параметра, функция будет применена к каждому элементу и сопоставлена ​​с новым элементом
mapToDouble(ToDoubleFunction f) Получает функцию в качестве параметра, функция будет применяться к каждому элементу, создавая новый DoubleStream
mapToInt(ToIntFunction f) Получает функцию в качестве параметра, который будет применяться к каждому элементу, создавая новый IntStream.
mapToLong(ToLongFunction f) Получает функцию в качестве параметра, функция будет применяться к каждому элементу, создавая новый LongStream
flatMap(Function f) Принимает функцию в качестве параметра, заменяет каждое значение в потоке другим потоком и объединяет все потоки в один поток.
//映射
@Test
public void test1(){
  Stream<String> str = persons.stream()
    .map((e) -> e.getName());
  System.out.println("-------------------------------------------");
  List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
  Stream<String> stream = strList.stream()
    .map(String::toUpperCase);
  stream.forEach(System.out::println);

  System.out.println("---------------------------------------------");

  Stream<Character> stream3 = strList.stream()
    .flatMap(TestStreamAPI::filterCharacter);
  stream3.forEach(System.out::println);
}

public static Stream<Character> filterCharacter(String str){
  List<Character> list = new ArrayList<>();
  for (Character ch : str.toCharArray()) {
    list.add(ch);
  }
  return list.stream();
}
2.2.3 Сортировка
метод описывать
sorted() создает новый поток, который сортируется в естественном порядке
sorted(Comparator comp) создает новый поток, который сортируется в порядке сравнения
@Test
public void test(){
  persons.stream()
    .map(Person::getName)
    .sorted()
    .forEach(System.out::println);

  System.out.println("------------------------------------");

  persons.stream()
    .sorted((x, y) -> {
      if(x.getAge() == y.getAge()){
        return x.getName().compareTo(y.getName());
      }else{
        return Integer.compare(x.getAge(), y.getAge());
      }
    }).forEach(System.out::println);
}

2.3 Операция завершения потока

Терминальные операции производят результаты из конвейера потока. Результатом может быть любое значение, не являющееся потоком, например: List, Integer или даже void.

2.3.1 Найти и сопоставить
метод описывать
allMatch(Predicate p) Проверьте, все ли элементы совпадают
anyMatch(Predicate p) Проверьте, соответствует ли хотя бы один элемент
noneMatch(Predicate p) Проверьте, не совпадают ли все элементы
findFirst() вернуть первый элемент
findAny() Возвращает любой элемент в текущем потоке
count() Возвращает общее количество элементов в потоке
max(Comparator c) Возвращает максимальное значение в потоке
min(Comparator c) Возвращает наименьшее значение в потоке
forEach(Consumer c) Внутренняя итерация (использование интерфейса Collection требует, чтобы пользователь выполнял итерацию, называемую внешней итерацией. В отличие от этого, Stream API использует внутреннюю итерацию — он выполняет итерацию за вас)
public class TestStreamAPI2 {

	List<Person> persons = Person.createRoster();	
	//3. 终止操作
	@Test
	public void test1(){
			boolean bl = persons.stream()
				.allMatch((e) -> e.getGender().equals(Person.Sex.FEMALE));
			
			System.out.println("所有成员都为女性吗?"+bl);
			
			boolean bl1 = persons.stream()
				.anyMatch((e) -> e.getGender().equals(Person.Sex.FEMALE));
			
			System.out.println("成员中有女性吗?"+bl1);
			
			boolean bl2 = persons.stream()
				.noneMatch((e) -> e.getGender().equals(Person.Sex.FEMALE));
			
			System.out.println("成员中是不是没有女性?"+bl2);
	}
	
	@Test
	public void test2(){
		Optional<Person> op = persons.stream()
			.sorted(Comparator.comparingInt(Person::getAge))
			.findFirst();
		System.out.println("年龄最小的:"+op.get());
		
		Optional<Person> op2 = persons.parallelStream()
			.filter((e) -> e.getGender().equals(Person.Sex.MALE))
			.findAny();
		
		System.out.println("随便找个男的:"+op2.get());
	}
	
	@Test
	public void test3(){
		long count = persons.stream()
						 .filter((e) -> e.getGender().equals(Person.Sex.FEMALE))
						 .count();
		
		System.out.println("女生的人数:"+count);
		
		Optional<Integer> op = persons.stream()
			.map(Person::getAge)
			.max(Integer::compare);
		
		System.out.println("最大年龄:"+op.get());
		
		Optional<Person> op2 = persons.stream()
			.min((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
		
		System.out.println("最小年龄成员:"+op2.get());
	}
	
	//注意:流进行了终止操作后,不能再次使用
	@Test
	public void test4(){
		Stream<Person> stream = persons.stream()
		 .filter((e) -> e.getGender().equals(Person.Sex.FEMALE));
		
		long count = stream.count();
		
		stream.map(Person::getAge)
			.max(Integer::compare);
	}
}
2.3.2 Протокол
метод описывать
reduce(T iden, BinaryOperator b) Элементы в потоке можно многократно комбинировать для получения значения. вернуть Т
reduce(BinaryOperator b) Элементы в потоке можно многократно комбинировать для получения значения. вернуть необязательный

Примечание. Объединение map и reduce часто называют шаблоном map-reduce, известным благодаря тому, что Google использует его для веб-поиска.

List<Person> persons = Person.createRoster();

//3. 终止操作:归约
@Test
public void test1(){
  List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
  Integer sum = list.stream()
    .reduce(0, (x, y) -> x + y);

  System.out.println(sum);
  System.out.println("----------------------------------------");

  Optional<Integer> op = persons.stream()
    .map(Person::getAge)
    .reduce(Integer::sum);
  System.out.println("所有成员的年龄和:"+op.get());
}

//需求:搜索名字中 “B” 出现的次数
@Test
public void test2(){
  Optional<Integer> sum = persons.stream()
    .map(Person::getName)
    .flatMap(TestStreamAPI1::filterCharacter)
    .map((ch) -> {
      if(ch.equals('B'))
        return 1;
      else 
        return 0;
    }).reduce(Integer::sum);

  System.out.println(sum.get());
}
2.3.3 Коллекция
метод описывать
collect(Collector c) Преобразование потока в другую форму. Получает реализацию интерфейса Collector, метод суммирования элементов в Stream

Collectors

Реализация методов в интерфейсе Collector определяет, как выполнять операцию сбора в потоке (например, сбор List, Set, Map). ноCollectorsВспомогательный класс предоставляет множество статических методов, с помощью которых можно легко создавать общие экземпляры сборщиков.Конкретные методы и примеры приведены ниже:docs.Oracle.com/java-color/8/do…

метод возвращаемый тип эффект Пример
toList List Соберите элементы в потоке в список List list= list.stream().collect(Collectors.toList());
toSet Set Собирать элементы из потока в Set Set set= list.stream().collect(Collectors.toSet());
toCollection Collection Собрать элементы из потока в созданную коллекцию Collectione mps=list.stream().collect(Collectors.toCollection(ArrayList::new));
counting Long подсчитать количество элементов в потоке long count = list.stream().collect(Collectors.counting());
summingInt Integer Суммируйте целочисленные атрибуты элементов в потоке Integer sum = persons.stream() .collect(Collectors.summingInt(Person::getAge));
averagingInt Double Вычисляет среднее значение целочисленных свойств элементов в потоке. double avg= list.stream().collect(Collectors.averagingInt(Person::getAge));
summarizingInt IntSummaryStatistics Соберите статистику для свойства Integer в потоке. например средний IntSummaryStatistics iss= list.stream().collect(Collectors.summarizingInt(Person::getAge));
joining String объединить каждую строку в потоке String str= list.stream().map(Person::getName).collect(Collectors.joining());
maxBy Optional<T> Выберите максимальное значение на основе компаратора Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Person::getAge)));
minBy Optonal<T> Выберите минимальное значение на основе компаратора Optional min = list.stream().collect(Collectors.minBy(comparingInt(Person::getAge)));
reducing Типы, полученные путем сокращения Начните с начального значения в качестве аккумулятора и используйте BinaryOperator для объединения элементов в потоке один за другим, чтобы сократить до одного значения. int total=list.stream().collect(Collectors.reducing(0, Person::getAge, Integer::sum));
collectingAndThen Преобразование типа, возвращаемого функцией Оберните другой сборщик и преобразуйте функцию в ее результат int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingBy Map<K,List<T>> Группировать потоки в соответствии со значением атрибута, атрибут — K, а результат — V. Map<Person.Sex, List<Person>> map = persons.stream() .collect(Collectors.groupingBy(Person::getGender));
partitioningBy Map<Boolean,List<T>> Раздел на основе истинного или ложного Map<Boolean, List<Person>> map = persons.stream() .collect(Collectors.partitioningBy((e) -> e.getAge() >= 50));
@Test
public void test3(){
  List<String> list = persons.stream()
    .map(Person::getName)
    .collect(Collectors.toList());
  list.forEach(System.out::println);
}

@Test
public void test4(){
  Optional<Integer> max = persons.stream()
    .map(Person::getAge)
    .collect(Collectors.maxBy(Integer::compare));

  System.out.println("最大年龄:"+max.get());

  Optional<Person> op = persons.stream().min(Comparator.comparingInt(Person::getAge));

  System.out.println("最小年龄的成员:"+op.get());

  Integer sum = persons.stream()
    .collect(Collectors.summingInt(Person::getAge));

  System.out.println("所有成员年龄和:"+sum);

  IntSummaryStatistics dss = persons.stream()
    .collect(Collectors.summarizingInt(Person::getAge));

  System.out.println("最大年龄:"+dss.getMax());
}

//分组
@Test
public void test5(){
  Map<Person.Sex, List<Person>> map = persons.stream()
    .collect(Collectors.groupingBy(Person::getGender));

  System.out.println("按性别分组:"+map);
}

//多级分组
@Test
public void test6(){
  Map<Person.Sex, Map<String, List<Person>>> map = persons.stream()
    .collect(Collectors.groupingBy(Person::getGender, Collectors.groupingBy((e) -> {
      if(e.getAge() >= 60)
        return "老年";
      else if(e.getAge() >= 35)
        return "中年";
      else
        return "成年";
    })));

  System.out.println(map);
}

//分区
@Test
public void test7(){
  Map<Boolean, List<Person>> map = persons.stream()
    .collect(Collectors.partitioningBy((e) -> e.getAge() >= 50));

  System.out.println(map);
}
@Test
public void test8(){
  String str = persons.stream()
    .map(Person::getName)
    .collect(Collectors.joining("," , "----", "----"));

  System.out.println(str);
}

@Test
public void test9(){
  Optional<Integer> sum = persons.stream()
    .map(Person::getAge)
    .collect(Collectors.reducing(Integer::sum));
  System.out.println(sum.get());
}

3. Параллельная потоковая передача и последовательная потоковая передача

Поговорим о параллелизме и параллелизме

Параллелизм — это когда две задачи разделяют период времени, а параллелизм — это когда две задачи выполняются одновременно, например, на многоядерном процессоре.

lbvsVU.png

Параллельная потоковая передача предназначена для разделения контента на несколько блоков данных и использования разных потоков для обработки потока каждого блока данных отдельно..

Параллелизм был оптимизирован в Java 8, и мы можем легко выполнять параллельные операции с данными. Stream API можно передать декларативноparallel()иsequential()Переключение между параллельным и последовательным потоками. Чтобы создать поток из класса коллекции, вызовитеparallerStreamМожно получить параллельный поток.

public static long parallelSum(long n) {
    return Stream.iterate(1L, i -> i + 1)
        .limit(n)
        .parallel()    //将流转化为并行流
        .reduce(0L, Long::sum);
}

Настройте пул потоков, используемый параллельным потоком

Используя параллельный метод потоков, вы можете задаться вопросом, откуда берутся потоки для параллельных потоков? Сколько их там? Как настроить?

Параллельные потоки внутренне используют значение по умолчанию.ForkJoinPool(инфраструктура ветки/слияния), количество потоков по умолчанию — это количество ваших процессоров, это значение определяетсяRuntime.getrRuntime().acailable-Processors()получить.

Вы можете передать системные свойстваjava.util.concurrent.ForkJoinPool.common.parallelismЧтобы изменить размер пула потоков, выполните следующие действия.

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","12");, который является глобальным параметром и, таким образом, влияет на все параллельные потоки в коде (в настоящее время нет возможности указать это значение специально для параллельного потока, обычно размер ForkJoinPool равен количеству процессоров по умолчанию).

Эффективное использование параллельных потоков

  • Параллельные потоки не всегда быстрее, чем последовательные.
  • Обратите внимание на упаковку. Операции автоупаковки и распаковки могут значительно снизить производительность, Java8 имеет потоки примитивного типа (IntStream, LongStream...), чтобы избежать таких операций.
  • Некоторые операции сами по себе выполняются хуже в параллельных потоках, чем в последовательных, особенно такие операции, как limit и findFirst, которые зависят от порядка элементов, и их выполнение в параллельных потоках очень затратно.
  • Также учтите общую вычислительную стоимость конвейера операций потока.
  • Для меньших объемов данных параллельные потоки не нужны.
  • Необходимо учитывать, легко ли разложить структуру данных за потоком.Например, эффективность разбиения ArrayList намного выше, чем у LinkedList, и первому не нужно проходить
  • Также подумайте, велика или мала стоимость объединения шагов в терминальных операциях (например, метод объединения в Collector).

4. Разветвить/объединить фреймворк

Базовая структура, используемая для параллельных потоков, была представлена ​​​​в Java7.структура ветвления/слияния.

Цель фреймворка Fork/Join (ветка/слияние) состоит в том, чтобы рекурсивно разделить (разветвить) параллелизуемые задачи на более мелкие задачи, а затем объединить (объединить) результаты каждой задачи для получения общего эффекта. Это реализация интерфейса ExectorService, который назначает подзадачи рабочим потокам в пуле потоков (называемом ForkJoinPool).

Структура Fork/Join: при необходимости большая задача разбивается (разветвляется) на несколько небольших задач (когда ее нельзя разделить), а затем результаты каждой операции небольшой задачи объединяются и суммируются.

fork-join.png

// 用分支/合并框架 并行求和
public class ForkJoinSumCalculator extends RecursiveTask<Long> {

    private final long[] numbers;
    private final int start;
    private final int end;

    //不再将任务分解为子任务的数组大小
    public static long THRESHOLD = 100;

    //公共构造器用于创建主任务
    public ForkJoinSumCalculator(long[] numbers) {
        this(numbers, 0, numbers.length);
    }

    //私有构造器用于以递归方式为主任务创建子任务
    private ForkJoinSumCalculator(long[] numbers, int start, int end) {
        this.numbers = numbers;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        int length = end - start;
        //如果大小小于等于阈值,顺序计算结果
        if (length <= THRESHOLD) {
            return computerSequntially();
        }

        ForkJoinSumCalculator leftTask = new ForkJoinSumCalculator(numbers, start, start + length / 2);

        leftTask.fork();

        ForkJoinSumCalculator rightTask = new ForkJoinSumCalculator(numbers, start + length / 2, end);

        Long rightResult = rightTask.compute();   //同步执行第二个任务,
        Long leftResult = leftTask.join(); // 读取第一个子任务的结果,如果尚未完成就等待
        return rightResult + leftResult;
    }


    // 子任务不再可分时计算和
    private long computerSequntially() {
        long sum = 0;
        for (int i = start; i < end; i++) {
            sum += numbers[i];
        }
        return sum;
    }

    public static long forkJoimSum(long n) {
        long[] numbers = LongStream.rangeClosed(1, n).toArray();
        ForkJoinTask<Long> task = new ForkJoinSumCalculator(numbers);
        return new ForkJoinPool().invoke(task);
    }

    public static void main(String[] args) {
        System.out.println("sum:" + forkJoimSum(10000));
    }
}

Разница между инфраструктурой Fork/Join и традиционным пулом потоков

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

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

Лучшие практики использования фреймворка Fork/Join

  • Вызов метода соединения для задачи блокирует вызывающую сторону до тех пор, пока задача не выдаст результат. Поэтому вызывать его необходимо после того, как началось вычисление обеих подзадач.
  • Метод вызова ForkJoinPool не следует использовать внутри RecursiveTask. Вместо этого вы всегда должны вызывать методы вычисления или разветвления напрямую, и только последовательный код должен использовать вызов для инициации параллельных вычислений.

кража работы

fork-join-steal.jpg

5. Spliterator

«Разделяемые итераторы» — разделители, как и итераторы, также используются для обхода элементов в источнике данных и предназначены для параллельного выполнения.

Java 8 предоставляет метод Spliterator по умолчанию для всех структур данных, содержащихся в структуре коллекций. Коллекции реализуют интерфейс Spliterator, который предоставляет метод Spliterator.

spliterator

Пять, метод по умолчанию и статический метод в интерфейсе

Традиционно класс в Java, реализующий интерфейс, должен предоставлять класс реализации для каждого метода, определенного в интерфейсе, или наследовать его реализацию от родительского класса. А вот если дизайнеру библиотеки классов нужно доработать интерфейс и добавить новые методы, то на этом пути будут проблемы. Все классы сущностей, которые используют этот интерфейс, должны быть изменены, чтобы адаптироваться к новому соглашению об интерфейсе (если он настолько несовместим, он будет устранен рано или поздно). Поэтому в Java8 появился новый механизм для решения этой проблемы.Поддержка интерфейса в Java 8 обеспечивает реализацию при объявлении методов. Один,Java 8 позволяет объявлять статические методы в интерфейсах. Во-вторых, новые функции, представленные в Java8 —Метод по умолчанию, с помощью метода по умолчанию вы можете указать реализацию метода интерфейса по умолчанию.(Поэтому, если класс, реализующий интерфейс, не предоставляет явно конкретную реализацию метода, он автоматически унаследует реализацию по умолчанию. Этот механизм позволяет плавно оптимизировать и обновлять интерфейс).

метод по умолчанию

В Java 8 интерфейс может содержать метод с конкретной реализацией, который называется «методом по умолчанию», а метод по умолчанию используетdefaultМодификация ключевого слова.

interface MyFunc<T>{
    T func(int a);

    default String getName(){
        return "hello java8";
    }
}
@Test
public void test1(){
    List<Integer> list = Arrays.asList(22,11,33,55,4);
    //sort是List接口中的默认方法,naturalOrder是Comparator的静态方法
    list.sort(Comparator.naturalOrder());
    for (Integer integer : list) {
        System.out.println(integer);
    }
}

default-method.png

Принцип «сначала класс» методов по умолчанию

Если интерфейс определяет метод по умолчанию, а другой родительский класс или интерфейс определяет метод с тем же именем

  • Выберите метод в родительском классе. Если суперкласс предоставляет конкретную реализацию, то методы по умолчанию в интерфейсе с тем же именем и параметрами игнорируются.

  • Конфликт интерфейсов. Если родительский интерфейс предоставляет метод по умолчанию, а другой интерфейс также предоставляет метод с тем же именем и списком параметров (независимо от того, является ли метод методом по умолчанию или нет), то для разрешения конфликта этот метод необходимо переопределить.

interface MyFunc<T> {
    default String getName() {
        return "hello java8";
    }
}

interface MyFunc1 {
    default String getName() {
        return "hello Java情报局";
    }
}

class MyClass implements MyFunc, MyFunc1 {

    @Override
    public String getName() {
        return MyFunc1.super.getName();
    }
}

Разработчики Java API в полной мере использовали методы по умолчанию и добавили множество новых методов в интерфейсы и классы коллекций.


6. Необязательный класс

1. Замените нуль на необязательный

Когда вы сталкиваетесь с NullPointerException в своей программе, является ли ваш первый импульс быстро найти код, добавить оператор if и проверить? ?

NullPointerException — типичное исключение при разработке программ на Java. Чтобы избежать такого рода исключений, наш код может быть заполнен слоями и слоями глубоко вложенных проверок null, а читабельность кода крайне плохая.

Необязательный класс (java.util.Optional) — это класс-контейнер, который представляет существование или отсутствие значения. Первоначально null означал, что значение не существует. Теперь Optional может лучше выразить эту концепцию. И может избежать исключения нулевого указателя.

Когда переменная существует, необязательное знание класса просто инкапсулирует класс. Если переменная не существует, отсутствующее значение моделируется как «пустой» необязательный объект, который используется методомOptional.empty()возвращение.

Общий метод:

  • Optional.of(T t) : создать необязательный экземпляр
  • Optional.empty() : создает пустой опциональный экземпляр.
  • Optional.ofNullable(T t): если t не равно null, создайте необязательный экземпляр, в противном случае создайте пустой экземпляр.
  • isPresent() : определить, содержит ли он значение orElse(T t) : если вызывающий объект содержит значение, вернуть значение, в противном случае вернуть t
  • orElseGet(Supplier s): если вызывающий объект содержит значение, вернуть значение, в противном случае вернуть значение, полученное s
  • map (функция f): если есть значение для его обработки, и вернуть обработанный необязательный элемент, в противном случае вернуть необязательный.пустой ()
  • flatMap (сопоставитель функций): аналогично карте, возвращаемое значение должно быть необязательным.

2. Необязательный экземпляр

2.1 Создать необязательный объект

@Test
public void test(){

    Optional<Person> optional = Optional.empty();  //创建一个空Optional

    Optional<Person> op = Optional.of(new Person());
    Person p = op.get();
    System.out.println(p);   //Person{name='null', birthday=null, gender=null, emailAddress='null'}

    Person person = null;
    Optional<Person> op1 = Optional.of(person); //person为null,抛出NullPointerException

    Optional<Person> op2 = Optional.ofNullable(person);   //创建允许null值得Optional对象

}

2.2 необязательные операции с объектами

@Test
public void test4(){
    Person person = new Person("Tom",IsoChronology.INSTANCE.date(1999, 7, 15),Person.Sex.FEMALE, "Tom@360.com")
    Optional<Person> op = Optional.ofNullable(person);

    Optional<String> op1 = op.map(Person::getName);
    System.out.println(op1.get());
    
    /**
    * 使用 map 从 optional 对象中提取和转换值
    * 如果想提取人员姓名,之前需要判断persion !=null,Optional提供了一个map方法,对其处理
    **/
    Optional<String> op2 = op.map(Person::getName);
    System.out.println(op2.get());

    //使用 flatMap 链接 optional 对象
    Optional<String> op3 = op.flatMap((e) -> Optional.of(e.getName()));
    System.out.println(op3.get());
    
    //TODO
}

7. CompletableFuture — компонуемое асинхронное программирование

1. Будущий интерфейс

Интерфейс Future был представлен в Java 5 и изначально был разработан для моделирования результатов, которые произойдут в какой-то момент в будущем. Он моделирует асинхронное вычисление, возвращающее ссылку на результат выполнения вычисления, которая возвращается вызывающему объекту после завершения вычисления. Запуск потенциально трудоемких операций в Future освобождает вызывающий поток для продолжения выполнения другой важной работы, не дожидаясь завершения трудоемкой операции. В качестве аналогии вы можете думать об этом как о сценарии, в котором вы несете сумку с одеждой в свою любимую химчистку для стирки. Химчистка выдаст вам счет, в котором будет указано, когда ваша одежда будет готова (это событие будущего). Пока одежда в химчистке, можно заняться другими делами. Другое преимущество Future заключается в том, что его проще использовать, чем Thread более низкого уровня. Чтобы использовать Future, вам обычно нужно только инкапсулировать трудоемкую операцию в вызываемом объекте, а затем отправить ее в ExecutorService. В следующем коде показан пример использования Futures до Java 8.

ExecutorService executor = Executors.newCachedThreadPool();
Future<Double> future = executor.submit(new Callable<Double>() {
    public Double call() {
        return doSomeThings();    //异步方式在新的线程中执行操作
    }
});
//doSomethingElse();    //异步操作进行的同时,可以做其他事情
try {
    //获取异步操作的结果,如果阻塞,等1秒后退出
    Double result = future.get(1, TimeUnit.SECONDS);   
} catch (ExecutionException | InterruptedException | TimeoutException e) {
}

1.1 Ограничения интерфейса будущего

Хотя Future и родственные методы использования предоставляют возможность асинхронного выполнения задач, получать результаты очень неудобно, а результаты задач можно получить только путем блокировки или опроса. Метод блокировки явно противоречит первоначальному замыслу нашего асинхронного программирования.Метод опроса будет потреблять ненужные ресурсы ЦП, и результат вычисления не может быть получен вовремя.Почему мы не можем использовать шаблон проектирования наблюдателя, чтобы вовремя уведомить слушателя когда результат расчета завершен Шерстяная ткань?

Некоторые фреймворки Java, такие как Netty, расширяют возможности Java.Futureинтерфейс, обеспечивающийaddListenerи другие методы расширения. Google guava также предоставляет общее расширение Future: ListenableFuture, SettableFuture и вспомогательные классы Futures и т. д. для облегчения асинхронного программирования.

Как ортодоксальная библиотека классов Java, должны ли мы сделать что-то, чтобы усилить функцию нашей собственной библиотеки?

В Java 8 был добавлен новый класс с примерно 50 методами:CompletableFuture, предоставляет очень мощную функцию расширения Future, которая может помочь нам упростить сложность асинхронного программирования, предоставляет возможность функционального программирования, может обрабатывать результаты вычислений с помощью обратных вызовов и предоставляет методы для преобразования и объединения CompletableFuture.

Например, реализуйте следующие примеры:

  • Объединить два асинхронных вычисления в одно — два асинхронных вычисления относительно независимы, а второе зависит от результата первого
  • Дождитесь завершения всех задач в коллекции Future.
  • Дождитесь завершения самой быстрой задачи в коллекции Future (возможно, потому, что они пытаются вычислить одно и то же значение разными способами) и верните ее результат.
  • Завершить выполнение задачи Future программно (то есть вручную установив результат асинхронной операции)
  • Реагировать на событие завершения Future (то есть вы получите уведомление, когда произойдет событие завершения Future, и вы сможете использовать результат вычисления Future для выполнения следующей операции, а не просто блокировать результат ожидания операция)

1.2 Создание асинхронных приложений с CompletableFuture

public class TestCompletableFuture {
    public static CompletableFuture<Integer> compute() {
        final CompletableFuture<Integer> future = new CompletableFuture<>();
        return future;
    }
    public static void main(String[] args) throws Exception {
        final CompletableFuture<Integer> f = compute();
        class Client extends Thread {
            CompletableFuture<Integer> f;
            Client(String threadName, CompletableFuture<Integer> f) {
                super(threadName);
                this.f = f;
            }
            @Override
            public void run() {
                try {
                    System.out.println(this.getName() + ": " + f.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }
        new Client("Client1", f).start();
        new Client("Client2", f).start();
        System.out.println("waiting");
        f.complete(100);
        System.in.read();
    }
}

8. Новый API времени и даты

1. Используйте LocalDate, LocalTime, LocalDateTime

  • Экземпляры классов LocalDate, LocalTime, LocalDateTimeнеизменяемый объект, представляющие дату, время, дату и время, соответственно, с использованием календарной системы ISO-8601. Они предоставляют простую дату или время и не содержат информацию о текущем времени. Он также не содержит информацию о часовом поясе.

    @Test
    public void test1(){
        LocalDate date = LocalDate.of(2020,01,03);
        Month month = date.getMonth();
        System.out.println(month);    //JANUARY
    
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        System.out.println(dayOfWeek);   //FRIDAY
    
        int len = date.lengthOfMonth();
        System.out.println(len);  //31
        //使用TemporalField(ChronoField枚举实现了该接口)读取LocalDate的值
        int year = date.get(ChronoField.YEAR);
        System.out.println(year);  //2020
    
        LocalDate ld = LocalDate.parse("2020-01-03");
        System.out.println(ld);   //2020-01-03
    
        LocalTime time = LocalTime.of(19,56,11);
        System.out.println(time);  //19:56:11
    
        LocalDateTime ldt = LocalDateTime.now();
        LocalDateTime l1 = LocalDateTime.of(2020,01,03,18,48);
        System.out.println(l1);  //2020-01-03T18:48
    
        LocalDateTime l2 = l1.plusYears(3);
        System.out.println(l2);     //2023-01-03T18:48
    
        LocalDateTime l3 = l1.minusMonths(1);
        System.out.println(l3);  //2019-12-03T18:48
        System.out.println(l3.getMinute()+","+l3.getYear());   //48,2019
    }
    

2. Мгновенная отметка времени

  • Операция для "отметки времени". Он рассчитывается как количество секунд, прошедших с начала первого года Unix (традиционно устанавливается в полночь 1 января 1970 года в часовом поясе UTC).

    @Test
    public void test2(){
        Instant ins = Instant.now();  //默认使用 UTC 时区
        OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
        System.out.println(odt);
        System.out.println(ins.getNano());
        Instant ins2 = Instant.ofEpochSecond(5);
        System.out.println(ins2);
    }
    

3. Продолжительность и период

  • Продолжительность: используется для расчета двух «временных» интервалов.

  • Период: используется для расчета интервала между двумя «датами».

    @Test
    public void test3(){
        Instant ins1 = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        Instant ins2 = Instant.now();
        System.out.println("所耗费时间为:" + Duration.between(ins1, ins2));   
    
        System.out.println("----------------------------------");
        LocalDate ld1 = LocalDate.now();
        LocalDate ld2 = LocalDate.of(2019, 1, 1);
    
        Period pe = Period.between(ld2, ld1);
        System.out.println(pe.getYears());  
        System.out.println(pe.getMonths());
        System.out.println(pe.getDays());
    }
    

4. Манипуляции с датами

  • Измените свойства LocalDate с помощью метода withXXX.

  • TemporalAdjuster : Регулятор времени. Иногда нам может понадобиться получить такие операции, как: скорректировать дату на «следующее воскресенье» и т. д.

  • TemporalAdjusters : этот класс предоставляет реализации ряда часто используемых TemporalAdjusters через статические методы.

    @Test
    public void test(){
        LocalDate date = LocalDate.now();
        //通过withAttributer方法修改LocalDate的属性
        LocalDate date1 = date.with(ChronoField.ALIGNED_WEEK_OF_YEAR,9);
        LocalDate date2 = date.withYear(2019);
        LocalDate date3 = date.withDayOfMonth(11);  //修改为11号
        System.out.println(date1);
        //下周日
        LocalDate nextSunday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        System.out.println(nextSunday);
    }
    

5. Разбор и форматирование

java.time.format.DateTimeFormatterКласс: этот класс предоставляет три метода форматирования:

  • предопределенные стандартные форматы

  • Формат, зависящий от локали

  • пользовательский формат

    @Test
    public void test(){
        //DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
    
        LocalDateTime ldt = LocalDateTime.now();
        String strDate = ldt.format(dtf);
    
        System.out.println(strDate); //2020年01月03日 20:32:14 星期五
    
        LocalDateTime newLdt = ldt.parse(strDate, dtf);
        System.out.println(newLdt);  //2020-01-03T20:32:14
    }
    

Обработка часовых поясов

  • В Java 8 добавлена ​​поддержка часовых поясов.Время с часовыми поясами: ZonedDate, ZonedTime, ZonedDateTime.

    Каждому часовому поясу соответствует идентификатор, а идентификатор региона имеет формат «{регион}/{город}». Например: Азия/Шанхай и т. д.

    ZoneId: этот класс содержит всю информацию о часовом поясе.

    • getAvailableZoneIds(): может получить информацию обо всех часовых поясах.
  • of(id) : получить объект ZoneId с указанной информацией о часовом поясе.

    @Test
    public void test(){
        Set<String> set = ZoneId.getAvailableZoneIds();  //遍历时区
        set.forEach(System.out::println);
        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        System.out.println(ldt);
    
        ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific"));
        System.out.println(zdt);
    }
    

9. Дублируйте аннотации и аннотации типов

аннотация

Java 8 предоставляет два улучшения обработки аннотаций:повторяемая аннотацияиАннотации, доступные для типов

Аннотации в Java — это механизм настройки элементов программы и предоставления дополнительной информации (до Java 8 аннотации можно было использовать только в объявлениях).

Дублировать аннотации

До Java8 повторяющиеся аннотации, подобные приведенным выше, не допускались, поэтому это ограничение обычно обходили некоторыми идиоматическими методами. Можно объявить новую аннотацию, содержащую массив аннотаций, которые вы хотите повторить.

Создать повторяющуюся аннотацию

  1. Пометить аннотацию как **@Repeatable**
  2. Предоставляет контейнер для аннотаций
import java.lang.annotation.Repeatable;
@Repeatable(Authors.class)
public @interface Author {
    String name();
}
public @interface Authors {
    Author[] value();
}
@Author(name = "Java")
@Author(name = "Android")
public class Book {
    public static void main(String[] args) {
        Author[] authors = Book.class.getAnnotationsByType(Author.class);
        Arrays.asList(authors).forEach(s->{
            System.out.println(s.name());
        });
    }
}

введите аннотацию

Начиная с Java 8 аннотации можно применять к любому типу. Включает оператор new, преобразования типов, проверки instanceof, параметры универсального типа, а также предложения implemtnts и throws.

@NotNull String name = person.getName();    //getName不返回空

List<@NotNull Person> persons = new ArrayList<>();  //persons总是非空

10. Другие особенности языка

атомарная операция

java.util.concurrent.atomicПакет предоставляет несколько классов, работающих с числовыми типами, например AtomicInteger и AtomicLong, которые поддерживают атомарные операции с одной переменной. Эти классы добавили больше поддержки методов в Java 8.

  • getAndUpdate - атомарно обновить текущее значение с помощью данного метода и вернуть значение до изменения

  • updateAndGet — атомарно обновить текущее значение заданным методом и вернуть измененное значение

  • getAndAccumulate — атомарно обновить текущие и заданные значения заданным методом и вернуть значение до изменения

  • accumulationAndGet - атомарно обновляет текущие и заданные значения с помощью заданного метода и возвращает измененное значение

Сумматор и аккумулятор

В многопоточной среде, если нескольким потокам необходимо выполнять частые операции обновления и редко считывать действия (например, в контексте статистических вычислений), документация Java API рекомендует использовать новые классы LongAdder, LongAccumulator, Double-Adder и DoubleAccumulator, попробуйте чтобы избежать использования соответствующих им атомарных типов. Эти новые классы были разработаны с учетом требований динамического роста, что может эффективно снизить конкуренцию между потоками.

И классы LongAddr, и DoubleAdder поддерживают операции сложения, а LongAccumulator и DoubleAccumulator могут объединять несколько значений с помощью заданного метода.

ConcurrentHashMap

Введение класса ConcurrentHashMap значительно улучшило модернизацию HashMap, а недавно представленный ConcurrentHashMap очень удобен для параллелизма. ConcurrentHashMap допускает одновременные операции добавления и обновления, поскольку он блокирует только определенные части внутренней структуры данных. Следовательно, он имеет более высокую производительность чтения и записи по сравнению с альтернативой, синхронной хэш-таблицей.

  1. представление

    Для повышения производительности необходимо изменить внутреннюю структуру данных ConcurrentHashMap. Как правило, записи карты хранятся в сегментах и ​​доступны на основе хеш-значения, сгенерированного из ключа. Однако, если большое количество ключей возвращает одно и то же значение хеш-функции, поскольку ведро реализовано в виде списка, сложность его запроса составляет O(n), и в этом случае производительность ухудшится. В Java 8, когда ведра становятся слишком раздутыми, они динамически заменяются отсортированными деревьями, новая структура данных имеет лучшую производительность запросов (сложность запроса отсортированного дерева составляет O(log(n))). Обратите внимание, что эта оптимизация возможна только в том случае, если ключи сопоставимы (например, классы String или Number).

  2. Потоковые операции

    ConcurrentHashMap поддерживает три новые операции, похожие на те, что вы уже видели с потоками:

  • forEach — выполнить определенную операцию над каждой парой ключ-значение

  • уменьшить - объединить все пары ключ-значение в один результат, используя заданную функцию сокращения

  • search — выполняет функцию для каждой пары ключ-значение до тех пор, пока возвращаемое значение функции не станет ненулевым значением.

    Каждая из вышеперечисленных операций поддерживает четыре формы, принимая функции, принимающие ключ, значение, Map.Entry и пары ключ-значение:

  • Операции с использованием ключей и значений (forEach, reduce, search)

  • Операции с использованием ключей (forEachKey, reduceKeys, searchKeys)

  • Операции, использующие значения (forEachValue, reduceValues, searchValues)

  • Операции с использованием объектов Map.Entry (forEachEntry, reduceEntries, searchEntries)

Обратите внимание, что эти операции не блокируют состояние ConcurrentHashMap. Они будут работать только с элементами во время выполнения. Функции, применяемые к этим операциям, не должны зависеть ни от упорядочения, ни от других объектов, ни от значений, изменяющихся в процессе вычислений. Кроме того, вам необходимо указать порог параллелизма для этих операций. Если предварительно оцененный размер текущей карты меньше установленного порога, операции будут выполняться последовательно. Используйте значение 1, чтобы включить максимальный параллелизм на основе универсального пула потоков. Используйте значение Long.MAX_VALUE, чтобы программа работала в одном потоке. В следующем примере мы используем reduceValues, чтобы попытаться найти максимальное значение на карте:

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); 
Optional<Integer> maxValue = Optional.of(map.reduceValues(1, Integer::max));

Обратите внимание, что для int, long и double операции сокращения различаются (например, reduceValuesToInt, reduceKeysToLong и т. д.).

  1. считать

    Класс ConcurrentHashMap предоставляет новый метод, называемыйmappingCount, который возвращает количество отображений в карте как long. Мы должны попытаться использовать этот новый метод вместо старого метода размера, который возвращает целое число. Это связано с тем, что количество карт может быть непредставимо целым числом.

  2. просмотр коллекции

    Класс ConcurrentHashMap также предоставляетKeySetНовый метод, возвращающий представление ConcurrentHashMap в виде набора (изменения карты отражаются в наборе и наоборот). Вы также можете использовать новый статический методnewKeySet, который создает набор из ConcurrentHashMap.

Arrays

Класс Arrays предоставляет различные статические методы для работы с массивами. Теперь он включает в себя четыре новых метода (все они имеют специально перегруженные переменные).

  • parallelSortМетод :parallelSort будет сортировать указанный массив параллельным образом, вы можете использовать естественный порядок или

    Определите специальный компаратор для объектов массива

  • setAll и parallelSetAll: методы setAll и parallelSetAll могут использовать предоставленную функцию для вычисления значения каждого элемента и установки всех элементов в указанном массиве последовательным или параллельным образом.

  • parallelPrefixМетод :parallelPrefix одновременно выполняет заданный пользователем бинарный оператор для каждого элемента в заданном массиве.

    Сделайте кумулятивный расчет

Number

Новый метод в классе Number

  • Классы Short, Integer, Long, Float и Double предоставляют статические методы sum, min и max.
  • Классы Integer и Long предоставляют методы compareUnsigned,divideUnsigned,remainUnsigned и toUnsignedLong для обработки чисел без знака.
  • Классы Integer и Long также предоставляют статические методы parseUnsignedInt и parseUnsignedLong соответственно для синтаксического анализа символов в типы unsigned int или long.
  • Классы Byte и Short предоставляют методы toUnsignedInt и toUnsignedLong для преобразования параметров в int или long путем беззнакового преобразования. Точно так же класс Integer теперь также предоставляет статический метод toUnsignedLong.
  • Классы Double и Float предоставляют статический метод isFinite, который может проверить, является ли параметр конечным числом с плавающей запятой.
  • Класс Boolean теперь предоставляет статические методы logicalAnd, logicalOr и logicalXor для выполнения операций and, or и xor между двумя логическими значениями.
  • Класс BigInteger предоставляет byteValueExact, shortValueExact, intValueExact и longValueExact для преобразования значения типа BigInteger в соответствующий базовый тип. Однако если во время преобразования происходит потеря информации, метод выдает арифметическое исключение.

Math

Класс Math предоставляет новые методы для создания арифметических исключений в случае сбоя методов Math во время операций. Методы, поддерживающие это исключение, включают addExact, subtractExact, multipleExact, incrementExact, decrementExact и negateExact с использованием параметров типа int и long. Кроме того, в классе Math есть новый статический метод toIntExact, который может преобразовывать значение типа long в значение типа int. Другие дополнения включают статические методы floorMod, floorDiv и nextDown.

Files

Наиболее заметным изменением в классе Files является то, что теперь вы можете создавать потоки непосредственно из файлов.

  • Files.list — создает Stream, состоящий из всех записей в указанном каталоге. Этот список не включается рекурсивно. Поскольку потоки потребляются лениво, этот метод полезен при работе с очень большими каталогами.
  • Files.walk — аналогично Files.list, он также создает Stream, содержащий все записи в заданном каталоге. Но этот список рекурсивный, вы можете установить глубину рекурсии. Обратите внимание, что обход идет в глубину
  • Files.find — находит совпадающие записи путем рекурсивного обхода каталога и создает объект Stream

String

Класс String также имеет новый статический метод, который называется join. Он может объединять несколько строк с разделителем. и тот, который предоставил apache, который мы использовали раньшеStringUtils.joinТакой же.

Reflection

Изменения в Reflection API должны поддерживать изменения в механизме аннотаций в Java 8. В дополнение к этому, еще одно изменение в интерфейсе переизбранияДобавлен API для запроса информации о параметрах метода., например, теперь вы можете использовать новыйjava.lang.reflect.ParameterИмена и модификаторы параметров метода запроса класса.


FAQ

  • Расскажите, какие новые функции вы знаете о Java8?

  • Что такое лямбда-выражение? Каковы преимущества?

  • В чем разница между реализацией ConcurrentHashMap в Java8 и Java7?

  • Можете ли вы рассказать об улучшенной JVM в Java 8?

  • Принцип hashMap, какие изменения внесены в java8?

  • Внешняя и внутренняя итерация, понимаете?


Ссылаться на

"Ява 8 бой"

«Функциональное программирование Java 8»

Официальная документация по Java 8

Бесплатный веб-сайт для видеообучения