предисловие
Так как в проекте используется много нового в Java8, я только сначала знал, как это написать, но это было не очень гладко, а потом я нашел хорошее видео о новых возможностях Java8 в Интернете, поэтому я продолжение После некоторого изучения ниже приведены мои заметки и соответствующее понимание лямбда-выражений и Stream API.Адрес видео, можете сами посмотреть, если интересно.
Новые функции в Java8
- Быстрее Заменена структура данных, структура памяти (JVM)
- *меньше кода (лямбда-выражения)*
- *Мощный потоковый API*
- Упростить параллельное вилочное соединение (параллельный последовательный коммутатор)
- Минимизировать исключения нулевого указателя Необязательно
Лямбда-выражения
Прежде чем говорить о Lambda, в первую очередь стоит поговорить о функциональном интерфейсе. Можно сказать, что это то, что существует для лямбда-выражений. Так что же такое функциональный интерфейс?
функциональный интерфейс
Определение: в интерфейсе есть только один абстрактный интерфейс. Все интерфейсы, такие как java.util.function, являются функциональными интерфейсами. Java 1.8 предоставляет @FunctionalInterface для проверки того, является ли интерфейс функциональным интерфейсом. например: Код пользовательского интерфейса в пакете java.util.function
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
// jdk 1.8 接口可以有默认实现
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Как только вы поймете, что такое функциональный интерфейс, вам будет легко понять лямбда-выражения.
«->» — это символ в левой части лямбда-выражения.Список параметров абстрактного метода в функциональном интерфейсе, правая сторона указываетваша реализация этого метода. Например например:
public class Test{
public static void main(String[] args){
Consumer consumer = x-> System.out.println(x);
consumer.accept(1);
}
}
выход 1;
Четыре функциональных интерфейса
Когда мы используем функциональные интерфейсы, мы обычно инкапсулируем их.
потребительский интерфейс
Потребитель имеет только один абстрактный метод с именем accept, список параметров имеет только один общий t и не возвращает никакого значения. Тип данных параметра определяется классом например:
/**
* @ClassName ConsumerTest
* @Description 消费型接口, 消费字符串字段 打印输出
* @Author ouyangkang
* @Date 2019-02-18 15:46
**/
public class ConsumerTest {
public static void main(String[] args) {
test("hello",x-> System.out.println(x));
}
public static <T> void test(T t, Consumer<T> consumer) {
consumer.accept(t);
}
}
вывод: привет Если вам нужно несколько списков параметров, вы также можете найти соответствующий функциональный интерфейс, такой как ObjLongConsumer, в пакете java.util.function. Остальные можете посмотреть сами
интерфейс питания
У поставщика есть только один абстрактный метод с именем get, список параметров пуст, есть возвращаемое значение и тип данных возвращаемого значения — T.
/**
* @ClassName SupplerTest
* @Description 供给型接口 字符串拼接
* @Author ouyangkang
* @Date 2019-02-18 15:53
**/
public class SupplerTest {
public static void main(String[] args) {
String hello = test("hello ", () -> "word!");
System.out.println(hello);
}
public static String test(String str,Supplier<String> supplier){
return str + supplier.get();
}
}
Вывод: привет, мир! Если возвращаемые данные относятся к базовому типу данных, вы можете найти соответствующий функциональный интерфейс в пакете java.util.function, например: getAsLong Другие можно просмотреть самостоятельно.
функциональный интерфейс
Function
/**
* @ClassName FunctionTest
* @Description 函数式接口 将字符串转换成大写的
* @Author ouyangkang
* @Date 2019-02-18 16:01
**/
public class FunctionTest {
public static void main(String[] args) {
String test = test("hello", x -> x.toUpperCase());
System.out.println(test);
}
public static String test(String str , Function<String,String> function){
return function.apply(str);
}
}
Вывод: ПРИВЕТ Если вам нужно несколько входных параметров, а затем вернуть значение, вы можете найти соответствующий функциональный интерфейс, такой как BiFunction, в пакете java.util.function. Остальные можете посмотреть сами
Напористый интерфейс
Напористый тип также известен как тип суждения. Predicate имеет только один абстрактный метод с именем test, только один параметр в списке параметров — T и имеет возвращаемое значение, а тип возвращаемого значения — логический.
/**
* @ClassName PredicateTest
* @Description 断言型接口,判断字符串大小是否大于6
* @Author ouyangkang
* @Date 2019-02-18 16:16
**/
public class PredicateTest {
public static void main(String[] args) {
boolean hello = test("hello", x -> x.length() > 6);
System.out.println(hello);
}
public static boolean test(String str, Predicate<String> predicate){
return predicate.test(str);
}
}
Вывод: ложь
Stream API
Отличительной чертой Java 8 является то, что Stream тесно связан сjava.ioInputStream и OutputStream в пакете — совершенно разные понятия. Потоковые промежуточные операции. Несколько промежуточных операций могут быть связаны для формирования конвейера. Если в конвейере не будет запущена операция завершения, никакая обработка не будет выполняться в середине! Когда операция завершена, она будет обработана сразу, что называется ленивой обработкой. Чтобы выполнить операцию потока, сначала получите поток. Есть 4 способа получить стрим.
- Получить поток Получить поток с помощью метода потока и метода parallelStream() (параллельный поток), предоставляемых серией коллекций.
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
// 常用获取流的方式
Stream<Integer> stream = list.stream();
}
- Преобразование массива в поток через Arrays.stream()
public static void main(String[] args) {
int[] a = new int[]{1,2,3,4};
IntStream stream = Arrays.stream(a);
}
- Создайте поток с помощью метода Stream.of Today
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
}
- Создавайте неограниченные потоки
public static void main(String[] args) {
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
}
Все операции над потоками можно разделить на 4 типа, а именно фильтрация и сегментация, отображение, сортировка и финализация (редукция, сбор)
Фильтрация и фрагментация
Операции: фильтр, расстояние, ограничение, пропуск. filter : операция фильтра, параметр метода является интерфейсом утверждения например:
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.filter(x->x != 2).forEach(x-> System.out.println(x));
}
вывод:
1
3
different : операция дедупликации, метод не имеет параметров limit : получить первые несколько фрагментов данных, параметр метода длинный skip : Сколько фрагментов данных пропустить раньше, а затем получить все следующие. Параметр метода длинный
карта
Общие операции включают map и flatMap. карта: обработайте исходные данные и верните обработанные данные. Параметр метода представляет собой функциональный интерфейс. например:
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.map(x->x*2).forEach(System.out::println);
}
вывод:
2
4
6
flatMap : интегрирует исходные данные исходного потока в другой поток один за другим. Параметр метода — это функциональный интерфейс, но возвращаемое значение — это поток. например:
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("f","d");
list.stream().flatMap(x->list2.stream().map(y-> x + y)).forEach(System.out::println);
}
Сортировать
Общие операции включают естественную сортировку сортировки, а параметр сортировки — это пользовательская сортировка сортировщика. Естественная сортировка, например:
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.sorted().forEach(System.out::println);
}
вывод:
1
2
3
пользовательская сортировка
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.sorted((x,y)->-Integer.compare(x,y)).forEach(System.out::println);
}
вывод:
3
2
1
Завершить операцию
- allMatch проверяет соответствие всех элементов. Параметр метода является интерфейсом утверждения.
- anyMatch проверяет соответствие всех элементов. Параметр метода является интерфейсом утверждений.
- noneMatch проверяет, не совпадают ли все элементы. Параметр метода является интерфейсом утверждения.
- findFirst возвращает первый элемент без параметров метода
- findAny возвращает любой элемент текущего потока без параметров метода
- count возвращает общее количество элементов в потоке, без параметров метода
- max возвращает максимальное значение потока, без аргументов метода
- min возвращает минимальное значение в потоке без аргументов метода
уменьшать
уменьшить : сокращение -- вы можете многократно комбинировать элементы в потоке, чтобы получить значение. например:
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer reduce = list1.stream().reduce(11, (x, y) -> x + y);
System.out.println(reduce);
}
выход: 66
собирать
Это очень распространенная операция. Переключите потоковую загрузку на другую форму. Получает реализацию интерфейса Collector, метод для суммирования элементов в Stream. Используйте метод collect для сбора. Параметр метода — Collector. Collector может быть реализован статическими методами, такими как toList(), toSet(), toMap(Function(T,R) key, Function(T,R)) value) в Collectors.
- toList() возвращает коллектор, который принимает список входных элементов в новый список.
- toMap(Function super T,? extends K> keyMapper, Function super T,? extends U> valueMapper) возвращает коллектор, который накапливает элементы в карту, чьи ключи и значения являются предоставленными функциями сопоставления, примененными к результату входной элемент.
- toSet() возвращает Collector, который устанавливает входные элементы в новый Set. например:
Класс пользователя
@Data
@ToString
public class User {
private String name;
private Integer age;
private Integer salary;
}
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("张三", 19, 1000),
new User("张三", 58, 2000),
new User("李四", 38, 3000),
new User("赵五", 48, 4000)
);
List<String> collect = users.stream().map(x -> x.getName()).collect(Collectors.toList());
Set<String> collect1 = users.stream().map(x -> x.getName()).collect(Collectors.toSet());
Map<Integer, String> collect2 = users.stream().collect(Collectors.toMap(x -> x.getAge(), x -> x.getName()));
System.out.println(collect);
System.out.println(collect1);
System.out.println(collect2);
}
вывод:
[张三, 张三, 李四, 赵五]
[李四, 张三, 赵五]
{48=赵五, 19=张三, 38=李四, 58=张三}
группировка
Метод Collectors.groupingBy() — это реализация операции с входными элементами, которая возвращает Collector «по группе» типа T , группируя элементы в соответствии с функцией сортировки. Это очень распространенная операция. Например, вы хотите сгруппировать людей с одинаковым именем. groupingBy(Function super T,? расширяет классификатор K>) например:
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("张三", 19, 1000),
new User("张三", 58, 2000),
new User("李四", 38, 3000),
new User("赵五", 48, 4000)
);
Map<String, List<User>> collect3 = users.stream().collect(Collectors.groupingBy(x -> x.getName()));
System.out.println(collect3);
}
Вывод: {Ли Си=[Пользователь{имя='Ли Си', возраст=38, зарплата=3000}], Чжан Сан=[Пользователь{имя='Чжан Сан', возраст=19, зарплата=1000}, Пользователь{ name='Чжан Сан', возраст=58, зарплата=2000}], Чжао Ву=[Пользователь{name='Чжао Ву', возраст=48, зарплата=4000}]}
Конечно, есть и другие, более сложные операции группирования, и фактический код зависит от того, какой бизнес нужно реализовать.
Суммировать
Поначалу лямбда-выражение в java8 может быть не очень знакомым, но пока вы с ним знакомы, вы обнаружите, что его очень легко использовать, а лямбда-выражение в сочетании с потоковым API может написать ваш собственный инструментальный класс. В обычных проектах это может сэкономить время и повысить эффективность написания кода. Теперь я даю класс инструментов List to Map.
public class CollectionStream {
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("张三", 19, 1000),
new User("张三", 58, 2000),
new User("李四", 38, 3000),
new User("赵五", 48, 4000)
);
Map<Integer, Integer> map = listToMap(users, x -> x.getAge(), x -> x.getSalary());
System.out.println(map);
}
/**
* @Author ouyangkang
* @Description list 转map key不能相同 ,如果相同会报错。 方法对 源数据,key,value过滤null。
* @Date 9:27 2019/2/19
* @param source 源数据
* @param key
* @param value
* @return java.util.Map<K,V>
**/
public static <DTO, K, V> Map<K, V> listToMap(List<DTO> source, Function<? super DTO, ? extends K> key, Function<? super DTO, ? extends V> value) {
Objects.requireNonNull(source, "source not null");
Objects.requireNonNull(key, "key not null");
Objects.requireNonNull(value, "value not null");
Map<K, V> map = source.stream()
.filter(dto -> dto != null)
.filter(dto -> key.apply(dto) != null)
.filter(dto -> value.apply(dto) != null)
.collect(Collectors.toMap(key, value));
return map;
}
}