【Java基础】JDK8新特性最佳实践2

简介: 【Java基础】JDK8新特性最佳实践2

6.函数式编程

6.1.Java8内置的四大函数式接口

 ·Lambda表达式必须先定义接口,创建相关方法之后可使用,这样做十分不方便,java8已经内置了许多接口,例如下面四个功能性接口,所以一般很少会由用户去定义新的函数时接口。

· java8的最大特性就是函数式接口,所有标注了@FunctionalInterface注解的接口都是函数式接口。

Consumer<T>:消费型接口,有入参,无返回值。
    void accept(T t);
Supplier<T>:供给型接口,无入参,有返回值。
    T get();
Function<T,R>:函数型接口,有入参,无返回值
    R apply(T t);
Predicate<T>:断言型接口,有入参,有返回值,返回值类型确定是boolean
    boolean test(T t);

6.2.函数式编程Function

  • ·Function
  • o  传入一个值经过函数的计算返回另一个值
  • o  T:入参类型,R:出参类型
@FunctionalInterface
public interface Function<T, R> {    
    /**     
     * Applies this function to the given argument.     
     * @param t the function argument     
     * @return the function result    
     */    
    R apply(T t);
}
  • ·作用:将转换后逻辑提取出来,解耦合
public class FunctionObj implements Function {
    @Override
    public Object apply(Object o) {
        return o+":apply处理";
    }
}
public static void main(String[] args) {
     Object lixiang = apply("lixiang", new FunctionObj());
     System.out.println(lixiang);
}
public static Object apply(String o,FunctionObj obj){
     return obj.apply(o);
}

800dbb1ec1bc4f288f77a3bb12d9ea66.jpeg

6.3.函数式编程BiFunction

  • ·BiFunction Function只能接受一个参数,如果要传递两个参数,则用BiFunction。
@FunctionalInterface
public interface BiFunction<T,U,R>{
    R apply(T t,U u);
}
public static void main(String[] args) {  
    System.out.println(operator(10,21,(a,b)->a+b));   
    System.out.println(operator(10,2,(a,b)->a-b)); 
    System.out.println(operator(8,4,(a,b)->a*b)); 
    System.out.println(operator(10,2,(a,b)->a/b)); 
}    
public static Integer operator(Integer a, Integer b, BiFunction<Integer,Integer, Integer> bf) {       
    return bf.apply(a, b);   
}

69d43bf3de7849b0908ef65f9d067eb1.jpeg

6.4.函数式编程Consumer

  • ·Consumer消费型接口:有入参,无返回值
  • ·将 T 作为输入,不反回任何内容
  • o调用方法:void accept(T t);
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
  • ·用途:因为没有出参常用于打印,发送短信等消费动作
    public static void main(String[] args) {
        sendMessage("11111111",phone -> System.out.println(phone+"已经被发送"));
    }
    public static void sendMessage(String phone, Consumer<String> consumer){
        consumer.accept(phone);
    }

9eb5a2d4767f4b448d78538015bd82f1.jpeg

6.5.函数式编程Supplier

  • ·Supplier:供给型接口:无入参,有返回值
  • ·T:出参类型
  • o调用方法:T get();
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
  • ·用途:泛型一定和方法的返回值是一种类型,如果需要获得一个数据,并且不需要传入参数,可以使用Supplier接口,例如无参的工厂方法。
    public static void main(String[] args) {
        Student student = newStudent();
        System.out.println(student);
    }
    public static Student newStudent(){
        Supplier<Student> supplier=()-> new Student("lixiang",20);
        return supplier.get();
    }

0fde1be85f234991ac9efdd312d21362.jpeg

6.6.函数式编程Predicate

  • ·Predicate:断言型接口:有入参,有出参,返回值类型是boolean
  • ·T:入参类型,出餐类型是Boolean
  • ·调用方法:boolean test(T t)
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}  
  • ·用途:接收一个参数,用于判断是否满足一定的条件过滤数据
public static void main(String[] args) {
        List<String> list = Arrays.asList("awewrwe","vdssdsd","aoooo","psdddsd");
        List<String> results = filter(list, obj -> obj.startsWith("a"));
        System.out.println(results);
    }
    public static List<String> filter(List<String> list,Predicate<String> predicate){
        List<String> results = new ArrayList<>();
        for (String s : list) {
            if(predicate.test(s)){
                results.add(s);
            }
        }
        return results;
    }

