Java SE : java8新特性(中)

简介: Java SE : java8新特性(中)

9.3 案例三

使用Lambda表达式给Supplier接口的变量赋值,实现产生1个100以内的整数功能。

代码演示如下:

@Test
public void test10(){
    //使用Lambda表达式给Supplier接口的变量赋值,实现产生1个100以内的整数功能。
    Supplier<Integer> s= ()-> new Random().nextInt(100);
    System.out.println(s);//打印s是得不到这个随机数值的
    System.out.println(s.get());//通过调用s.get()得到随机数值
}

9.4 案例四

声明一个Employee员工类型,包含属性编号、姓名、薪资,属性私有化,提供有参构造,get/set,重写toString.

添加n个员工对象到一个HashMap<lnteger,Employee>集合中,其中员工编号为key,员工对象为value。

调用Map的forEach遍历集合

调用Map的replaceAll方法,将其中薪资低于10000元的,薪资设置为10000。

再次调用Map的forEach遍历集合查看结果

代码演示如下:

public class Employee {
    private int id;
    private String name;
    private int salary;
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                '}';
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
    public Employee(int id, String name, int salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }
}
@Test
public void test11(){
    HashMap<Integer,Employee> map=new HashMap<>();
    Employee e1=new Employee(1,"张三",6700);
    Employee e2=new Employee(2,"李四",9700);
    Employee e3=new Employee(3,"王五",16000);
    Employee e4=new Employee(4,"赵六",27000);
    map.put(e1.getId(),e1);
    map.put(e2.getId(),e2);
    map.put(e3.getId(),e3);
    map.put(e4.getId(),e4);
    map.forEach((key,value)-> System.out.println(map.get(key)));
    System.out.println("--------------------------------------");
    map.replaceAll((key,value)-> {
        if (map.get(key).getSalary()<10000){
            map.get(key).setSalary(10000);
        }
        return value;
    });
    map.forEach((key,value)-> System.out.println(map.get(key)));
}


十. 方法引用与构造器引用

10.1 方法引用

10.1.1 什么是方法引用?

它是指一种新的语法格式:

类名 :: 方法名

对象名 :: 方法名

10.1.2 方法引用用在哪里?

作用: 方法引用是用于简化Lambda表达式的语法。

10.1.3 方法引用可使用的情况

注意:

不是所有的Lambda表达式都可以用方法引用进行简化的,只有满足以下情况时,才能用它进行简化:

1)Lambda体只有一个语句并且这个语句是通过调用一个现有的类或对象的方法来完成的

并且在调用方法时,所使用的实参正好时Lambda表达式的形参,整个使用过程中,没有额外的数据出现。

代码演示如下:

@Test
public void test12(){
    ArrayList<String> list=new ArrayList<>();
    list.add("jack");
    list.add("hello");
    list.add("rose");
    list.add("tom");
    list.forEach(t -> System.out.println(t));//使用lambda进行遍历,可进行方法引用以简化
    list.forEach(t -> System.out.println(t+"\t"));//不能根据这个lambda进行方法引用
    System.out.println("--------------------------");
    list.forEach(System.out:: println );//使用方法引用
}

(2) Lambda体只有一个语句,并且这个语句是通过调用一个现有的对象的方法来完成的。

此时调用方法的对象是Lambda表达式的第一个形参,并且Lambda表达式的剩下的形参,正好作为该方法的实参,

整个使用过程中,没有额外的数据出现

代码演示如下:

@Test
public void test13(){
    String[] arr = {"hello","Bob","Rose","java","chai"};
    Arrays.sort(arr, (o1,o2) -> o1.compareToIgnoreCase(o2) );
    for (String s : arr) {
        System.out.println(s);
    }
    System.out.println("-----------------------");
    String[] arr1 = {"hello","Bob","Rose","java","chai"};
    Arrays.sort(arr1, String::compareToIgnoreCase );
    for (String s : arr) {
        System.out.println(s);
    }
}

10.2 构造器引用

当Lambda表达式是一个创建对象的表达式,即Lambda体是一个new表达式,而且 所有构造器的实参,都是Lambda表达式的形参,那么此时就可以使用构造器引用。

语法格式:

类名 :: new

代码演示如下:

@Test
    public void test14(){
/*        功能型接口Function<T,R>,有一个抽象方法 R apply(T t)
        希望它通过某个字符串,作为Person对象的name值,创建一个Person对象*/
//        Function<String,Person> fun= s -> new Person(s);
        Function<String,Person> fun= Person::new;
        String[] names={"jack","rose","tom"};
        //根据names的字符串,创建一个Person数组
        Person[] people=new Person[names.length];
        for (int i = 0; i < names.length ; i++) {
            people[i]=fun.apply(names[i]);
        }
        for (Person person : people) {
            System.out.println(person);
        }
    }

