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")); //终结操作
    }


相关文章
|
3天前
|
存储 算法 Java
Java Set因其“无重复”特性在集合框架中独树一帜
【10月更文挑战第14天】Java Set因其“无重复”特性在集合框架中独树一帜。本文深入解析Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定的数据结构(哈希表、红黑树)确保元素唯一性,并提供最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的`hashCode()`与`equals()`方法。
14 3
|
1天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
9 3
|
1天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
7 2
|
1天前
|
Java 开发者
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素。通过哈希表和红黑树两种模式,Set能够高效地识别并拒绝重复元素的入侵,确保集合的纯净。无论是HashSet还是TreeSet,都能在不同的场景下发挥出色的表现,成为开发者手中的利器。
10 2
|
1天前
|
Java
Java Set以其“不重复”的特性,为我们提供了一个高效、简洁的处理唯一性约束数据的方式。
【10月更文挑战第16天】在Java编程中,Set接口确保集合中没有重复元素,每个元素都是独一无二的。HashSet基于哈希表实现,提供高效的添加、删除和查找操作;TreeSet则基于红黑树实现,不仅去重还能自动排序。通过这两个实现类,我们可以轻松处理需要唯一性约束的数据,提升代码质量和效率。
9 2
|
3天前
|
存储 Java 数据处理
在Java集合框架中,Set接口以其独特的“不重复”特性脱颖而出
【10月更文挑战第14天】在Java集合框架中,Set接口以其独特的“不重复”特性脱颖而出。本文通过两个案例展示了Set的实用性和高效性:快速去重和高效查找。通过将列表转换为HashSet,可以轻松实现去重;而Set的contains方法则提供了快速的元素查找功能。这些特性使Set成为处理大量数据时的利器。
12 4
|
4天前
|
存储 Java 数据处理
Java中的Set接口以其独特的“不重复”特性,在集合框架中占据重要地位。
【10月更文挑战第13天】Java中的Set接口以其独特的“不重复”特性,在集合框架中占据重要地位。本文通过两个案例展示了Set的实用性和高效性:快速去重和高效查找。通过将列表转换为HashSet,可以轻松实现去重;而Set的contains方法则提供了高效的元素查找功能。这些特性使Set在处理大量数据时表现出色,值得我们在日常编程中充分利用。
17 3
|
4天前
|
安全 Java UED
Java中的多线程编程:从基础到实践
本文深入探讨了Java中的多线程编程,包括线程的创建、生命周期管理以及同步机制。通过实例展示了如何使用Thread类和Runnable接口来创建线程,讨论了线程安全问题及解决策略,如使用synchronized关键字和ReentrantLock类。文章还涵盖了线程间通信的方式,包括wait()、notify()和notifyAll()方法,以及如何避免死锁。此外,还介绍了高级并发工具如CountDownLatch和CyclicBarrier的使用方法。通过综合运用这些技术,可以有效提高多线程程序的性能和可靠性。
|
4天前
|
缓存 Java UED
Java中的多线程编程:从基础到实践
【10月更文挑战第13天】 Java作为一门跨平台的编程语言,其强大的多线程能力一直是其核心优势之一。本文将从最基础的概念讲起,逐步深入探讨Java多线程的实现方式及其应用场景,通过实例讲解帮助读者更好地理解和应用这一技术。
22 3
|
8天前
|
Java 调度 UED
深入理解Java中的多线程与并发机制
本文将详细探讨Java中多线程的概念、实现方式及并发机制,包括线程的生命周期、同步与锁机制以及高级并发工具。通过实例代码演示,帮助读者理解如何在Java中有效地处理多线程和并发问题,提高程序的性能和响应能力。