32878c019df74991ae4971a408757aa7.jpeg

6.7.方法与构造方法引用

  • ·以前调用方法:对象.方法名(),类名.方法名()
  • ·JDK8提供了另外一种方式 :: (双冒号)
方法引用是一种更简洁易懂的lambda表达式,操作符是双冒号::,用来直接访问类或者实例已经存在的方法或者构造方法。
通过语法引用,可以将方法的引用赋值给一个变量
语法:左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名
静态方法:ClassName::methodName
实例方法:Instance::methodName
构造函数:类名::new
单个参数
Function<入参1,返回类型> func = 方法引用
应用 func.apply(݇入参);
两个参数
BiFunction<݇入参1, 入参2> func = 方法引用
应用 func.apply(入参1,入参2);

测试调用

public static void main(String[] args) {
        //静态方法的调用
        Function<String,Integer> function1 =  Integer::parseInt;
        Integer num = function1.apply("1024");
        System.out.println("转化后:"+num);
        //实例方法的调用
        String context = "lixiang";
        Function<Integer,String> function2 = context::substring;
        String str = function2.apply(1);
        System.out.println("截取后的字符串:"+str);
        //构造方法的调用,双参数
        BiFunction<String,Integer,Student> function3 = Student::new;
        Student lixiang = function3.apply("lixiang", 20);
        System.out.println(lixiang);
        //构造方法的调用,单个参数
        Function<String,Student> function4 = Student::new;
        Student lisi = function4.apply("lisi");
        System.out.println(lisi);
        //函数作为参数传递到另一个方法中
        String sayHello = sayHello(String::toUpperCase, "lixiang");
        System.out.println(sayHello);
    }
    public static String sayHello(Function<String,String> function,String str){
        String apply = function.apply(str);
        return apply;
    }

ed6f65a38f4f44e28bfaf1028d36b6e7.jpeg

7.Stream流式操作集合框架

7.1.Stream简介

(1)什么是stream

Stream中文称为"流",通过将集合转化为这么一种叫做流的元素队列,通过声明性方式,能够对集合中的每一个元素进行一些列并行或穿行的流水线操作。
元素是特定类型的对象,所以元素集合看作一种流,流在管道中传输,且可以在管道的节点上进行处理,比如 排序,聚合,过滤等

96c12e6a2d4443fcb0e09b9863a5041b.jpeg

  • ·操作详情
  • o数据元素就是原始的集合,List、Map、Set等
  • o生成流,可以是串行流stream()或者并行流parallelStream()
  • o中间操作,可以是排序,聚合,过滤,转换等
  • o终端操作,很多流操作本身就会返回一个流,所以多个操作可以直接连接起来,最后统一收集

(2)案例

        List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ");
        List<String> collect = list.stream().map(obj -> obj + "-拼接").collect(Collectors.toList());
        for (String s : collect) {
            System.out.println(s);
        }

e9ec04c62d4b4b70ac38871c2955f6db.jpeg

7.2.map和filter函数

(1)map函数

  • ·将流中的每一个元素T映射成R(类似类型转换)
  • ·应用场景:转换对象,类似DO对象转换成DTO对象
  • ·map函数源码

dc7608469df1404cb4fd7080c236683e.jpeg

  • ·测试
    public static void main(String[] args) {
        List<User> users = Arrays.asList(
                new User(1, "小东", "123"),
                new User(2, "小李", "123"),
                new User(3, "小王", "123"),
                new User(4, "小张", "123"));
        List<UserDTO> collect = users.stream().map(user -> {
            UserDTO userDTO = new UserDTO();
            userDTO.setUserId(user.getId());
            userDTO.setUsername(user.getName());
            return userDTO;
        }).collect(Collectors.toList());
        for (UserDTO userDTO : collect) {
            System.out.println(userDTO);
        }
    }

0b1c92f76a18417a807f323d575cf237.jpeg

(2)filter函数

  • ·用于通过设置的条件过滤出元素
  • ·应用场景:过滤出符合条件的元素
  • ·filter函数源码

a95430801c6c41fba4ef852d21d750c0.jpeg

  • ·测试
 List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ","JUC");
//filter
List<String> collect5 = list.stream().filter(str -> str.length() > 4).collect(Collectors.toList());
System.out.println(collect5);