10.3 数组引用

当Lambda表达式是创建一个数组对象,并且满足Lambda表达式形参正好是给创建这个数组对象的长度,就可以数组构造引用

语法格式:

数组类型名: :new

代码演示如下:

@Test
    public void test15(){
/*        如果使用Lambda表达式给一个Function接口的变量赋值
        需求: 给定一个长度,你返回一个对应长度的String[]数组给我*
        功能型接口Function<T,R>  有一个抽象方法 R apply(T t)
        形参的类型: Integer
        返回值类型: String[]*/
//        Function<Integer,String[]> fun=l -> new String[l];
        Function<Integer,String[]> fun= String[]::new;
        String[] str=fun.apply(5);
        for (String s : str) {
            System.out.print(s+"\t");
        }
    }


十一. Stream API

11.1 stream是什么?

stream这个单词,在之前IO流的文章就提到过。在在IO流中是代表一个字节输入流或一个字节输出流,它是用于数据的传输的今天讲的这个stream也是代表一个数据流,但是这个数据流和之前的IO流是有区别的;

今天说的stream它是指用于数据“加工”的一套流程。例如:数据的过滤、数据的统计、数据的迭代、数据的修改、删除、查询筛选等

stream本身是不存储数据的,存储数据的是数组、集合这样的容器。

11.2 特点

(1) stream本身是不存储数据的

(2) stream每一次加工处理都会产生一个新的stream对象

代码演示如下:

@Test
    public void test16(){
        ArrayList<String> list=new ArrayList<>();
        list.add("jack");
        list.add("option");
        list.add("java");
        list.add("world");
        list.add("h5");
        //1)创建stream
        //通过集合创建Stream
        Stream<String> stream = list.stream();
     /*   stream.filter(new Predicate<String>() { //Predicate接口为判断式,可使用lambda
            @Override
            public boolean test(String s) {
                return s.contains("o");
            }
        });*/
        //2)中间加工处理
        //筛选含”o“的单词
        //lambda表达式
        Stream<String> o = stream.filter(s -> s.contains("o"));//原先得Steream流stream本身不会存储任何数据且每一次加工处理都会产生一个新的Stream流对象
        //3)终结
        //遍历流中剩余的元素
//        o.forEach(s -> System.out.println(s));
        o.forEach(System.out::println);
        System.out.println("list:"+list);//list:[jack, option, java, world, h5]  不会改变源数据
    }

(3) stream的中间处理/加工操作会被延迟,一直要到最后取结果的“终结作”才会执行。

不加”终结操作“前后对比:

没加代码演示如下:

@Test
    public void test17(){
        ArrayList<Student> list=new ArrayList<>();
        list.add(new Student("KFC"));
        list.add(new Student("dragon"));
        //1)创建流对象
        Stream<Student> stream = list.stream();
        //2)加工处理
        //peek():peek(Consumer<? super T> action)
        //返回由该流的元素组成的流,另外在从生成的流中消耗元素时对每个元素执行提供的操作。
        Stream<Student> peek = stream.peek(System.out::println);
        //3)终结操作
        //3)没写得时间,前面得代码都没执行
/*
        long nums=peek.count();//统计流中的元素的个数
        //peek.count()有返回值,不是stream,所以它是一个终结操作
        System.out.println(nums);
*/
    }

加了 代码演示如下:

@Test
public void test17(){
    ArrayList<Student> list=new ArrayList<>();
    list.add(new Student("KFC"));
    list.add(new Student("dragon"));
    //1)创建流对象
    Stream<Student> stream = list.stream();
    //2)加工处理
    //peek():peek(Consumer<? super T> action)
    //返回由该流的元素组成的流,另外在从生成的流中消耗元素时对每个元素执行提供的操作。
    Stream<Student> peek = stream.peek(System.out::println);
    //3)终结操作
    //3)没写得时间,前面得代码都没执行
    long nums=peek.count();//统计流中的元素的个数
    //peek.count()有返回值,不是stream,所以它是一个终结操作
    System.out.println(nums);
}

(4) stream的加工处理不会改变的数据源(集合和数组的元素,个数等)

11.3 如何使用stream?

(1) 创建Stream

创建Stream的几种方法:

①通过集合对象.stream

JDK1.8在

ColLection系列集合中增加了方法:default Stream stream()

②通过数组工具类Arrays.stream方法

代码演示如下:

@Test
public void test18(){
    //通过Arrays。stream()创建
    int[] a={1,2,4,5,10};
    IntStream stream = Arrays.stream(a);
}

③Stream接口中有这样的一些静态方法,可以创建

Streamof(T… value) : 有限流

static Stream generate(Supplier s) : 无限流

static Stream iterate(T seed, UnaryOperator f):无限流

代码演示如下:

