Java8 新特性

java8 新特性

1. Optional

Optional类是一个容器对象,可以包含或者不包含一个非空的值。以下是Optional类的一些主要特性:避免空指针异常,通过使用Optional类,可以更加明确地表达一个值可能为null的情况,避免了空指针异常的发生。
Optional类提供了一系列方法来判断Optional对象是否包含值,如果包含值则可以获取该值,如果不包含值则可以提供默认值或者执行其他操作。
以下是一个简单的示例演示如何使用Optional类:
import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        String str = "Hello, World!";
        Optional<String> optional = Optional.ofNullable(str);

        // 判断Optional对象是否包含值
        if (optional.isPresent()) {
            System.out.println("Value is present: " + optional.get());
        } else {
            System.out.println("Value is not present");
        }

        // 使用map方法对Optional对象进行转换
        optional.map(s -> s.toUpperCase()).ifPresent(System.out::println);

        // 使用orElse方法提供默认值
        String result = optional.orElse("Default Value");
        System.out.println("Result: " + result);
    }
}

2. Lambda表达式

Lambda 表达式是一种匿名函数,它将方法参数、表达式和代码块封装在一个可传递的函数体中,从而实现更加紧凑的代码结构和函数式编程。
通过 Lambda 表达式,可以将函数作为参数传递给其他函数或从其他函数中返回函数。

基本语法

lambda表达式的基本语法如下
(parameter) -> expression
或
(parameter) -> { statements; }
其中,parameter是参数列表,expression是单个表达式,statements是代码块。
代码举例
1.有参数且只有一条语句时
(a,b) -> a + b;

2.只有一个参数时
a  -> a;

3.没有参数时
()  -> System.out.println("java8 lambda");

4.有多条语句时
(a,b) -> {
    int c = a + b;
    return c;
}
lambda表达式重要特征说明:
1. 可选的参数类型声明 : 无需声明参数的类型。编译器可以从参数的值推断出相同的值。
2. 可选的参数周围的小括号():如果只有一个参数,可以忽略参数周围的小括号。但如果有多个参数,则必须添加小括号。
3. 可选的大括号{}:如果 Lambda 表达式只包含一条语句,那么可以省略大括号。但如果有多条语句,则必须添加大括号。
4. 可选的 return 关键字:如果 Lambda 表达式只有一条语句,那么编译器会自动 return 该语句最后的结果。但如果显式使用了 return 语句,则必须添加大括号 {} ,哪怕只有一条语句。
public class LambdaTest1 {
   @Test
    public void test1() {
        //第一种
        Runnable runnable = new Runnable() {
            public void run() {
                System.out.println("不使用Lambda表达式");
            }
        };
        runnable.run();


        //第二种
        Runnable runnable1 = () -> System.out.println("使用Lambda表达式");
        runnable1.run();
    }

  // lambda自动类型推断
  @Test
  public void test2() {
      //第一种:没有使用lambda表达式
      Comparator<Integer> comparator = new Comparator<Integer>() {
          @Override
          public int compare(Integer o1, Integer o2) {
           return o1.compareTo(o2);
          }
      };
      
      //第二种:使用lambda表达式
      Comparator<Integer> comparator2 = (o1,o2)->o1.compareTo(o2);
      System.out.println(comparator2.compare(1,2));
  }
}

3. 函数接口 (Functional Interface)

Functional Interface是指只包含一个抽象方法的接口。可以使用@FunctionalInterface注解来明确标识一个接口是函数式接口,编译器会检查该接口是否符合函数式接口的定义。 Functional Interface是指只包含一个抽象方法的接口。可以使用@FunctionalInterface注解来明确标识一个接口是函数式接口,编译器会检查该接口是否符合函数式接口的定义。
示例:
//自定义函数式接口
@FunctionalInterface
interface MyFunctionalInterface {
    void myMethod();
}

Lambda表达式与Functional Interface

Lambda表达式可以用来实现函数式接口的抽象方法,从而简化代码编写。
示例:
MyFunctionalInterface myFunctionalInterface = () -> System.out.println("Executing myMethod");
myFunctionalInterface.myMethod();

Java内置的Functional Interface

Java 8提供了一些内置的函数式接口,如Supplier、Consumer、Predicate、Function等,用于常见的函数式编程场景.
示例:

