day25_新特性

news2024/11/18 1:22:22

今日内容

零、 复习昨日
一、JDK8新特性介绍
二、接口新特性
三、Lambda表达式
四、函数式接口
五、Stream流
六、新日期API

零、 复习昨日

晨考

一、JDK8新特性

  • 接口中默认方法+静态方法 − 默认方法就是一个在接口里面有了一个实现的方法。静态方法就是接口中有个已经使用的静态方法,可直接调用

  • Lambda 表达式(拉姆达) − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。

  • 方法引用 (Method Reference)− 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

    // 方法引用的代码
    System.out.println() ---> System::println();
    
  • Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

  • Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。

  • Date Time API − 加强对日期与时间的处理。

二、关于接口的新特性

JDK8以后,允许接口中有被default和static修饰的方法带方法体

package com.qf.new_;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public interface Demo1_Interface {

    // 默认方式
    public abstract void m1();

    // JDK8以后,允许被default修饰的方法带方法体
    // 子实现类可以重写,子类对象也可以调用
    // 场景1:大型项目中某一接口有很多实现类,如果在接口中设置了一个抽象方法,那么所有子类必须全部重写这个方法
    // 影响较大,设计了default后,方法带方法体,那么对子实现类来说是无感的,子类就可以自己有选择的重写这些方法

    // 场景2: 该方法确实是所有子类都可以使用的方法,那就定义在父接口中,子类直接调用
    public default void m2(){
        System.out.println("m2..带方法体" );
    }

    public default void m3(){
        System.out.println("m3..带方法体" );
    }

    // JDK8以后,允许被static修饰的方法带方法体
    // 该静态方法,子实现类不能重写不能调用,只能可以通过接口名直接调用
    public static void m5(){
        System.out.println("m5()" );
    }

}

public class Demo1InterfaceImpl implements Demo1_Interface{

    @Override
    public void m1() {
        System.out.println("m1()被重写" );
    }

    @Override
    public void m3() {

    }

    public static void main(String[] args) {
        Demo1InterfaceImpl d1 = new Demo1InterfaceImpl( );
        d1.m1();
        d1.m2();
        d1.m2();

        Demo1_Interface.m5();
    }
}

三、Lambda表达式[重要]

Lambda 允许把函数(方法)作为一个方法的参数(函数作为参数传递到方法中)。


其实就是简化了匿名内部类的写法

3.1 初识lambda

package com.qf.jdk.lambda;

public class Demo1Lambda {

    public static void main(String[] args) {
        // 1 之前使用匿名内部类,开启线程
        new Thread(new Runnable( ) {
            @Override
            public void run() {
                System.out.println("匿名内部类开启线程" );
            }
        }).start();

        // 以上代码,主要关注的是线程的执行任务,即run()内部的代码

        // 2 换成lambda后
        new Thread(() -> System.out.println("lambda开启线程" )).start();

        // lambda基本结构是
        // () -> 语句
        // 参数列表,箭头符号,执行语句
    }
}

3.2 语法特点

能够使用lambda的前提是

  1. 方法得有参数
  2. 参数的必须是接口
  3. 接口中的方法有且只能有一个!!!
总结: lambda就是对接口的抽象方法重写实现

new Thread(Runable run) Thread构造方法有参数

参数Runnable是接口

且Runnable接口内只有一个方法run


语法特征

(参数) -> {执行语句}
或者
参数  -> 执行语句
  • 参数圆括号,当参数是一个的时候,圆括号可加可不加

    • (x) -> System.out.println(x)
    • x -> System.out.println(x)
  • 参数圆括号,当参数是多个的时候,圆括号必须加

    • (x,y) -> System.out.println(x+y)
  • 参数数据类型可写可不写,编译时会自动推断是什么类型

    • (x,y) -> System.out.println(x+y)
    • (int x,String y) -> System.out.println(x+y)
  • 执行语句的花括号,当且仅当执行语句只有一句时,可以不加花括号

    • new Thread(() -> System.out.println("匿名内部类开启线程")).start();
      
  • 执行语句的花括号,当执行语句不只一句时,必须加花括号

    • new Thread(() -> {
               int a = 1;
               a++;
               System.out.println("lambda开启线程" );
           }).start();
      
  • 关于返回值

    • 如果方法有返回值,且执行语句只有一行语句时,可以不用写return,直接写值

      test(() -> 1);
      test(() -> return 1);
      
    • 如果代码比较多,又要返回数据,就必须写上return

      test(() -> {
      	int a = 1;
      	a++;
      	return a;
      });
      