@Test
public void test19(){
    Stream<String> jack = Stream.of("jack", "hello", "world");
    Stream<Integer> integerStream = Stream.of(1, 3, 5, 2);
}
@Test
    public void test20(){
        //static <T> Stream<T> generate(Supplier<T> s)
        // 返回无限顺序无序流,其中每个元素由提供的Supplier 。 这适合于产生恒定流,随机元素流
        Stream<Double> generate = Stream.generate(Math::random);
        generate.forEach(s -> System.out.println(s));
    }

@Test
    public void test21(){
/*        static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
         返回有序无限连续Stream由函数的迭代应用产生f至初始元素seed ,产生Stream包括seed , f(seed) , f(f(seed)) ,等
        第一元件(位置0在) Stream将是提供seed 。 对于n > 0 ,位置n的元素将是将函数f应用于位置n - 1的元素的n - 1 。
        参数类型
        T - 流元素的类型
        参数
        seed - 初始元素
        f - 要应用于前一个元素以生成新元素的函数
        结果
        一个新的顺序 Stream*/
/*
        Function<T,R>接口抽象方法 R apply(T t);参数的类型和返回值的类型可以不同
        UnaryOperator<T> 接口抽象方法 T apply(T t)参数的类型和返回值的是一样的
*/
        //需求:对每一个元素,进行迭代处理,从第一个元素开始,每次迭代都+2,然后一直在上一次的基础上,不断迭代。
        Stream<Integer> iterate = Stream.iterate(1, t -> t + 2);
        iterate=iterate.peek(t->{  //让流中的数据每隔100ms产生一个
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        iterate.forEach(t-> System.out.println(t));
    }

(2) 中间加工处理

处理方法如下:

代码演示如下:

@Test
public void test22(){
    //过滤所有的偶数
    Stream.of(1,2,3,4,5) //创建流
            .filter(t -> t%2==0)  //中间加工处理
            .forEach(t -> System.out.println(t)); //终结操作
}

@Test
public void test23(){
    //去掉所有的重复数字
    Stream.of(1,2,3,4,5,2,4,6,5,3,1) //创建流
            .distinct()  //中间加工处理
            .forEach(t-> System.out.println(t)); //终结操作
}
 @Test
    public void test23(){
        //去掉所有的重复数字
        Stream.of(1,2,3,4,5,2,4,6,5,3,1) //创建流
                .distinct()  //中间加工处理
                .forEach(t-> System.out.print(t+"\t")); //终结操作
    }


相关文章
|
5月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
|
5月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
929 1
Java API 开发者
175 0
|
7月前
|
并行计算 Java API
Java List 集合结合 Java 17 新特性与现代开发实践的深度解析及实战指南 Java List 集合
本文深入解析Java 17中List集合的现代用法,结合函数式编程、Stream API、密封类、模式匹配等新特性,通过实操案例讲解数据处理、并行计算、响应式编程等场景下的高级应用,帮助开发者提升集合操作效率与代码质量。
343 1
|
7月前
|
安全 Java 微服务
Java 最新技术和框架实操:涵盖 JDK 21 新特性与 Spring Security 6.x 安全框架搭建
本文系统整理了Java最新技术与主流框架实操内容,涵盖Java 17+新特性(如模式匹配、文本块、记录类)、Spring Boot 3微服务开发、响应式编程(WebFlux)、容器化部署(Docker+K8s)、测试与CI/CD实践,附完整代码示例和学习资源推荐,助你构建现代Java全栈开发能力。
834 1
|
7月前
|
缓存 安全 Java
Java 并发新特性实战教程之核心特性详解与项目实战
本教程深入解析Java 8至Java 19并发编程新特性,涵盖CompletableFuture异步编程、StampedLock读写锁、Flow API响应式流、VarHandle内存访问及结构化并发等核心技术。结合电商订单处理、缓存系统、实时数据流、高性能计数器与用户资料聚合等实战案例,帮助开发者高效构建高并发、低延迟、易维护的Java应用。适合中高级Java开发者提升并发编程能力。
291 0
|
7月前
|
安全 Java API
Java 17 及以上版本核心特性在现代开发实践中的深度应用与高效实践方法 Java 开发实践
本项目以“学生成绩管理系统”为例,深入实践Java 17+核心特性与现代开发技术。采用Spring Boot 3.1、WebFlux、R2DBC等构建响应式应用,结合Record类、模式匹配、Stream优化等新特性提升代码质量。涵盖容器化部署(Docker)、自动化测试、性能优化及安全加固,全面展示Java最新技术在实际项目中的应用,助力开发者掌握现代化Java开发方法。
338 1
|
IDE Java 关系型数据库
Java14发布,16大新特性,代码更加简洁明快
Java14发布,16大新特性,代码更加简洁明快
428 0
Java14发布,16大新特性,代码更加简洁明快
|
4月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
263 1
|
4月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
271 1