// Supplier接口,提供一个值
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
Supplier<String> supplier = () -> "Hello";
System.out.println(supplier.get());

// Consumer接口,消费一个值
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    
    default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (T t) -> { accept(t); after.accept(t); };
    }
}
Consumer<String> consumer = s -> System.out.println("Consuming: " + s);
consumer.accept("Java");

// Predicate接口,判断一个值
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
    
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}
Predicate<Integer> predicate = i -> i > 0;
System.out.println(predicate.test(5));

// Function接口,转换一个值
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
Function<Integer, String> function = i -> "Number: " + i;
System.out.println(function.apply(10));

4. 方法引用

方法引用是一种简化Lambda表达式的语法,可以直接引用已有方法或构造函数,使得代码更加简洁、易读。方法引用,是指如果某个方法签名和接口恰好一致,就可以直接传入方法引用。
方法引用的操作符是双冒号 :: 。常见的有下几种分类:
类型 lambda表达式
类名::静态方法 (args)->ClassName.staticMethod(args)
对象::实例方法 (args)->instance.instanceMethod(args)
类名::实例方法 (arg0,rest)->arg0.instanceMethod(rest)
类名::new 构造器方法

类名::静态方法

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {

    private String name;

    private Integer age;

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

class PersonAgeComparator implements Comparator<Person> {
    public int compare(Person a, Person b) {
        return a.getAge().compareTo(b.getAge());
    }
}

public static void main(String[] args) {
        List<Person> list = Lists.newArrayList();

        // 构造30个对象
        for (int i = 0; i < 30; i++) {
            list.add(new Person(RandomUtil.randomString(6), RandomUtils.nextInt(1,100)));
        }

        // 对list排序
        list.sort(new PersonAgeComparator());

        // 使用lambda改写
        list.sort((a,b)->a.getAge().compareTo(b.getAge()));

        // 使用Person的静态方法
        list.sort((a,b)->{Person.compareByAge(a,b)});

        // 使用静态方法引用
        list.sort(Person::compareByAge);

    }

对象::实例方法

Person person = new Person("a",11);
Supplier<Integer> supplier = ()->person.getAge();
System.out.println(supplier.get());


Person person1 = new Person("b",22);
Supplier<Integer> supplier1 = person1::getAge;
System.out.println(supplier1.get());

类名::实例方法

//第一种: 规则 第一个参数是方法的调用者,第二个参数是方法的参数
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp = String::equals;
System.out.println(bp.test("a","b"));  //输出 false
System.out.println(bp.test("a","a"));  //输出 true


//第二种: 特定类型的任意对象的实例方法
List<String> strings = Arrays.asList("a", "b", "c");
// 使用lambda表达式
List<String> upperCaseStrings = strings.stream().map(s -> s.toUpperCase()).collect(Collectors.toList());
// 使用方法引用
List<String> upperCaseStrings = strings.stream().map(String::toUpperCase).collect(Collectors.toList());

构造器引用

// 构造器引用适用于lambda表达式主体中仅仅调用了某个类的构造函数返回实例的场景

// 使用lambda表达式
Supplier<List<String>> supplier = () ->new ArrayList<String>();
// 使用方法引用
Supplier<List<String>> supplier = ArrayList<String>::new;

5. Stream

Stream是一系列元素的集合,它支持各种操作,如过滤、映射、排序等。通过Stream,可以更方便地对集合进行处理,而无需显式地使用循环。

Stream常用操作

中间操作

中间操作允许对Stream进行各种转换和处理,例如过滤、映射、排序等。常见的中间操作包括:
  1. filter(Predicate): 过滤符合条件的元素
  2. map(Function): 对每个元素进行映射
  3. sorted(): 对元素进行排序
  4. distinct(): 去除重复元素

终端操作

终端操作会触发Stream的处理并生成最终结果。常见的终端操作包括:
  1. forEach(Consumer): 对每个元素执行操作
  2. collect(Collectors): 将Stream转换为集合或其他数据结构
  3. count(): 计算元素个数

示例

下面是一个简单的示例,演示了如何使用Stream对集合进行操作
List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");

// 过滤长度大于5的水果,并转换为大写
List<String> result = fruits.stream()
                            .filter(fruit -> fruit.length() > 5)
                            .map(String::toUpperCase)
                            .collect(Collectors.toList());

System.out.println(result); // 输出: [BANANA, CHERRY]

6. Collectors

在Java 8中,Collectors是用于对Stream进行汇总操作的工具类。Collectors提供了丰富的汇总操作,例如将Stream元素收集到集合中、对元素进行分组、分区等

常用的Collectors操作

将Stream元素收集到集合中

可以使用Collectors.toList()、Collectors.toSet()等方法将Stream元素收集到List或Set中。例如
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());