public interface MyInterface {
    void m1(); // 无参无返回值
}
public interface MyInterface2 {
    void m1(int a); // 有参无返回值
}
public interface MyInterface3 {
    void m1(int a,String b);// 有2个参数
}
public interface MyInterface4 {
    int m1();
}
public class Demo3_lambda {
   // 总结: lambda就是对接口的抽象方法重写实现
   //      其实就是简化了匿名内部类的写法
    public static void main(String[] args) {
        // 先使用匿名内部类完成
        show(new MyInterface( ) {
            @Override
            public void m1() {
                System.out.println("m1执行了" );
            }
        });
		// 改造成lambda
        show(() -> System.out.println("m1执行力..." ));

        show2(new MyInterface2( ) {
            @Override
            public void m1(int a) {
                System.out.println(a );
            }
        });

        show2((int a) -> System.out.println(a ));
        // 当只有一个参数时,括号和数据类型都可以不加
        show2(a -> System.out.println(a ));

        show3(new MyInterface3( ) {
            @Override
            public void m1(int a, String b) {
                System.out.println(a + "," +b );
            }
        });

        show3((int a,String b) ->  System.out.println(a + "," +b ));

        // 方法多个参数的时候,圆括号必须加,数据类型可以省略
        // 如果{}内只有一个语句,{}省略
        show3((int a,String b) ->  System.out.println(a + "," +b ));
        show3((a,b) ->  System.out.println(a + "," +b ));

        //show4(() -> {return 100;});
        // 如果语句只有一句话且是return语句,return可以省略
        show4(() -> 100);
        // 如果{}内有多个语句的话,return必须写
        // 如果{}内有多个语句,{}不能省略
        show4(() -> {
            int a = 1;
            int b = 2;
            return a + b;
        });

    }

    /**
     * lambda前提是
     * 1 方法有参数
     * 2 参数必须是接口
     * 3 接口中有且仅有一个方法
     */
    public static void show(MyInterface a) {
        a.m1();
    }

    public static void show2(MyInterface2 a) {
        a.m1(1);
    }

    public static void show3(MyInterface3 a) {
        a.m1(1,"a");
    }

    public static void show4(MyInterface4 a) {
        int i = a.m1( );
        System.out.println(i );
    }
}

3.3 无参无返回值的lambda

lambda就是匿名内部类的简化.

package com.qf.jdk.lambda;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo2TestLambda {
    /**
     * lambda
     * 1 方法有参数
     * 2 参数是接口
     * 3 接口只有一个方法
     */
    public static void main(String[] args) {
        // 用匿名内部类来一遍
        m1(new M1( ) {
            @Override
            public void test1() {
                System.out.println("test1执行-无参无返回值" );
            }

        });

        // 改造成lambda
        m1(() -> System.out.println("lambda执行-无参无返回值" ));
    }

    public static void m1(M1 m1) {
        m1.test1();
    }
}

// 定义一个接口
// 像这种只能有一个抽象方法的接口,用于lambda的接口
// 称之为函数式接口
interface M1{
    void test1();
    // void test11();
}

3.4 有参数无返回值

package com.qf.jdk.lambda;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 有参无返回值的lambda
 */
public class Demo3TestLambda {
    /**
     * 1 方法有参数
     * 2 参数是接口
     * 3 接口只有一个抽象方法
     */

    public static void main(String[] args) {
        // 匿名内部类实现
        m2(10, new M2( ) {
            @Override
            public void test2(int a) {
                System.out.println(a*10);
            }
        });

        m22(8, "8", new M22( ) {
            @Override
            public void test22(int a, String b) {
                System.out.println(a+b);
            }
        });

        // lambda改造
        // 一个参数时,圆括号可以加
        m2(5,(a) -> System.out.println(a*10));
        // 一个参数时,圆括号也可以不加
        m2(6,a -> System.out.println(a*10));
        // 数据类型可加可不加
        m2(7,(int a) -> System.out.println(a*10));

        // 多个参数,圆括号必须加
        m22(9,"9",(a,b) -> System.out.println(a+b ));
        // 数据类型可加可不加
        m22(10,"10",(int a,String b) -> System.out.println(a+b ));
    }

    public static void m2(int x,M2 m2) {
        m2.test2(x);
    }

    public static void m22(int x,String y,M22 m22) {
        m22.test22(x,y);
    }

}

interface M2{
    void test2(int a);
}

interface M22{
    void test22(int a,String b);
}

3.5 无参有返回值

package com.qf.jdk.lambda;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 无参有返回值得lambda
 */
public class Demo4TestLambda {
    /**
     * 1 方法得有参数
     * 2 参数得是接口
     * 3 接口中只能有一个抽象方法
     */
    public static void main(String[] args) {
        // 匿名内部类
        m3(new M3( ) {
            @Override
            public int test3() {
                int a = 1;
                a++;
                return 200;
            }
        });

        // lambda
        // lambda 中有且只有一行语句时,return可以省略
        m3(() -> 302);
        m3(() -> {return 302;});
        // lambda中有多行语句,return不能省略
        m3(() -> {
            int a = 1;
            a++;
            return 302;
        });

    }


    public static void m3(M3 m3){
        int i = m3.test3( );
        System.out.println(i );
    }


}

interface M3 {
    int test3();
}

3.6 有参有返回值

设计一个方法m4 , 方法的参数列表是接口

该接口中有1个抽象方法,能接收两个int类型参数,返回值是String

要求,给m4方法传入lambda表达式,功能是将传入的两个参数拼接为String后返回

public class Demo5TestLambda {
    /**
     * 设计一个方法m4,方法的参数列表是接口
     * 该接口中有1个抽象方法,能接收两个int类型参数,返回值是String
     * 要求,给m4方法传入lambda表达式,功能是将传入的两个参数拼接为String后返回
     */
    public static void main(String[] args) {
        m4(10,20,(x,y) ->x+""+y);
    }
    public static void m4(int a,int b,M4 m4) {
        String str = m4.test4(a,b);
        System.out.println(str );
    }
}
interface M4{
    String test4(int a,int b);
}