f4c88e940fbb495184720ec282d50c8f.jpeg

7.3.sorted和limit函数

(1)sorted函数

  • ·sorted()对流进行自然的排序,其中的元素必须实现Comparable接口
  • ·应用场景:需要对集合的元素进行定制化排序
  • ·sorted源码

4261204b959a481795b30b86c5185925.jpeg

  • ·测试
//排序,sort(),默认升序
List<String> collect1 = list.stream().sorted().collect(Collectors.toList());
System.out.println("sort()按照英文字母升序:"+collect1);
//根据长度排序,默认升序
List<String> collect2 = list.stream().sorted(Comparator.comparing(obj -> obj.length())).collect(Collectors.toList());
System.out.println("sort()按照英文字母的长度升序:"+collect2);
//根据长度排序,降序
List<String> collect3 = list.stream().sorted(Comparator.comparing(obj -> obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());
System.out.println("sort()按照英文字母的长度降序:"+collect3);

d44e9e6758634745aef3b65c8e7855c6.jpeg

(2)limit函数

  • ·limit()截断流使其最多包含指定的数量的元素
  • ·应用场景:排行榜,截取前多少名
  • ·limit源码

ba27e538ecdb428d81300e3d667207b2.jpeg

  • ·测试
//根据长度排序,降序,截取前三个
List<String> collect4 = list.stream()
       .sorted(Comparator.comparing(String::length,Comparator.reverseOrder())).limit(3)
       .collect(Collectors.toList());
System.out.println(collect4);

0a93b68672fe47cdbf318c164f525b44.jpeg

1f6f25b5d9b6480b9940e0dab1d44f18.jpeg

7.4.allMatch和anyMatch函数

(1)allMatch函数

  • ·检查是否匹配所有元素,主有全部符合才返回true
  • ·allMatch源码

13675347819a4c148213e4b2b008c340.jpeg

  • ·测试
List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ","Netty","JUC","Docker");
boolean allFlag = list.stream().allMatch(str -> str.length()>5);
System.out.println("allFlag全部满足返回true:"+allFlag);

a571bf20d6f947108a6ec6f75a3930cd.jpeg

(2)anyMatch函数

  • ·检查是否匹配所有元素,主有全部符合才返回true
  • ·anyMatch源码

385763edfabf4ed6a76b1c7be6136008.jpeg

  • ·测试
List<String> list = Arrays.asList("SpringBoot", "SpringCloud", "Redis", "RabbitMQ","Netty","JUC","Docker");
boolean allFlag = list.stream().anyMatch(str -> str.length()>5);
System.out.println("allFlag全部满足返回true:"+allFlag);

17afbc3354e94758ac97a8dc323f03b6.jpeg

7.4.max和min函数

(1)max函数

  • ·获取集合元素中的最大值
  • ·max源码

1df6dab753364e21b9efd6608dde5aca.jpeg

  • ·测试
Optional<Student> max = list.stream().max(Comparator.comparingInt(Student::getAge));
if (max.isPresent()){
    System.out.println("最大年龄:"+max.get().getAge());
}

7da0bf35f48d42de988afd2b36330a4e.jpeg

(2)min函数

  • ·获取集合中的最小值
  • ·min源码

6eb5557904bc476894b953d009196eb1.jpeg

  • ·测试
Optional<Student> min = list.stream().min((student1, student2) -> {
     return Integer.compare(student1.getAge(), student2.getAge());
});
if(min.isPresent()){
     System.out.println("最小年龄:"+min.get().getAge());
}

ef26f25357ed4a7ea205f956f517d21c.jpeg

7.5.并行流parallelStream

  • ·为什么会有这个并行流
  • o 集合做重复的操作,如果使用串行执行会相当耗时,因此一般会采用多线程来加快,Java8的paralleStream用fork/join框架提供了并发执行能力
  • o底层原理
  • ·线程池(ForkJoinPool)维护一个线程队列
  • ·可以分割任务,将父任务拆分成子任务,完全贴合分治思想
  • ·fork/join框架

17b0a5d90129486a8c701cca75cac74c.jpeg

  • ·两个区别
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//串行流
System.out.print("串行流:");
numbers.stream().forEach(num -> System.out.print(num+" "));
System.out.println();
//并行流
System.out.print("并行流:");
numbers.parallelStream().forEach(num -> System.out.print(num+" "));

0a589df65c264b8c81c8a1c99987eedc.jpeg

  • ·存在问题
  • ·parallelStream并行是否一定比Sream串行快?
  • o 错误,数据量少的情况,可能串行更快,ForkJoin会耗性能


  • ·多数情况下并行比串行块,是否可以都用并行
  •    o 不行,部分情况会线程安全问题,parallelStream里面使用的外部变量,比如集合一定要使用线程  安全集合,不然就会引用多线程安全问题
for (int i = 0; i < 10; i++) {
    //List<Integer> list = new ArrayList<>();
    CopyOnWriteArrayList list = new CopyOnWriteArrayList();
    IntStream.range(1,100).parallel().forEach(list::add);
    System.out.println(list.size());
}

52afd69003734277a1278a30fd549a31.jpeg

7.6.reduce函数

  • ·什么是reduce操作
  • o聚合操作,中文意思是“减少”
  • o根据一定的规则将Stream中的元素进行计算后返回一个唯一的值
  • o源码分析

124612b8690e4bbc94d376c2b42da0be.jpeg

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
//将集合内的元素相加
Integer integer = list.stream().reduce((x, y) -> x + y).get();
System.out.println("集合内元素相加:"+integer);
//初始值100,将集合内的元素相加
Integer integer1 = list.stream().reduce(100,(x,y) -> x+y);
System.out.println("100累加集合内的元素:"+integer1);
//判断最大值返回
Integer integer2 = list.stream().reduce((x, y) -> x > y ? x : y).get();
System.out.println("集合内最大元素:"+integer2);

fdd11e0f9be04197904b028ae525156c.jpeg

7.7.集合foreach

  • ·集合遍历方式
  • ofor循环
  • o迭代器Iterator
  • ·源码分析

72cdeb0dfe6f4c8396e2bc177319294c.jpeg

  • ·JDK8里面的新增接口
List<Student> result = Arrays.asList(new Student(32),new Student(33),new Student(21),new Student(29),new Student(18));
result.forEach(obj -> System.out.println(obj.getAge()));

a718385f012749f19dc11908f51656c4.jpeg

  • ·注意点:
  • o不能修改包含外部的变量的值
  • o不能用break或者return或者continue等关键词结束或者跳出循环



相关文章
|
3月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
Java API 开发者
116 0
|
4月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
338 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
|
5月前
|
Oracle Java 关系型数据库
新手必看:Java 开发环境搭建之 JDK 与 Maven
本文分享了 Java 学习中 JDK 安装配置与 Maven 使用的入门知识,涵盖 JDK 下载安装、环境变量设置、Maven 安装配置及本地仓库与镜像设置,帮助新手快速搭建 Java 开发环境。
558 0
|
5月前
|
并行计算 Java API
Java List 集合结合 Java 17 新特性与现代开发实践的深度解析及实战指南 Java List 集合
本文深入解析Java 17中List集合的现代用法,结合函数式编程、Stream API、密封类、模式匹配等新特性,通过实操案例讲解数据处理、并行计算、响应式编程等场景下的高级应用,帮助开发者提升集合操作效率与代码质量。
246 1
|
5月前
|
安全 Java 微服务
Java 最新技术和框架实操:涵盖 JDK 21 新特性与 Spring Security 6.x 安全框架搭建
本文系统整理了Java最新技术与主流框架实操内容,涵盖Java 17+新特性(如模式匹配、文本块、记录类)、Spring Boot 3微服务开发、响应式编程(WebFlux)、容器化部署(Docker+K8s)、测试与CI/CD实践,附完整代码示例和学习资源推荐,助你构建现代Java全栈开发能力。
616 0
|
5月前
|
缓存 安全 Java
Java 并发新特性实战教程之核心特性详解与项目实战
本教程深入解析Java 8至Java 19并发编程新特性,涵盖CompletableFuture异步编程、StampedLock读写锁、Flow API响应式流、VarHandle内存访问及结构化并发等核心技术。结合电商订单处理、缓存系统、实时数据流、高性能计数器与用户资料聚合等实战案例,帮助开发者高效构建高并发、低延迟、易维护的Java应用。适合中高级Java开发者提升并发编程能力。
165 0
|
Java 测试技术
Java特性组合的通用方案
Java特性组合的通用方案
328 0
|
2月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
189 1
|
2月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
213 1