对元素进行分组

List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");

// 将水果按长度分组
Map<Integer, List<String>> groupedByLength = fruits.stream()
        .collect(Collectors.groupingBy(s->s.length));

System.out.println(groupedByLength); // 输出: {5=[apple, cherry], 6=[banana], 4=[date]}

汇总统计信息

可以使用Collectors.summarizingInt(), Collectors.summarizingDouble(), Collectors.summarizingLong()等方法对元素进行汇总统计。例如,统计水果名称长度的汇总信息:
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
        IntSummaryStatistics stats = fruits.stream().collect(Collectors.summarizingInt(String::length));
        System.out.println(stats.toString());
        //输出:IntSummaryStatistics{count=4, sum=21, min=4, average=5.250000, max=6}

项目中案例

package com.wanli.hdip.base.utils;

import lombok.Data;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * desc 通用树的构建
 *
 * @author lvhangfei
 * @create 2023/5/27
 */
public class TreeProcessor<K extends TreeProcessor.Node> {

    @Data
    public static class Node<T> {
        private T id;
        private T parentId;
        private List<? extends Node> children;
        private Boolean hasChildren;
    }

    /**
     * 获取整棵树  可以有多个root(树根)
     *
     * @param nodes      所有节点
     * @param from       获取跟节点,不同业务根节点获取不同
     * @param end        设置截止条件
     * @param consumer   节点处理
     * @param comparator 排序
     * @return
     */
    public List<K> getTree(List<K> nodes, Predicate<K> from, Predicate<K> end, Consumer<K> consumer, Comparator<K> comparator) {
        //获取根节点
        List<K> roots = nodes.stream().filter(from).collect(Collectors.toList());
        buildTree(nodes, roots, end, consumer, comparator);
        return roots;
    }

    /**
     * 构建树
     *
     * @param nodes      所有树节点
     * @param roots      根节点(多个)
     * @param predicate  设置截止条件,若为null,则每个节点递归到结束为止
     * @param consumer   节点处理
     * @param comparator 排序
     */
    private void buildTree(List<K> nodes, List<K> roots, Predicate<K> predicate, Consumer<K> consumer, Comparator<K> comparator) {
        roots.forEach(root -> {
            if (Objects.nonNull(predicate) && predicate.test(root)) {
                return;
            }
            List<K> children = nodes.stream().filter(node -> Objects.nonNull(node.getParentId()) && node.getParentId().equals(root.getId())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(children)) {
                root.setChildren(children);
                root.setHasChildren(true);
                buildTree(nodes, children, predicate, consumer, comparator);
            } else {
                root.setChildren(new ArrayList<>());
                root.setHasChildren(false);
            }
            if (Objects.nonNull(consumer)) {
                consumer.accept(root);
            }
        });
        if (Objects.nonNull(comparator)) {
            roots.sort(comparator);
        }
    }

    /**
     * 扁平化处理,按照父子顺序
     *
     * @param nodes
     * @param resultList
     */
    public void flatList(List<K> nodes, List<K> resultList) {
        nodes.forEach(item -> {
            resultList.add(item);
            if (item.getHasChildren()) {
                flatList(item.getChildren(), resultList);
            }
            item.setChildren(new ArrayList<>());
        });
    }
}

List<OrganizeModel> tree = new TreeProcessor<OrganizeModel>()
        .getTree(organizeModels, o -> o.getParentId().equals(null), null, null, Comparator.comparing(OrganizeModel::getSortAll))

参考资料

  1. https://blog.csdn.net/qq_39939541/article/details/131649546
  2. https://www.liaoxuefeng.com/wiki/1252599548343744/1255943847278976
  3. https://zhuanlan.zhihu.com/p/439176814
  4. https://www.cnblogs.com/liuxiaozhi23/p/10880147.html
  5. https://blog.csdn.net/qq_36602071/article/details/126846682
posted @ 2024-06-29 18:11  Net_Fly  阅读(13)  评论(0编辑  收藏  举报