3.7 练习

ArrayList 集合中的元素使用 Collections 工具类进行排序.

Collections.sort(list,compartor) 其中可以指定一个比较器,进行自定义排序

用lambda

public class Demo5_lambda {

    public static void main(String[] args) {
        // 最早时候这么写
        TreeSet<Integer> set = new TreeSet<>(new MyIntegerCompartor());
        set.add(1);
        set.add(1);
        set.add(1);
        System.out.println(set );

        // 学过匿名内部类,这么写
        TreeSet<Integer> set2 = new TreeSet<>(new Comparator<Integer>( ) {
            @Override
            public int compare(Integer o1, Integer o2) {
                return 0;
            }
        });
        set2.add(2);
        set2.add(2);
        set2.add(2);
        System.out.println(set2 );

        // 学过lambda,这么写
        TreeSet<Integer> set3 = new TreeSet<>((o1,o2) -> 0);
        set3.add(3);
        set3.add(3);
        set3.add(3);
        System.out.println(set3 );

        // --------------------
        // 改造线程池创建写法
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        threadPool.execute(() -> System.out.println("任务执行..." ));
        threadPool.shutdown();
        // Collections
        ArrayList<Integer> list = new ArrayList<>( );
        list.add(3);
        list.add(2);
        list.add(1);
        list.add(4);

        // Collections.sort(list, new Comparator<Integer>( ) {
        //     @Override
        //     public int compare(Integer o1, Integer o2) {
        //         return o2-o1;
        //     }
        // });
        Collections.sort(list, (o1,o2) -> o2-o1);
        System.out.println(list );
    }

}
class MyIntegerCompartor implements Comparator<Integer> {
    @Override
    public int compare(Integer o1, Integer o2) {
        return 0;
    }
}

3.8 总结

  • lambda就是简化了匿名内部类的写法
  • lambda其实就是接口方法的重写
  • lambda的参数和返回值是根据接口方法决定的

四、函数式接口

接口中只有一个抽象方法时,该接口就是函数式接口.

为什么叫做函数式接口?因为这种接口,放在方法中当参数时,可以改造成lambda,进行运算.


Java提供了一个注解可以校验接口是否是函数式接口

@FunctionalInterface

Java中提供了几个特别常用的函数式接口

  • Supplier 供应,即返回一个数据 (无参有返回值的方法)
  • Consumer 消费,即给其传入数据做运算 (有参无返回值的方法)
  • Function 函数,传入2个参数,用于转换数据的 (有参有返回值的方法)
  • Predicate 判断,返回时boolean (有参,返回值是boolean)

4.1 Supplier

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
// 该接口用来返回一个数据,所以叫供应商
// 其实就是无参数有返回值的接口,用的时候就是无参有返回值的lambda

