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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 【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等关键词结束或者跳出循环



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
5天前
|
算法 Java 编译器
深入理解 Java JDK —— 让我们从基础到进阶
JDK(Java Development Kit)是 Java 开发的核心工具包,包含编译、运行和调试 Java 程序所需的所有工具和库。它主要由 JVM(Java 虚拟机)、JRE(Java 运行时环境)和 Java 核心类库组成。JVM 是跨平台运行的基础,负责字节码的加载、执行和内存管理;JRE 提供运行 Java 应用的环境;核心类库则提供了丰富的 API 支持。通过编写、编译和运行一个简单的 Java 程序,可以深入理解 JDK 的工作原理。此外,JDK 还提供了 JIT 编译、垃圾回收优化和并发工具包等高级功能,帮助开发者提高程序性能和稳定性。
60 10
|
1月前
|
存储 Java 开发者
什么是java的Compact Strings特性,什么情况下使用
Java 9引入了紧凑字符串特性,优化了字符串的内存使用。它通过将字符串从UTF-16字符数组改为字节数组存储,根据内容选择更节省内存的编码方式,通常能节省10%至15%的内存。
|
1月前
|
容器
jdk8新特性-详情查看文档
jdk8新特性-详情查看文档
57 7
|
1月前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
84 6
|
2月前
|
Oracle 安全 Java
深入理解Java生态:JDK与JVM的区分与协作
Java作为一种广泛使用的编程语言,其生态中有两个核心组件:JDK(Java Development Kit)和JVM(Java Virtual Machine)。本文将深入探讨这两个组件的区别、联系以及它们在Java开发和运行中的作用。
134 1
|
2月前
|
IDE Java 编译器
开发 Java 程序一定要安装 JDK 吗
开发Java程序通常需要安装JDK(Java Development Kit),因为它包含了编译、运行和调试Java程序所需的各种工具和环境。不过,某些集成开发环境(IDE)可能内置了JDK,或可使用在线Java编辑器,无需单独安装。
117 1
|
2月前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
45 4
|
3月前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
149 3
|
3月前
|
Java Spring 数据库连接
[Java]代理模式
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
62 0
[Java]代理模式
|
3月前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
35 2