练习,设计方法,通过Supplier接口,获得字符串的长度

    public static void main(String[] args) {

        String str = "java";

        // 获得字符串长度
        getStringLength(() -> str.length());
        // 获得字符串首字母
        getStringLength(() -> (int) str.charAt(0));
        // 获得某个字符下标
        getStringLength(() -> str.indexOf('v'));
    }

    public static void getStringLength(Supplier<Integer> sup`plier){
        Integer length = supplier.get();
        System.out.println(length);
    }

4.2 Consumer

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     * 给传入一个值,对该值进行操作
     * @param t the input argument
     */
    void accept(T t);
}
// 其实就是有参数无返回值的接口,用的时候就是有参无返回值的lambda

练习:设计方法,传入字符串,将字符串全部转大写,后输出

public class Demo1_Consumer {

    public static void main(String[] args) {
        // 将传入的字符串转大写后输出
        show("java",(s) -> {
            String s1 = s.toUpperCase( );
            System.out.println(s1 );
        });

        show("java",(s) -> System.out.println(s.toUpperCase( ) ));

      // 将传入的数字,变成立方结果后输出
        show2(10,(i) -> System.out.println(Math.pow(10,3)));

    }

    // 消费,就是传入一个数据,对其进行处理
    public static void show(String s,Consumer<String> c) {
        c.accept(s);
    }

    public static void show2(Integer i,Consumer<Integer> c) {
        c.accept(i);
    }
}

4.3 Function

@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);
}
// 该接口用于,转换数据
// 其实就是有参数有返回值的接口,用的时候就是有参有返回值的lambda

练习,设计方法,将传入的字符串数字,转为整形数字

package com.qf.function_interface;

import java.util.function.Function;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo2_Function {

    public static void main(String[] args) {

        show("111",(t) -> Integer.parseInt(t));


        show(2,(t) -> String.valueOf(t * 10));
    }

    // Function接口,主要是用于接收数据,处理数据后返回

    // 将传入的字符串数字,转为整形数字后返回
    public static void show(String t,Function<String,Integer> f){
        Integer i = f.apply(t);
        System.out.println(i);
    }

    // 将传入的数字放大10倍后变为字符串返回
    public static void show(Integer t,Function<Integer,String> f){
        String i = f.apply(t);
        System.out.println(i);
    }
}

4.4 Predicate

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}
// 用于判断数据
// 其实就是有参数有返回值为boolean的接口,用的时候就是有参有返回值为boolean的lambda

设计方法,判断数据

    public static void main(String[] args) {
        // 判断人名,是否太长,大于3即认为太长
        isTrue("迪丽热巴",name -> name.length() > 3);

        // 判断年龄,年龄不能超过 0-150之间
        isTrue2(220,age -> age <= 150 && age >= 0);
    }

    public static void isTrue2(Integer age, Predicate<Integer> predicate){
        boolean test = predicate.test(age);
        System.out.println("test = " + test);
    }


    public static void isTrue(String name, Predicate<String> predicate){
        boolean test = predicate.test(name);
        System.out.println("test = " + test);
    }

作业

定义一个方法,传入一个整型数组,返回数组最大值
定义一个方法,返回100内最大质数
ps: 质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数
定义一个方法,传入一个数组,返回指定数组的和
定义一个方法,传入一个数,判断他是否是3的倍数
package com.qf.function_interface;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo4 {

    public static void main(String[] args) {
        int[] arr = {3,12,5,4,1};
        getMax(arr,(a) -> {
            int max = a[0];
            for (int i = 0; i < a.length; i++) {
                if (a[i] > max) {
                    max = a[i];
                }
            }
            return max;
        });


        getMaxZhishu(() -> {
            int max = -1;
            for (int i = 1; i < 101; i++) {
                boolean flag = true;// 假设都是质数
                for (int j = 2; j < i; j++) {
                    if (i % j == 0) {
                        flag = false;
                    }
                }
                if (flag) {
                    // System.out.println("质数:" + i );
                    max = i;
                }
            }
            return max;
        });

        printZhishu(20,(n) -> {
            for (int i = 1; i <= n; i++) {
                boolean flag = true;// 假设都是质数
                for (int j = 2; j < i; j++) {
                    if (i % j == 0) {
                        flag = false;// 但凡有一个除了1和它本身能整除的
                                     // 他就不是质数
                    }
                }
                if (flag) {
                    System.out.print(i+" " );
                }
            }
        });
    }

    // 传入一个整型数组,返回数组最大值
    public static void getMax(int[] arr,Function<int[],Integer> f){
        Integer max = f.apply(arr);
        System.out.println("数组最大值是: " + max );
    }


    // 返回100内最大质数
    public static void getMaxZhishu(Supplier<Integer> s) {
        Integer integer = s.get( );
        System.out.println("100以内的最大质数值:" + integer );
    }

    // 输出整数1-n之间的所有质数
    public static void printZhishu(Integer n,Consumer<Integer> s) {
        s.accept(n);
    }
}

五、Stream流

Stream流,不要和之前学的IO流进行联想,他们之间没有关系.

IO流,数据像水流一样在传输

Stream流,数据像车间流水线,在一直往下走动,不是保存数据,也不纯粹的传输数据,而是像车间流水线一样,在处理数据.

Stream流可以让我们更快的处理数据.

分别演示之前处理数据,和使用Stream流来处理数据

package com.qf.stream;

import java.util.ArrayList;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 初始Stream
 */
public class Demo1 {
    public static void main(String[] args) {
        // 假如有个集合,存储了人名
        // 找到名字长度<= 3,且名称包含"龙",将其输出
        ArrayList<String> list = new ArrayList<>( );
        list.add("小龙");
        list.add("于文龙");
        list.add("我是成龙");
        list.add("张三");
        list.add("迪丽热巴");
        for (int i = 0; i < list.size(); i++) {
            String n = list.get(i);
            if (n.length() <= 3) {
                if (n.contains("龙")) {
                    System.out.println(n );
                }
            }
        }

        System.out.println("--------------" );
        // 以上代码使用Stream流式操作
        list.stream().filter((s) -> s.length() <= 3).filter((s) -> s.contains("龙")).forEach((s) -> System.out.println(s ));


    }
}

image-20230428110856497

5.1 获得流

Java提供了几种方式,可以让我们获得Stream流

  1. [集合创建流]Collection 接口的 stream()或 parallelStream()方法
  2. [自由值创建]静态的 Stream.of()、Stream.empty()方法
  3. [数组创建流]Arrays.stream(array)
  4. 静态的 Stream.generate()方法生成无限流,接受一个不包含引元的函数
  5. 静态的 Stream.iterate()方法生成无限流,接受一个种子值以及一个迭代函数
  6. Pattern 接口的 splitAsStream(input)方法
  7. 静态的 Files.lines(path)、Files.lines(path, charSet)方法
  8. 静态的 Stream.concat()方法将两个流连接起来
package com.qf.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 演示获得流
 */
public class Demo2 {

    public static void main(String[] args) {
        // Collection接口在JDK1.8以后,加入了一个新的方法stream()
        // 该方法就可以将集合转成流
        ArrayList<Integer> list = new ArrayList<>( );
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        Stream<Integer> stream = list.stream( );

        // jdk1.8后,提供了Stream接口,其中有个静态方法
        Stream<Integer> stream2 = Stream.of(1, 2, 3, 4, 5);

        // Arrays类也有了新的方法
        int[] arr = {11,22,33,44,55};
        IntStream stream3 = Arrays.stream(arr);
    }
}

5.2 中间操作

Stream流就是流式处理数据,流的操作有很多种

  • 获得流
  • 中间操作(真正处理数据的操作)
    • 中间操作就是执行完返回的是一个流,即可以继续执行流操作
  • 终止操作(将操作完的结果返回)
操作函数说明
中间操作filter(Predicate)将结果为false的元素过滤掉
中间操作map(Function)转换元素的值,可以用方法引元或者lambda表达式
中间操作flatMap(Function)若元素是流,将流摊平为正常元素,再进行元素转换(合并两个流为一个流)
中间操作limit(long n)保留前n个元素
中间操作skip(long n)跳过前n个元素
中间操作concat(Stream s1, Stream s2)将两个流拼接起来
中间操作distinct()剔除重复元素
中间操作sorted()将Comparable元素的流排序
中间操作sorted(Comparator)将流元素按Comparator排序
中间操作peek(Consumer)流不变,但会把每个元素传入fun执行,可以用作调试
终结操作max(Comparator)取最大值
终结操作min(Comparator)取最小值
终结操作count()统计元素数量
终结操作findFirst()获得流的第一个元素
终结操作findAny()返回任意元素
终结操作anyMatch(Predicate)任意元素匹配时返回true
终结操作allMatch(Predicate)所有元素匹配时返回true
终结操作noneMatch(Predicate)没有元素匹配时返回true
终结操作reduce(Function)从流中计算某个值,接受一个二元函数作为累积器,从前两个元素开始持续应用它,累积器的中间结果作为第一个参数,流元素作为第二个参数
终结操作iterator()迭代器迭代元素
终结操作forEach(Consumer)lambda的方式迭代
终结操作forEachOrdered(Consumer)可以应用在并行流上以保持元素顺序

Stream流的操作注意事项

  1. 流的操作只能使用一次
  2. 使用中间操作,返回新的流
  3. 没有终止操作,就不会有结果,换句话说,没有终结操作,中间操作是 不会执行的
package com.qf.stream;

import java.util.ArrayList;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo3 {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>( );
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        Stream<Integer> stream = list.stream( );

        // 流第一次用
        // stream.forEach((s) -> System.out.println(s ));
        // 第二次再用报错!! 流只能使用一次!!
        // stream.forEach((s) -> System.out.println(s ));


        // 中间操作会返回新的流
        // 没有终止操作,中间操作不会执行
        Stream<Integer> stream1 = stream.filter((x) -> {
            System.out.println("正在过滤..."+x );
            return x % 2 == 0;
        });
        stream1.forEach((x) -> System.out.println(x ));
    }
}


下面演示流的操作使用 - 中间操作

package com.qf.jdk.stream;

import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 操作流
 */
public class Demo4 {

    public static void main(String[] args) {
        // 1 获得流
        Stream<String> stream = Stream.of("11", "11","22","22", "33");
        Stream<String> stream2 = Stream.of("aa", "bb", "cc");
        // 2 limit(long n) 保留流里面的前几个
        // stream.limit(2).forEach(s -> System.out.println(s ));

        // 3 skip(long n) 跳过前几个
        // stream.skip(2).forEach(s -> System.out.println(s ));

        // 4 concat 拼接两个流为新的流
        // 该方法是Stream接口中的静态方法,直接通过接口名调用
        // Stream.concat(stream,stream2).forEach(s -> System.out.println(s ));

        // 5 distinct 将流中的数据去重
        // stream.distinct().forEach(s -> System.out.println(s ));

        // 6 sorted 排序,默认是升序
        Stream<Integer> stream3 = Stream.of(5,3,2,1,4);
        // stream3.sorted().forEach(s -> System.out.println(s ));

        stream3.sorted((o1,o2) -> o2 - o1).forEach(s -> System.out.println(s ));
       // 7 flatMap
        // 对给定单词列表 ["Hello","World"],你想返回列表["H","e","l","o","W","r","d"]
        String[] words = new String[]{"Hello","World"};
        List<String[]> a = Arrays.stream(words)
                .map(word -> word.split(""))
                .collect(Collectors.toList());
		// 这样得到的是List<String[]>
        a.forEach(e -> System.out.println(e ));

        // 对流扁平化处理(将多个String[]转成流后合并成一个流)
        List<String> a2 = Arrays.stream(words)
                .map(word -> word.split(""))
                .flatMap(n -> Arrays.stream(n))
                .collect(Collectors.toList());
        a2.forEach(e -> System.out.println(e ));


        ArrayList<Integer> l1 = new ArrayList<>( );
        l1.add(1);
        l1.add(2);
        l1.add(3);

        ArrayList<Integer> l2 = new ArrayList<>( );
        l2.add(4);
        l2.add(5);
        l2.add(6);
        // List里面有2个元素,是两个List,将它们合并成一个流
        ArrayList<List<Integer>> list = new ArrayList<>( );
        list.add(l1);
        list.add(l2);

        list.stream().flatMap(n -> n.stream()).forEach(e -> System.out.println(e ));
    }

}

在这里插入图片描述

在这里插入图片描述

下面演示流的操作使用 - 终止操作

package com.qf.jdk.stream;

import jdk.nashorn.internal.ir.IfNode;

import java.util.Iterator;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo5 {

    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(5, 3, 2, 1, 4);

        // 1 终止操作min,返回的是Optional类
        // Optional类中有个方法,get() ,可以获得其中的数据
        // min方法返回的是,排序后的第一个
        // Optional<Integer> optional = stream.min((o1, o2) -> o1 - o2);
        // Integer min = optional.get( );
        // System.out.println(min );

        // Integer min = stream.min((o1, o2) -> o1 - o2).get( );

        // 2 count() 计数
        // System.out.println(stream.count( ));
        // long count = stream.filter(e -> e > 2).count( );
        // System.out.println(count );

        // 3 findFirst() 获得流里面第一个,返回Optional
        // System.out.println(stream.findFirst( ).get( ));

        // 4 anyMatch(Predicate)  任意元素匹配时返回true
        // 判断流里面的元素,任意一个都>3
        // 任意一个是,只要有一个就可以
        // System.out.println(stream.anyMatch(i -> i > 3));

        // 5 allMatch(Predicate)  全部元素匹配时返回true
        // System.out.println(stream.allMatch(i -> i > 3));

        // 6 reduce() 将元素归纳
        // 假设我们对一个集合中的值进行求和
        // System.out.println(stream.reduce(0, (sum, e) -> {
        //     System.out.println("sum = " + sum);
        //     System.out.println("e = " + e);
        //     return sum + e;
        // }));

        // 7 iterator()  迭代器迭代元素
        // Iterator<Integer> iterator = stream.iterator( );
        // while (iterator.hasNext()) {
        //     Integer next = iterator.next( );
        //     System.out.println(next );
        // }
    }
}

练习: 给定ArrayList集合,先过滤数据只保留偶数,后对数据进行降序排序,去除重复元素,将元素转成String类型后返回一个ArrayList

ArrayList<Integer> list4 = new ArrayList<>( );        
list4.add(1);
list4.add(2);
list4.add(2);
list4.add(3);
list4.add(3);
list4.add(4);
list4.add(4);

List<String> collect2 = list4.stream( )
    .filter(e -> e % 2 == 0)
    .sorted((o1, o2) -> o2 - o1)
    .distinct( )
    .map(e -> String.valueOf(e))
    .collect(Collectors.toList( ));

5.3 流的收集

流操作完,将数据流中的数据再返回成数组和集合 --> 这就是收集流

将流收集到集合或数组中

  • collect() 收集到集合
  • toArray 收集到数组
package com.qf.jdk.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Demo6 {

    public static void main(String[] args) {
        Stream<Integer> stream = Stream.of(5, 5,3, 2, 1, 4,4);

        // 流中数据转成list集合
        // List<Integer> list = stream.filter(i -> i > 3).collect(Collectors.toList( ));
        // System.out.println(list );

        // 流中数据转成set集合
        // Set<Integer> set = stream.filter(i -> i > 3).collect(Collectors.toSet( ));
        // System.out.println(set );

        // 流可以转成数组
        // Object[] array = stream.toArray( );

        // 也可转成指定类型的数组
        Integer[] array = stream.toArray((length) -> new Integer[length]);
        System.out.println(Arrays.toString(array));
    }
}

六、新日期API

Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。

在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:

  • 非线程安全 − java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
  • 设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
  • 时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
/*一些吐槽:
1.java.util.Date被设计为日期 + 时间的结合体。也就是说如果只需要日期,或者只需要单纯的时间,用Date是做不到的。
2. 年要减1900…  月从0-11 …
3.	Date是可变的,也就是说我把一个Date日期时间对象传给方法,方法内竟然还能更改
*/
@Test 
public void test() { 
    Date currDate = new Date(); 
    System.out.println("当前日期是①:" + currDate); 
    boolean holiday = isHoliday(currDate); 
    System.out.println("是否是假期:" + holiday); 
 
    System.out.println("当前日期是②:" + currDate); 
} 
 
/** 
 * 是否是假期 
 */ 
private static boolean isHoliday(Date date) { 
    // 假设等于这一天才是假期,否则不是 
    Date holiday = new Date(2021 - 1900, 10 - 1, 1); 
 
    if (date.getTime() == holiday.getTime()) { 
        return true; 
    } else { 
        // 模拟写代码时不注意,使坏 
        date.setTime(holiday.getTime()); 
        return true; 
    } 
}

日期

LocalDate

	@Test
	public void test02() {
		// ========== 获得日期 ==========
		// 获得当前日期
		LocalDate now = LocalDate.now();
		System.out.println(now);
		// 获得指定日期的时间
		LocalDate date = LocalDate.of(2020, 1, 1);
		System.out.println(date);
		
		// 获得年
		System.out.println(now.getYear());
		// 获得月
		System.out.println(now.getMonthValue());
		// 获得日
		System.out.println(now.getDayOfMonth());
		
		// ========== 设置日期 ==========
		// 设置之后返回的日期是一个新的日期对象,之前的日期并未更改
		// 设置年
		LocalDate withYear = now.withYear(1990);
		// 设置月
		LocalDate withMonth = now.withMonth(8);
		// 设置日
		LocalDate withDayOfMonth = now.withDayOfMonth(8);
		System.out.println(now);
		System.out.println(withYear);
		// 增加日期,返回新的日期对象
		// 增加的方法plusXxx()
		LocalDate plusYears = now.plusYears(2);
		
		// 减少日期
		// 减少的方法 minusXxx()
		LocalDate minusYears = now.minusYears(2);

	}

时间

LocalTime

	@Test
	public void test03() {
		// ========== 获得时间 ==========
		// 获得当前时间
		LocalTime now = LocalTime.now();
		System.out.println(now);
		// 获得指定时间
		LocalTime of1 = LocalTime.of(10, 10); // 时分
		LocalTime of2 = LocalTime.of(10, 10,10);// 时分秒
		LocalTime of3 = LocalTime.of(10, 10,10,10);// 时分秒纳秒
		System.out.println(of1);
		
		// 获得时,分,秒
		System.out.println(now.getHour());
		System.out.println(now.getMinute());
		System.out.println(now.getSecond());
		
		// ========== 设置时间 ==========
		// 设置时
		LocalTime hour = now.withHour(8);
		// 设置分
		LocalTime minute = now.withMinute(8);
		// 设置秒
		LocalTime second = now.withSecond(8);
		System.out.println(now);
		System.out.println(hour);
				
        // 增加时间,返回新的时间对象
		// 增加的方法plusXxx()
		LocalTime plus = now.plusHours(2);
		
		// 减少时间
		// 减少的方法 minusXxx()
		LocalTime minus = now.minusHours(2);
	}

日期时间

LocalDateTime

	@Test
	public void test04() {
		// ========== 获得日期时间 ==========
		// 获得当前时间
		LocalDateTime now = LocalDateTime.now();
		System.out.println(now);
		// 获得指定时间
		LocalDateTime of1 = LocalDateTime.of(1900, 1, 1, 10, 10); //年月日时分
		LocalDateTime of2 = LocalDateTime.of(2000, 10,10,8,8,8);// 年月日时分秒
		System.out.println(of1);
		
		// 获得年,月,日
		System.out.println(now.getYear());
		System.out.println(now.getMonthValue());
		System.out.println(now.getDayOfMonth());
		// 获得时,分,秒
		System.out.println(now.getHour());
		System.out.println(now.getMinute());
		System.out.println(now.getSecond());
		
		// ========== 设置日期时间 ==========
		// 设置时
		LocalDateTime hour = now.withHour(8);
		// 设置分
		LocalDateTime minute = now.withMinute(8);
		// 设置秒
		LocalDateTime second = now.withSecond(8);
		System.out.println(now);
		System.out.println(hour);

		// 增加时间,返回新的时间对象
		// 增加的方法plusXxx()
		LocalDateTime plus = now.plusHours(2);
		
		// 减少时间
		// 减少的方法 minusXxx()
		LocalDateTime minus = now.minusHours(2);

		System.out.println(now.isAfter(plus));
		System.out.println(now.isBefore(plus));
		System.out.println(now.isEqual(plus));
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/496541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows下安装QT

一、Windows下安装QT 1、QT官网 QT官网&#xff1a;https://download.qt.io/&#xff0c;打开官网地址&#xff0c;如下&#xff1a; 目录结构介绍 目录说明snapshots预览版&#xff0c;最新的开发测试中的 Qt 库和开发工具onlineQt 在线安装源official_releases正式发布版&am…

2023,滴滴“摸着自动驾驶过河”

在“滴滴网约车”的出行领域&#xff0c;出行网络和数据量级是滴滴自动驾驶的优势。但就自动驾驶技术本身来看&#xff0c;滴滴仍然需要展示更多的肌肉。 作者|斗斗 出品|产业家 滴滴自动驾驶有了新动作。 一款“人性化”的概念车、两个加速实现量产L4级车辆的自研硬件、一…

【攻略】北京国际鲜花港

文章目录 一、概述二、经典景观1.万花馆2.花艺中心3.花神广场4.瑞云坪5.百花田6.奇石园7.梅园8.唐草园9.幻花湖10.大地花海11.白滩12.樱花大道13.海棠园 三、网友点评四、注意事项五、北京其他景点推荐 北京国际鲜花港_360百科北京顺义区十大著名景点—2、北京顺义国际鲜花港 -…

C嘎嘎~~ [类 下篇]

类 下篇 1.类的6个默认成员函数2.构造函数2.1 构造函数出现的原因2.2 特性2.3 深刻解读---构造函数可以重载2.4 深刻解读---默认构造函数补充: 3.析构函数3.1概念3.2 特性3.3深刻解读例子 总结 4.拷贝构造函数4.1 概念4.2 特性4.3深刻解读---拷贝构造是构造的一种重载4.4深刻理…

【Linux网络】传输层中UDP和TCP协议

文章目录 1、再谈端口号2、UDP协议3、TCP协议3.1 TCP协议段格式3.2 TCP的三次握手和四次挥手&#xff08;连接管理机制&#xff09;3.3 TCP的滑动窗口3.4 TCP的流量控制3.5 拥塞控制3.6 延迟应答和捎带应答3.7 面向字节流和粘包问题3.8 TCP总结 1、再谈端口号 端口号port标识一…

动态规划算法——40道leetcode实例入门到熟练

目录 t0.解题五部曲1.基础入门题目1.509. 斐波那契数2.70. 爬楼梯3.746. 使用最小花费爬楼梯4.62. 不同路径5.63. 不同路径 II6.343. 整数拆分7.96. 不同的二叉搜索树 2.背包问题1.01背包&#xff08;二维数组实现&#xff09;2.01背包&#xff08;滚动数组实现&#xff09;1.4…

OpenPCDet系列 | 4.数据集数据加载流程

文章目录 数据加载流程0. create_kitti_infos1. __getitem__函数2. prepare_data函数3. collate_batch函数数据加载流程 这里记录一下具体用到的那些数据形式,整个kitti数据集的处理框架图如下所示: 在数据集处理到获取一个batch数据的整个流程的入口如下: # 开始迭代每…

01-微服务部署2023系列-centos安装nginx和jdk教程

centos安装nginx和jdk教程 一、centos安装nginx 0、前提:安装依赖 yum -y install gcc gcc-c++ make libtool zlib zlib-devel openssl openssl-devel pcre pcre-devel 1、压缩包 下载nginx 选择Stable version: http://nginx.org/en/download.html 上传压缩包到…

yolov3核心网络模型

1. 改进概述 yolov3主要围绕核心网络Darknet优化进行。 yolov3的速度和map值比之前的算法优秀。 改进包含&#xff1a;网络结构、特征融合、先验框&#xff1a; V1 2, V25,V39、Softmax等。 softmax 2. 多scale方法改进与特征融合 3. 经典变换方法 预测中目标时&#xff0c…

Nacos配置管理、Fegin远程调用、Gateway服务网关

1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#xf…

Spring-IOC

IOC概念和原理 什么是IOC 控制反转&#xff0c;为了将系统的耦合度降低&#xff0c;把对象的创建和对象直接的调用过程权限交给Spring进行管理。 IOC底层原理 XML解析 ​ 通过Java代码解析XML配置文件或者注解得到对应的类的全路径&#xff0c;获取对应的Class类 Class clazz …

Django框架之模型查询介绍及示例

本篇文章所使用模型查询都在《Django框架之模型自定义管理器》基础上讲解查询和使用示例&#xff0c;通过看前篇可以有助于理解内容。 概述 查询集&#xff1a;从数据库获取的对象集合 查询集可以有多个过滤器 过滤器就是一个函数&#xff0c;根据所给的参数限制查询集结果 …

【Vue学习笔记5】Vue3中的响应式:ref和reactive、watchEffect和watch

所谓响应式就是界面和数据同步&#xff0c;能实现实时更新。 Vue 中用过三种响应式解决方案&#xff0c;分别是 defineProperty、Proxy 和 value setter。Vue 2 使用的方案是 defineProperty API。Vue3中使用的方案是Proxy和value setter。 1. ref和reactive vue3中实现响应…

基于docker部署ELK实战- ELK文章1

选择版本为elasticsearch:7.17.9&#xff0c;kibana:7.17.9&#xff0c;logstash:7.17.9 版本一定要一致 docker hub地址&#xff1a;https://hub.docker.com elk相关文档&#xff1a;https://www.elastic.co/guide/en/kibana/7.17 一、部署单点es 1.创建网络 因为我们还需要…

iframe嵌套grafana (前端视角)

1、grafana 启动方式 ①.grafana目录鉴赏。咱们就是直接拿到配置好的grafana。咱们暂时不涉及配置数据啥。 ①.双击grafana-server.exe &#xff0c;会出现黑色命令框。 ②.在浏览器中访问 http://localhost:3000 此时就可以看到配置好的grafana 2.前端嵌入 ①.html <…

消息队列中间件 - Docker安装RabbitMQ、AMQP协议、和主要角色

概述 不管是微服务还是分布式的系统架构中&#xff0c;消息队列中间件都是不可缺少的一个重要环节&#xff0c;主流的消息队列中间件有RabbitMQ、RocketMQ等等&#xff0c;从这篇开始详细介绍以RabbitMQ为代表的消息队列中间件。 AMQP协议 AMQP协议是一个提供统一消息服务的应…

图像处理:基于cv2.inpaint()图像修补

前言 今天我们将学习如何通过一种“修复”的方法消除旧照片中的小噪音&#xff0c;笔画等。当然&#xff0c;经过我的测试你也可以将其用于削弱混杂了其他的颜色的图像。 实验背景 大多数人家都会有一些旧的的旧化照片&#xff0c;上面有黑点&#xff0c;一些笔触等。你是否…

从零实现深度学习框架——常见学习率调整策略原理与实现

引言 本着“凡我不能创造的&#xff0c;我就不能理解”的思想&#xff0c;本系列文章会基于纯Python以及NumPy从零创建自己的深度学习框架&#xff0c;该框架类似PyTorch能实现自动求导。 &#x1f4a1;系列文章完整目录&#xff1a; &#x1f449;点此&#x1f448; 要深入理解…

day24_多线程

今日内容 零、 复习昨日 一、作业 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 见晨考 一、作业 售卖后车票 见代码二、线程安全的类[了解] StringBuffer是线程安全的,是因为每个方法都加上synchronized,即都是同步方法 StringBuil…

【前端】前后端分离ruoyi-vue初步学习

1.了解vue基础知识。 Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org) 2.将ruoyi-vue项目拉下来&#xff0c;并成功运行。 开源项目网址&#xff1a;RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|…