JAVA 新特性

JAVA8 新特性

JAVA8 新特性

接口中默认方法修饰为普通方法

  • JDK8之前,interface之中可以定义变量和方法,变量必须是public、static、final的,方法必须是public、abstract的,由于修饰符都是默认的。
  • 方法:分为普通方法和抽象方法

  • 普通方法 是有方法体

  • 抽象方法 没有方法体 需要子类重写

  • 接口定义方法:public 抽象方法 需要子类实现

  • 接口定义变量:public、static、final

  • JDK8之后,支持使用static和default修饰,可以写方法体,JDK8之后,支持使用static和default修饰,可以写方法体,不需要重写static、default修饰的方法。
public interface JDK8Interface {
    /**
     * 接口定义方法:修饰符默认有public、abstract,写了反而冗余
     */
    void add();

    /**
     * JDK8定义default方法,允许有方法体,可以不需要重写该方法
     */
    default void defaultGet(){
        System.out.println("defaultGet");
    }

    /**
     * JDK8允许使用静态方法,也允许有方法体,可以不需要重写该方法
     */
    static void staticDel(){
        System.out.println("staticDel");
    }
}

函数式接口

  • 有且仅有一个抽象方法的接口,也可以定义其他方法(如默认方法、静态方法、私有方法)
  • 默认方法的优先级

    1. 子类(接口继承、实现)如果重写了,子类的优先级更高
/**
 * 默认方法的优先级
 * 1、子类(接口继承、实现)如果重写了,子类的优先级更高
 */
public class DefaultTest {
    public static void main(String[] args) {
        new C().m1(); //C会被打印出来
    }
}

interface A{
    default void m1(){
        System.out.println("A");
    }
}

class C implements A{//子类(接口继承、实现)如果重写了,子类的优先级更高
    @Override
    public void m1() {
        System.out.println("C"); 
    }
}
    1. 实现多接口,接口中有相同的默认方法需要指明使用哪一个接口中定义的默认方法
/**
 * 默认方法的优先级
 * 2、 实现多接口,接口中有相同的默认方法需要指明使用哪一个接口中定义的默认方法
 */
public class DefaultTest {
    public static void main(String[] args) {
        new C().m1(); //A会被打印出来
    }
}

interface A{
    default void m1(){
        System.out.println("A");
    }
}

interface B{
    default void m1(){
        System.out.println("B");
    }
}

class C implements A,B{
    @Override
    public void m1() {
        A.super.m1();//实现多接口,接口中有相同的默认方法需要指明使用哪一个接口中定义的默认方法
    }
}
修饰符 interface 接口名称{
    public abstract 返回值类型 方法名称(可选参数信息);
    //其他非抽象方法内容
}
    1. 子类使用接口中的默认方法需求将该方法覆盖且为抽象方法
/**
 * 默认方法的优先级
 * 3、 子类使用接口中的默认方法需求将该方法覆盖且为抽象方法
 */
public class DefaultTest {
    public static void main(String[] args) {
        new C().m1();
    }
}

interface A{
    default void m1(){
        System.out.println("A");
    }
}

interface B{
    default void m1(){
        System.out.println("B");
    }
}

class C implements A,B{
    @Override
    public void m1() {
        A.super.m1();
    }
}

abstract class D implements A,B{
    public abstract void m1(); //子类使用接口中的默认方法需求将该方法覆盖且为抽象方法
}
  • 静态方法

/**
 * 静态方法
 */
public class DefaultTest {
    public static void main(String[] args) {
        new C().m1();
        E.m2();
    }
}

interface A{
    default void m1(){
        System.out.println("A");
    }
}

interface B{
    default void m1(){
        System.out.println("B");
    }
}

class C implements A,B{
    @Override
    public void m1() {
        A.super.m1();
    }
}

abstract class D implements A,B{
    public abstract void m1();
}

interface E{
	//静态方法
    static void m2(){
        System.out.println("E");
    };
}
  • 接口当中的抽象方法的public abstract是可以省略的。
  • @FunctionalInterface注解的作用是检测接口是否是一个函数式接口。
  • 函数式接口的使用:一般可以作为方法的参数和返回值类型
  • 函数式接口作为方法的参数,那么调用该方法时,①可以传递接口的实现对象;②或可以传递接口的匿名内部类。③或使用Lambda表达式。

/**
 * 创建函数式接口
 */
@FunctionalInterface
public interface MyFunctionalInterface {
    //定义一个抽象方法
    public abstract void method();
}

/**
 * 创建实现函数式接口的类
 */
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface{
    @Override
    public void method() {
        System.out.println("使用实现接口的对象重写接口的抽象方法");
    }
}

/**
 * 函数式接口作为参数传递的测试Demo
 */
public class Demo {
    //定义一个方法,参数使用函数式接口MyFunctionalInterface
    public static void show(MyFunctionalInterface myInter){
        myInter.method();
    }

    public static void main(String[] args) {
        //调用show方法,方法的参数是一个接口,所以可以传递接口的实现对象
        show(new MyFunctionalInterfaceImpl());
        //调用show方法,方法的参数一个接口,所以我们可以传递接口的匿名内部类
        show(new MyFunctionalInterface() {
            @Override
            public void method() {
                System.out.println("使用匿名内部类重写接口中的抽象方法");
            }
        });
        //调用show方法,方法的参数是一个函数式接口,所以我们可以使用Lambda表达式
        show(()-> System.out.println("使用Lambda表达式重写接口中的抽象方法"));
    }
}

生产型接口 Supplier

import java.util.function.Supplier;

/**
 * 常用的函数式接口
 *
 * Supplier<T>接口别称为生产型接口
 *
 */
public class Demo01Supplier {
    //定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个String
    public static String getString(Supplier<String> sup){
        return sup.get();
    }

    public static void main(String[] args) {
        //调用getString()
        String str = getString(()->"胡歌");
        System.out.println(str);
    }
}

比较器接口 Comparator

import java.util.Arrays;
import java.util.Comparator;

/**
 * 函数式接口Comparator
 */

public class Demo02Comparator {
    public static Comparator<String> getComparator(){
//        //定义一个方法,方法的返回值类型使用函数式接口Comparator
//        return new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                return o2.length() - o1.length();
//            }
//        };

        //方法的返回值是一个函数式接口,就可以返回一个Lambda表达式
        return (s1,s2)->s2.length() - s1.length();
    }

    public static void main(String[] args) {
        String[] str = {"aaaa","c","bbbbbbbb"};
        System.out.println(Arrays.toString(str));
        Arrays.sort(str,getComparator());
        System.out.println(Arrays.toString(str));
    }

}

消费型接口 Consumer

import java.util.function.Consumer;

/**
 * 消费型接口Consumer<T>
 */
public class Demo01Consumer {
    /**
     * 定义一个方法
     */

    public static void method(String name, Consumer<String> con){
        con.accept(name);
    }

    public static void main(String[] args) {
        //调用method()
//        method("赵丽",System.out::println); //方法引入
        method("赵丽颖",(name)->{
            String reName = new StringBuffer(name).reverse().toString();
            System.out.println(reName);
        });
    }
}

组合型接口 Consumer接口的andThen()实现

andThen()作用:需要两个Consumer接口,可以把两个Consumer接口组合在一起,再对数据进行消费。

import java.util.function.Consumer;
/**
 * Consumer接口的默认方法andThen
 * 如:
 * Consumer<String> con1 * Consumer<String> con2 * * String s = "Hello" * con1.accept(s); * con2.accept(s); * * con1.andThen(con2).accept(s) 谁写前面谁先消费
 */
public class Demo02AndThen {
    //定义一个,方法的参数传递一个字符串和两个Consumer接口
    public static void method(String s, Consumer<String> con1,Consumer<String> con2){
//        con1.accept(s);
//        con2.accept(s);
		//使用andThen方法,把两个Consumer接口连接到一起,再消费数据
 		con1.andThen(con2).accept(s); //con1连接con2,先执行con1消费数据,再执行con2消费数据
 	}
    public static void main(String[] args) {
        method("Hello",(t)->{
                    System.out.println(t.toUpperCase());
                },
                (t)->{
                    System.out.println(t.toLowerCase());
                });
    }
}

Consumer接口的nullsFirst()实现

**nullsLast()的实现与nullsFirst()是相反的
在这里插入图片描述
在这里插入图片描述

Consumer接口的comparing()实现

@Test
public void test19() {
  Comparator<Integer> comparator = Comparator.comparing(x -> {
    if (x > 0) {
      x -= 2;
    } else {
      x /= 2;
    }
    return x;
  });
  int compare = comparator.compare(1, 0); 
}

Predicate接口

作用:对某种数据类型的数据进行判断,结果返回一个boolean值。

import java.util.function.Predicate;

/**
 * Predicate接口中包含一个抽象方法
 * boolean test(T t):用来对指定数据类型数据进行判断的方法
 */
public class Demo01Predicate {
    /**
     * 定义一个方法
     * 参数传递一个String类型的字符串
     * 传递一个Predicate接口,泛型使用String
     * 使用Predicate中的方法test对字符串判断,并把判断结果返回
     */
    public static boolean checkString(String s, Predicate<String> pre){
        return pre.test(s);
    }

    public static void main(String[] args) {
        //定义一个字符串
        String s = "abcdef";
        boolean b = checkString(s,str->str.length() > 5);

        System.out.println(b);
    }

}
Predicate接口的 and方法
import java.util.function.Predicate;
/**
 * 逻辑表达式:可以连接多个判断的条件
 * &&:与运算符,有false则false
 * ||:或运算符,有true则true
 * !:非(取反)运算符,非真则假
 *
 * 需求:
 *  1.判断字符串的长度是否大于5
 *  2.判断字符串中是否包含a
 * * 两个条件必须同时满足,我们就可以使用&&运算符连接两个条件
 *
 *  Predicate接口有个方法and,表示并且关系,也可以用于连接两个判断条件
 *
 */
public class Demo02Predicate_and {
    public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
//        return pre1.test(s) && pre2.test(s);
 		return pre1.and(pre2).test(s);
    }
    public static void main(String[] args) {
        //定义一个字符串
 		String s = "abcdef";
        boolean b = checkString(s,str->str.length() > 5,str->str.contains("a"));
        System.out.println(b);
    }
}
Predicate接口的 or方法
import java.util.function.Predicate;

public class Demo03Predicate_or {
    public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
    	//return pre1.or(pre2).test(s);
        return pre1.test(s)||pre2.test(s);
    }

    public static void main(String[] args) {
        String s = "abcdef";
        
        boolean b = checkString(s,str->str.length() > 5,str->str.contains("a"));
        
        System.out.println(b);
    }
}
Predicate接口的 negate方法
import java.util.function.Predicate;
/**
 * negate: 取反符号!
 */
public class Demo04Predicate_negate {
    public static boolean checkString(String s, Predicate<String> pre){
    	//return pre.negate().test(s);
        return !pre.test(s);
    }
    public static void main(String[] args) {
        String s = "abcdefg";
        boolean b = checkString(s,str->str.length() < 5);
        System.out.println(b);
    }
}

import java.util.ArrayList;
import java.util.function.Predicate;
/**
 * 过滤长度为4的名字且性别为女
 */
public class Demo04Test {
    public static ArrayList<String> filter(String[] arr, Predicate<String> pre1, Predicate<String> pre2){
        ArrayList<String> list = new ArrayList<>();
        for (String s : arr) {
            boolean b = pre1.test(s) && pre2.test(s);
            if(b){
                list.add(s);
            }
        }
        return list;
    }
    public static void main(String[] args) {
        String[] array = {"迪丽热巴,女","古力娜扎,女","马儿扎哈,男","赵丽颖,女"};
        ArrayList<String> list = filter(array, (s) -> s.split(",")[0].length() == 4, s -> s.split(",")[1].contains("女"));
        System.out.println(list);
    }
}
Predicate接口的 isEqual方法

用于对象的比较

public class Employee {
    private Long id;
    private String name;
    private Integer age;
    private Double salary;

    public Employee(Long id, String name, Integer age, Double salary) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                '}';
    }
}
===========================================================================================
import com.bjsxt.common.Employee;
import org.junit.Test;

import java.util.function.Predicate;

public class FunctionalInterfaceMethod {
    Employee tom = new Employee(1L, "tom", 20, 10000.0);
    Employee xiaoming = new Employee(1L, "xiaoming", 35, 12000.0);

    @Test
    public void test01() {
        Predicate<Employee> predicate = employee -> employee.getAge() > 30;
        boolean tomTest = predicate.test(tom);
        boolean xiaomingTest = predicate.test(xiaoming);
        System.out.println("tomTest = " + tomTest + "\n" + "xiaomingTest=" + xiaomingTest);
    }

    @Test
    public void test02() {
        Predicate<Employee> agePredicate = employee -> employee.getAge() > 30;
        Predicate<Employee> and = agePredicate.and(employee -> employee.getSalary() == 10000);
        System.out.println(and.test(tom));
    }

    @Test
    public void test03(){
        Predicate<Employee> agePredicate = employee -> employee.getAge() > 30;
        Predicate<Employee> negate = agePredicate.negate();
        System.out.println(negate.test(tom));
    }

    @Test
    public void test04(){
        Predicate<Employee> agePredicate = employee -> employee.getAge() > 30;
        Predicate<Employee> salaryPredicate = employee -> employee.getSalary() == 10000;
        Predicate<Employee> or = agePredicate.or(salaryPredicate);
        boolean test = or.test(tom);
        System.out.println(test);
    }

    @Test
    public void test05(){
        //isEqual
        Predicate<Employee> employeePredicate = Predicate.isEqual(tom);
        boolean test = employeePredicate.test(xiaoming);
        System.out.println(test);
    }
}

Function接口

用来根据一个类型的数据得到另一个类型的数据,前者为前置条件,后者为后置条件。

import org.junit.Test;

import java.math.BigDecimal;
import java.util.function.Function;

public class LambdaTest {
	@Test
    public void test10(){
        Function<String, BigDecimal> stringToBigDecimal = BigDecimal::new;
        BigDecimal apply = stringToBigDecimal.apply("123.34");
        System.out.println(apply);
    }
}

import java.util.function.Function;
/**
 * Function<T,R>接口中最主要的抽象方法:R apply(T t),根据类型T的参数获取类型R的结果
 */
public class Demo01Function {
    /**
 * 将String类型转换为Integer类型
 */
    public static void change(String s, Function<String,Integer> fun){
        Integer in = fun.apply(s);
        System.out.println(in);
    }
    public static void main(String[] args) {
        String s = "1234";
        change(s,str->Integer.parseInt(str));
    }
 }

Function接口的默认方法 andThen() 用来组合操作

**compose()的实现与andThen()是相反的

import java.util.function.Function;
/**
 * Function<T,R>接口中的默认方法andThen,用来进行组合操作
 *
 * 需求:
 * 把String类型的“123”,转换为Integer类型,把转换后的结果加10,
 * 然后把增加之后的Integer类型的数据,转换为String类型
 */
public class Demo02Function_andThen {
    public static void change(String s, Function<String,Integer> fun1, Function<Integer,String> fun2){
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }
    public static void main(String[] args) {
        //定义一个字符串
        String s = "123";
        change(s,str->Integer.parseInt(str)+10,i->i+"");
    }
}
//Function的案例
import java.util.function.Function;

/**
 * 需求:
 *      String s = "赵丽颖,20"
 *      1.将自付春截取数字年龄部分,得到字符串
 *        Function<String,String> "赵丽颖,20"->"20"
 *      2.将上一步的字符串转换为int类型的数字
 *        Function<String,Integer> "20"->20
 *      3.将上一步的int数字累加100,得到结果int数字
 *        Function<Integer,Integer> 20+100 -> 120
 */
public class Demo05Test {
    public static int change(String s, Function<String,String> func1, Function<String,Integer> func2, Function<Integer,Integer> func3){
        return func1.andThen(func2).andThen(func3).apply(s);
    }

    public static void main(String[] args) {
        String s = "赵丽颖,20";

        int result = change(s, str -> str.split(",")[1], str -> Integer.parseInt(str), i -> i + 100);
        System.out.println(result);
    }
}
应用案例
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class Demo {
    public static void main(String[] args) {
//        Consumer<Double> consumer = new Consumer<Double>() {
//            @Override
//            public void accept(Double t) {
//                System.out.println("聚餐消费:" + t);
//            }
//        };
        //Consumer
        Consumer<Double> consumer = (t)-> System.out.println("聚餐消费:" + t);
        happy(consumer,1000);
        happy((t)-> System.out.println("唱歌消费:" + t),2000);

        //Supplier
        int[] arr = getNums(()->new Random().nextInt(100),5);
        System.out.println(Arrays.toString(arr));

        //Function
        String result = handlerString(s-> s.toUpperCase(),"hello world");
        System.out.println(result);

        String result2 = handlerString((s->s.trim()),"         zhang   ");
        System.out.println(result2);

        //Predicate
        List<String> list = new ArrayList<>();
        list.add("zhangsan");
        list.add("zhangwuji");
        list.add("lisi");
        list.add("wangwu");
        list.add("zhaoliu");

        List<String> listName = filterNames(s->s.startsWith("zhang"),list);
        System.out.println(listName);

        List<String> listName2 = filterNames(s->s.length() > 5,list);
        System.out.println(listName2);
    }
    //Consumer消费型接口
    public static void happy(Consumer<Double> consumer, double money){
        consumer.accept(money);
    }

    //Supplier 供给接口
    public static int[] getNums(Supplier<Integer> supplier,int count){
        int[] arr = new int[count];
        for(int i = 0;i < count;i++){
            arr[i] = supplier.get();
        }
        return arr;
    }

    //Function函数接口
    public static String handlerString(Function<String,String> function,String str){
        return function.apply(str);
    }

    //Predicate 断言型接口
    public static List<String> filterNames(Predicate<String> predicate, List<String> list){
        List<String> resultList = new ArrayList<>();
        for (String string : list) {
            if(predicate.test(string)){
                resultList.add(string);
            }
        }
        return resultList;
    }
}

装箱拆箱

  • 基本类型和包装类型之间的拆箱和装箱,是要消耗CPU和内存的,对于数据量过大,操作过多,新增了一些函数式接口,可以解决以上问题。
    在这里插入图片描述
import org.junit.Test;

import java.util.function.IntPredicate;


public class LambdaTest {
    @Test
    public void test(){
        IntPredicate intPredicate = a -> a > 0;
        boolean test = intPredicate.test(-1);
        System.out.println(test);
    }
}

Lambda表达式

在这里插入图片描述

  • 使用Lambda表达式的好处
  • Lambda的延迟执行,提升性能(恰恰解决一些在代码执行后,结果不一定会被使用,从而造成性能的浪费) 注:日志可以帮助我们快速定位问题,记录程序运行过程总的情况,以便项目的监控和优化。

/**
 * 日志案例
 * 发现以下代码存在的一些性能浪费的问题
 * 调用showLog方法,传递的第二个参数是一个拼接后的字符窜
 * 先把字符串拼接好,然后在调用showLog方法
 * showLog方法中如果传递的日志等级不是1级
 * 所以感觉字符串白拼接了,造成性能的浪费
 */
public class Demo01Logger {
    //定义一个根据日志的级别,显式日志信息的方法
    public static void showLog(int level,String message){
        //对日志的等级判断
        if(level == 1){
            System.out.println(message);
        }
    }

    public static void main(String[] args){
        //定义三个日志信息
        String msg1 = "Hello";
        String msg2 = "World";
        String msg3 = "Java";

        //调用showLog方法,传递日志级别和日志信息
        showLog(1,msg1 + msg2 + msg3);
    }
}
//优化后
/**
 * 创建拼接消息的函数式接口
 */
@FunctionalInterface
public interface MessageBuilder {
    //定义一个拼接消息的抽象方法
    public abstract String builderMessage();
}

/**
 * 使用Lambda优化日志案例
 * Lambda的特点:延迟加载
 * Lambda的使用前提,必须存在函数式接口
 */
public class Demo01Lambda {
    //定义一个显示日志的方法,方法的参数传递日志的等级和MessageBuilder接口
    public static void showLog(int level,MessageBuilder mb){
        //对日志的等级进行判断,如果是1级,则调用MessageBuilder接口的builderMessage方法
        if(level == 1){
            System.out.println(mb.builderMessage());
        }
    }

    public static void main(String[] args) {
        //定义三个日志信息
        String msg1 = "Hello";
        String msg2 = "World";
        String msg3 = "Java";

        //调用showLog方法,传递日志级别和日志信息
        showLog(2,()->msg1 + msg2 + msg3);

        /**
         * 使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中
         * 只满足条件,日志的等级不是1级,MessageBuilder接口中的方法builderMessage也不会执行
         * 所以拼接字符串的代码也不会执行,不会存在性能的浪费
         */
    }
}
  • 简化匿名内部类的调用

  • Lambda表达式+方法引入 代码会变的更加精简。

Lambda表达式 依赖于函数接口

  • 接口中只能允许有一个抽象方法
  • 函数接口可以重写object类中的方法
  • 可使用默认或者静态方法
  • @FunctionalInterface 标识为函数接口
  • 可以引用外部变量,但不可修改外部变量,匿名内部类同样如此
@FunctionalInterface
public interface MyFunctionalInterface {
    //抽象方法,public abstract默认就有的,可不写
    public abstract void get();

    //默认方法
    default  void set(){
        System.out.println("set");
    }

    //静态方法
    static  void del(){
        System.out.println("del");
    }

    //object父类中的方法可以在函数式接口重写的
    String toString();
}

Lambda基础语法

Lambda表达式由三部分组成:分别是参数列表、箭头、函数体
在这里插入图片描述

():参数列表
->:分割(类似goto)
{}:方法体

  • ()->{}
import org.junit.Test;

import java.util.Comparator;
import java.util.function.Predicate;

public class LambdaTest {
    /**
     * 参数列表
     */
    @Test
    public void test01(){
        //和普通函数一样,Lambda也有参数列表,且表达式相同,如:(ParamType1 param1,ParamType2 param2,...)。
        Comparator<Integer> comparator = (Integer a, Integer b)->{
            return a - b;
        };
        int compare = comparator.compare(1, 3);
        System.out.println("compare = " + compare);
    }

    @Test
    public void test02(){
        //可以省略参数列表参数类型,如(param1,param2,...)。
        Comparator<Integer> comparator = (a,b) ->{
            return a - b;
        };

        int compare = comparator.compare(1, 3);
        System.out.println("compare=" + compare);
    }

    @Test
    public void test03(){
        //如果参数列表只有一个,且省略了参数类型,可以省略(),如param1。
        Predicate<Integer> predicate = a -> {return a > 0;};
        boolean b = predicate.test(1);
        System.out.println(b);
    }

    @Test
    public void test04(){
        //参数列表没有参数,()不能省略
        Runnable runnable = ()->{
            System.out.println("Lambda...");
        };
        runnable.run();
    }

    /**
     * 函数体
     */
    @Test
    public void test05(){
        //如果函数体只有一条语句,可以省略{}
        Runnable runnable = ()-> System.out.println("Lambda...");
        runnable.run();
    }

    @Test
    public void test06(){
        //如果函数体只有一条语句,且函数有返回值,return关键字可省略,参数也只有一个,()也可以省略
        Predicate<Integer> predicate = a -> a > 0;
        boolean test = predicate.test(1);
        System.out.println("test = " + test);
    }
}

Stream流

在这里插入图片描述

  • Stream特点
    在这里插入图片描述
  • Stream使用步骤
    在这里插入图片描述
  • 创建Stream
    在这里插入图片描述
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args) {
        //1、Collection对象中的Stream()和parallelStream()方法
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("apple");
        arrayList.add("huawei");
        arrayList.add("xiaomi");
        //创建Stream流
        Stream<String> stream1 = arrayList.stream();
        //创建Stream流,得到的是parallelStream()--->并行流
        Stream<String> stream2 = arrayList.parallelStream();
        //遍历
        stream1.forEach(s-> System.out.println(s));
        stream1.forEach(System.out::println);

        //2、Arrays工具类的stream方法
        String[] arr = {"aaa","bbb","ccc"};
        Stream<String> stream3 = Arrays.stream(arr);
        stream3.forEach(System.out::println);

        //3、Stream接口中的of方法
        Stream<Integer> stream4 = Stream.of(10,20,30,40,50);
        stream4.forEach(System.out::println);

        //4、Stream接口中的iterate方法,得到的是迭代流
        Stream<Integer> iterate = Stream.iterate(0,x->x+2);
        iterate.limit(10).forEach(System.out::println);

        //4、Stream接口中的generate方法,得到的是生成流
        Stream<Integer> generate = Stream.generate(()->new Random().nextInt(100));
        generate.limit(10).forEach(System.out::println);

        //5、通过IntStream、LongStream、DoubleStream接口中of、range、rangeClosed方法
        IntStream stream5 = IntStream.of(10, 200, 300);
        IntStream stream6 = IntStream.range(0, 50);//结果是前闭后开
        IntStream stream7 = IntStream.rangeClosed(0, 50);//结果是前闭后闭
        stream5.forEach(System.out::println);
        stream6.forEach(System.out::println);
        stream7.forEach(System.out::println);
    }
}
  • 中间操作、终止操作
    在这里插入图片描述
import java.util.Objects;

public class Employee {
    private String name;
    private int age;

    public Employee() {
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age && Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
import java.util.*;
import java.util.stream.Collectors;

public class Test {
    public static void main(String[] args) {
        ArrayList<Employee> list = new ArrayList<>();
        list.add(new Employee("小王",15));
        list.add(new Employee("小张",12));
        list.add(new Employee("小李",18));
        list.add(new Employee("小孙",20));
        list.add(new Employee("小刘",25));
        list.add(new Employee("小刘",25));

        //filter 过滤
        list.stream().filter(e->e.getAge() > 15).forEach(System.out::println);

        //limit 限制
        list.stream().limit(2).forEach(System.out::println);

        //skip 跳过
        list.stream().skip(2).forEach(System.out::println);

        //distinct 去重
        list.stream().distinct().forEach(System.out::println);

        //sorted 排序
        list.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);

        //map 映射
        list.stream().map(e->e.getName()).forEach(System.out::println);

        //parallel 并行流;采用的是多线程,效率高
        list.parallelStream().forEach(System.out::println);

        //终止操作 forEach、min、max、count、reduce(规约)、collect(收集)
        Optional<Employee> min = list.stream().min((e1, e2)->Double.compare(e1.getAge(),e2.getAge()));//Optional防止空指针异常
        System.out.println(min.get());

        long count = list.stream().count();
        System.out.println("员工个数:" + count);

        //计算所有员工的年龄和
        Optional<Integer> sum = list.stream().map(e->e.getAge()).reduce((x,y)->x+y);
        System.out.println(sum.get());

        //获取所有的员工姓名,封装成一个list集合
        List<String> names = list.stream().map(e->e.getName()).collect(Collectors.toList());
        for (String name : names) {
            System.out.println(name);
        }

        //串行流和并行流的区别
        ArrayList<String> lists = new ArrayList<>();

        for (int i = 0; i < 5000000; i++) {
            lists.add(UUID.randomUUID().toString());
        }

        //串行流
        long start1 = System.currentTimeMillis();
        long count1 = list.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge())).count();
        System.out.println(count1);
        long end1 = System.currentTimeMillis();
        System.out.println("串行流用时:" + (end1 - start1));

        //并行流
        long start2 = System.currentTimeMillis();
        long count2 = list.parallelStream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge())).count();
        System.out.println(count2);
        long end2 = System.currentTimeMillis();
        System.out.println("并行流用时:" + (end2 - start2));
    }
}
  • Stream是Java 8中新增用于操作集合的API,使用Stream API可以使我们对集合的操作只需要关注数据变化 ,而不是迭代过程。
  • Stream流:非常方便精简的形式遍历集合实现过滤、排序等,它关注的是做什么,而不是怎么做。
  • Stream流的特点:Stream流属于管道流,只能使用一次(第一个Stream流调用完毕,就会流转到下一个Stream上,这时第一个流使用完毕,就会关闭了)。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

获取流

  • java.util.stream.Stream<T>是JDK8新加入的常用流接口
  • 所有的Collection集合可以通过stream默认方法获取流
  • default Stream<E> stream()

of
  • Stream接口的静态方法of可以获取数组对应的流
  • static <T> Stream<T> of (T... values)

import java.util.*;
import java.util.stream.Stream;

/**
 * Stream的两种获取流方法
 */
public class Demo02GetStream {
    public static void main(String[] args) {
        /**
         * 第一种:所有的Collection集合可以通过stream默认方法获取流
         */
        //集合转换为Stream流
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        Set<String> set = new HashSet<>();
        Stream<String> stream2 = set.stream();

        Map<String,String> map = new HashMap<>();

        //获取键,存储到一个Set集合中
        Set<String> keyset = map.keySet();
        Stream<String> stream3 = keyset.stream();

        //获取值,存储到一个Collection集合中
        Collection<String> values = map.values();
        Stream<String> stream4 = values.stream();

        //获取键值对
        Set<Map.Entry<String,String>> entries = new HashSet<>();
        Stream<Map.Entry<String,String>> stream5 = entries.stream();

        /**
         * 第二种:Stream接口的静态方法of可以获取数组对应的流
         */
        //把数组转换为Stream流
        Stream<Integer> stream6 = Stream.of(1,2,3,4,5);

        //可变参数可以传递数组
        Integer[] arr = {1,2,3,4,5};
        Stream<Integer> stream7 = Stream.of(arr);

        String[] arr2 = {"a","bb","ccc"};
        Stream<String> stream8 = Stream.of(arr2);
    }
}
iterate

通过迭代生成对应的流

@Test
public void test(){
    Stream<Integer> iterate = Stream.iterate(0, x -> x + 2).limit(10);
    iterate.forEach(System.out::println);
}

Arrays.stream()

数组生成流

@Test
public void test(){
   String[] strings = {"a","b","c","d"};
   Arrays.stream(strings).forEach(System.out::println);
}

generate
@Test
public void test(){
   Stream.generate(Math::random).limit(10).forEach(System.out::println);
}

Stream流的中间操作方法

在这里插入图片描述

filter:延迟方法,过滤数据

将一个流转换成另一个子集流,Stream filter(Predicate<? super T> predicate);
在这里插入图片描述

import java.util.stream.Stream;

/**
 * Stream流中常用方法fileter
 * Stream<T> filter(Predicate<? super T> predicate);
 * Predicate函数式接口的抽象方法:boolean test(T t);
 */
public class Demo03Stream_filter {
    public static void main(String[] args) {
        //创建Stream流
        Stream<String> stream = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
        //对Stream流中的元素进行过滤
        Stream<String> stream2 = stream.filter(name -> name.startsWith("张"));
        //遍历stream2流
        stream2.forEach(name-> System.out.println(name));
    }
}
distinct:去重
Stream<T> distinct();

@Test
public void test(){
    List<Employee> employees = DataUtils.getEmployees();
    employees.stream().distinct().collect(Collectors.toList()).forEach(System.out::println);
}

sorted:排序

// 实现 Comparable接口
public class Employee implements Comparable{
	private Long id;
	private String name;
	private Integer age;
	private Double salary;

	public Employee() {
	}

	public Employee(Long id, String name, Integer age, Double salary) {
		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
	}

	// getter/setter/toString

  // 实现CompareTo方法
	@Override
	public int compareTo(Object o) {
		if (o instanceof Employee) {
			Employee e = (Employee) o;
			return this.age - e.getAge();
		} else {
			throw new RuntimeException("类型不正确");
		}
//        Objects.requireNonNull(o);
//        //年龄相同,工资逆序
//        Objects.requireNonNull(o.getAge());
//        Objects.requireNonNull(o.getSalary());
//        if(!this.age.equals(o.getAge())){
//            return this.age - o.getAge();
//        }else{
//            Double r = o.getSalary() - this.salary;
//            return r.intValue();
//        }
	}
}
========================================================
@Test
public void test(){
	Employee employee = new Employee;
	employee.stream().sorted.collect(Collectors.toList()).forEach(System.out::println);
}

map:流中的元素映射到另一个流

在这里插入图片描述

import java.util.stream.Stream;

/**
 * 需要将流中的元素映射到另一个流中,可使用map方法
 * <R> Stream<R> map(Function<? super T, ? extends R> mapper);
 * 该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流
 * Function中的抽象方法:
 *      R apply(T t);
 */
public class Demo04Stream_map {
    public static void main(String[] args) {
        //获取Stream流
        Stream<String> stream = Stream.of("1","2","3","4");

        //使用map方法,把字符串类型的整数,转换(映射)为Integer类型的整数
        Stream<Integer> stream2 = stream.map(s -> Integer.parseInt(s));
        stream2.forEach(System.out::println);
    }
}
count:终结方法 统计Stream流中的元素个数
import java.util.ArrayList;
import java.util.stream.Stream;

/**
 * Stream流中的常用方法_count:用于统计Stream流中元素的个数
 * long count();
 * count方法是一个终结方法,返回值为long类型的整数
 * 所以不能再继续调用Stream流中的其他方法了
 */
public class Demo05Stream_count {
    public static void main(String[] args) {
        //获取Stream流
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);

        Stream<Integer> stream = list.stream();
        long count = stream.count();

        System.out.println(count);
    }
}
切片
limit:延迟方法 对Stream流进行截取,取用前几个

在这里插入图片描述

import java.util.stream.Stream;

/**
 * limit方法可以对流进行截取,只取用前n个
 * Stream<T> limit(long maxSize);
 *
 * Stream流中的常用方法_limit:用于截取流中的元素
 * limit方法是一个延迟方法,只是对流中的元素进行截取,返回的是一个新的流,
 * 所以可以继续调用Stream流中的其他方法
 */
public class Demo06Stream_limit {
    public static void main(String[] args) {
        //获取Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼"};
        Stream<String> stream = Stream.of(arr);

        //截取前3个元素
        Stream<String> stream1 = stream.limit(3);
        stream1.forEach(System.out::println);
    }
}
skip: 跳过前几个元素

在这里插入图片描述

import java.util.stream.Stream;

/**
 * Stream流中的常用方法_skip:用于跳过元素
 * 如果跳过前几个元素,可以使用skip方法获取一个截取之后的新流:
 * Stream<T> skip(long n);
 * 如果流的当前长度大于你,则跳过前n个;否则将会得到一个长度为0的空流
 */
public class Demo07Stream_skip {
    public static void main(String[] args) {
        //获取Stream流
        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼"};
        Stream<String> stream = Stream.of(arr);

        //跳过前3个元素
        Stream<String> stream1 = stream.skip(3);
        stream1.forEach(System.out::println);
    }
}
concat:用于把流组合到一起
import java.util.stream.Stream;

/**
 * Stream流中的常用方法_concat:用于把流组合到一起
 *
 * 如果两个流,希望合并为一个流,那么可以使用Stream接口的静态方法concat
 * static <T> Stream<T> concat(Stream<? extends T> a,Stream<? extends T> b)
 */
public class Demo08Stream_concat {
    public static void main(String[] args) {
        //创建Stream流
        Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");

        String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼"};
        Stream<String> stream2 = Stream.of(arr);

        //将两个流组合成一个流
        Stream.concat(stream1,stream2).forEach(System.out::println);
    }
}
//Stream流的综合案例

/**
 * 定义Person类
 */
public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
====================================================
import java.util.ArrayList;
import java.util.stream.Stream;

public class Demo01StreamTest {
    public static void main(String[] args) {
        ArrayList<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("石破天");
        one.add("石中玉");
        one.add("老子");
        one.add("庄子");
        one.add("洪七公");
        //第一种:传统方法实现
//        ArrayList<String> one1 = new ArrayList<>();
        //过滤长度为3的名字
//        for (String s : one) {
//            if(s.length() == 3){
//                one1.add(s);
//            }
//        }
        //添加前两个名字进入新的集合
//        ArrayList<String> one2 = new ArrayList<>();
//        for (int i = 0; i < 3; i++) {
//            one2.add(one1.get(i));
//        }

        //第二种:通过Stream流方法实现
        Stream<String> oneStream = one.stream().filter(name -> name.length() == 3).limit(3);;

        ArrayList<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("赵丽颖");
        two.add("张三丰");
        two.add("尼古拉斯赵四");
        two.add("张天爱");
        two.add("张二狗");

        //第一种:传统方法实现
//        ArrayList<String> two1 = new ArrayList<>();
        //过滤”张“的名字
//        for (String s : two) {
//            if(s.startsWith("张")){
//                two1.add(s);
//            }
//        }
//
//        ArrayList<String> two2 = new ArrayList<>();
        //不要前两个名字
//        for(int i = 2;i < two1.size();i++){
//            two2.add(two1.get(i));
//        }
//
//        ArrayList<String> all = new ArrayList<>();
//        all.addAll(one2);
//        all.addAll(two2);
//
//        ArrayList<Person> list = new ArrayList<>();
		//将姓名添加到list集合
//        for (String name : all) {
//            list.add(new Person(name));
//        }
		//打印Person对象的信息
//        for (Person person : list) {
//            System.out.println(person);
//        }

        //第二种:通过Stream流方法实现
        Stream<String> twoStream = two.stream().filter(name -> name.startsWith("张")).skip(2);
        Stream.concat(oneStream,twoStream).map(name->new Person(name)).forEach(System.out::println);
    }
}
forEach:终结方法,遍历流中的数据
import java.util.stream.Stream;

/**
 * Stream流中常用方法forEach
 * void forEach(Consumer<? super T> action);
 * Consumer函数式接口的抽象方法:void accept(T t);
 */
public class Demo02Stream_forEach {
    public static void main(String[] args) {
        //获取Stream流
        Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六");
        stream.forEach(name-> System.out.println(name));
    }
}

方法引用

  • 结合Lambda表达式让代码变得更加精简
  • 双冒号::为引用运算符,被称为方法引用
  • Lambda表达式:s->System.out.println(s);

  • 方法引用写法:System.out::println;

/**
 * 定义打印的函数式接口
 */

@FunctionalInterface
public interface Printable {
    //定义字符串打印的抽象方法
    void print(String s);
}
================================================================================
public class Demo01Printable {
    //定义一个方法,参数传递Printable接口,对字符串进行打印
    public static void printString(Printable p){
        p.print("HelloWorld");
    }

    public static void main(String[] args) {
        //调用printString方法,方法的参数Printable是一个函数式接口
        printString(s-> System.out.println(s));
        System.out.println("=======================");
        /**
         *  分析:
         *      Lambda表达式的目的,打印参数传递的字符串
         *      把参数s,传递给了System.out对象,调用out对象中的方法println,对字符串进行了输出
         *      注意:
         *          1.System.out对象是已经存在了
         *          2.println方法也是已经存在的
         *      所以我们可以使用方法引用来优化Lambda表达式
         *      可以使用System.out对象,进行方法直接引用(调用)println方法
         *      System.out::println
         */
        //System.out对象的方法引用
        printString(System.out::println);
    }
}

a. 匿名内部类使用
b. Lambda调用匿名内部类
c. 方法引用

静态方法引用:类名::(静态)方法名称

/**
 * 定义计算接口
 */
@FunctionalInterface
public interface Calcable {
    //定义一个抽象方法,传递一个整数,对整数进行绝对值计算并返回
    int calsAbs(int number);
}
===========================================================================================
/**
 * 静态方法引用:类名::(静态)方法名称
 *
 * 通过类名引用静态成员方法
 * 类名存在
 * 静态成员方法存在
 * 就可以通过类名直接引用静态成员方法
 */
public class Demo01StaticMethodReference {
    //定义一个方法,方法的参数传递要计算绝对值的整数、函数式接口Calcable
    public static int method(int number,Calcable c){
        return c.calsAbs(number);
    }

    public static void main(String[] args) {
        //调用method方法,传递计算绝对值的整数,使用Lambda表达式
        int number = method(-10,(n)->{
            return Math.abs(n);
        });
        System.out.println(number);
        System.out.println("====================");
        /**
         * 使用方法引用优化Lambda表达式
         * Math类存在
         * abs()
         *
         * 静态方法引用:类名::(静态)方法名称
         */
        int num = method(-10,Math::abs);
        System.out.println(num);
    }
}

super方法引用:super:: 父类成员方法名称

/**
 * 定义见面的函数式接口
 *
 */
@FunctionalInterface
public interface Greetable {
    //定义见面的抽象方法
    void greet();
}
============================================================================================
/**
 * 定义Human父类
 */
public class Human {
    //定义一个sayHello的方法
    public void sayHello(){
        System.out.println("Hello 我是Human!");
    }
}
============================================================================================
/**
 * 定义Man子类
 */
public class Man extends Human{
    //子类重写父类sayHello()

    @Override
    public void sayHello() {
        System.out.println("Hello 我是Man!");
    }

    //定义一个方法参数传递Greetable接口
    public void method(Greetable g){
        g.greet();
    }

    public void show(){
        //调用method方法,方法的参数Greetable是一个函数式接口,所以可使用Lambda表达式
//        method(()->{
//            //创建父类对象
//            Human h = new Human();
//            //调用父类的sayHello()
//            h.sayHello();
//        });

        //因为有子父类关系,所以存在一个关键字:super(代表父类),可使用super调用父类的成员方法
        method(()->super.sayHello());
        System.out.println("=================");
        /**
         * 使用super引用类成员方法
         * super存在
         * 父类的成员方法sayHello()也存在
         *
         * 所以我们可以直接使用super引用父类的成员方法
         * super:: 父类成员方法名称
         */
        method(super::sayHello);
    }

    public static void main(String[] args) {
        new Man().show();
    }
}

this方法引用:this:: 本类成员方法名称

/**
 * 定义一个富有的函数式接口
 */
@FunctionalInterface
public interface Richable {
    void buy();
}
============================================================================================
/**
 * 通过this引用本类的成员方法
 */
public class Husband {
    //定义买房的方法
    public void buyHouse(){
        System.out.println("北京二环内买一套四合院!");
    }

    //定义一个结婚的方法,参数传递Richable接口
    public void marry(Richable r){
        r.buy();
    }

    public void soHappy(){
        //调用结婚的方法,方法的参数Richable是一个函数式接口,传递Lambda表达式
        //使用this.成员方法,调用本类房子的方法
        marry(()->this.buyHouse());
        System.out.println("===============");

        /**
         * 使用方法引用优化Lambda表达式
         * this存在
         * 本类的成员方法buyHouse也是存在的
         *
         * 所以可直接使用this引用本类的成员方法buyHouse
         * this::本类成员方法名称
         *
         */
        marry(this::buyHouse);
    }

    public static void main(String[] args) {
        new Husband().soHappy();
    }
}

对象方法引用:对象:: 实例方法名称

/**
 * 对象方法引用:对象::  实例方法名称
 * 通过对象名引用成员方法
 * 使用前提是对象名是已经存在的,成员方法也是已经存在
 * 就可以使用对象名来引用成员方法
 */
 ============================================================================================
 /**
 * 定义打印的函数式接口
 */
@FunctionalInterface
public interface Printable {
    //定义字符串打印的抽象方法
    void print(String s);
}
============================================================================================
/**
 * 通过对象名引用成员方法
 */
public class MethodRerObject {
    //定义成员方法,传递字符串,把字符串按照大写输出
    public void printUpperCaseString(String s){
        System.out.println(s.toUpperCase());
    }
}
============================================================================================
public class Demo01ObjectMethodReference {
    //定义一个方法,方法的参数传递Printable接口
    public static void printString(Printable p){
        p.print("Hello");
    }

    public static void main(String[] args) {
        //调用printString方法,方法的参数Printable是一个函数式接口,所以可以传递Lambda表达式
        printString((s)->{
            //创建MethodRerObject对象
            MethodRerObject obj = new MethodRerObject();
            //调用MethodRerObject对象中的成员方法printUpperCaseString()
            obj.printUpperCaseString(s);
        });

        System.out.println("======================");
        /**
         * 使用方法引用来优化Lambda
         * 对象已经存在 MethodRerObject
         * 成员方法也已经存在 printUpperCaseString()
         */
        MethodRerObject obj = new MethodRerObject();
        //通过对象名引用成员方法
        printString(obj::printUpperCaseString);
    }
}

构造器引用:类名:: new

/**
 * 定义Person类
 */
public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
============================================================================================
/**
 * 定义一个创建Person对象的函数式接口
 */
@FunctionalInterface
public interface PersonBuilder {
    //定义一个方法,根据传递的姓名,创建Person对象返回
    Person builderPerson(String name);
}
============================================================================================
/**
 * 类的构造器(构造方法)引用
 */
public class Demo {
    //定义一个方法,参数传递姓名和PersonBuilder接口,方法中通过姓名创建Person对象
    public static void printName(String name,PersonBuilder pb){
        Person person = pb.builderPerson(name);
        System.out.println(person.getName());
    }

    public static void main(String[] args) {
        //调用printName方法,方法的参数PersonBuilder接口是一个函数式接口,可以使用Lambda表达式
        printName("赵丽颖",(name)->{
            return new Person(name);
        });
        System.out.println("=====================");

        /**
         * 使用方法引用优化Lambda表达式
         * 构造方法new Person()存在
         * 创建对象 new也是存在的
         *
         * 所以就可以使用Person引用new创建对象
         * Person::new
         */
        printName("赵丽颖",Person::new);
    }
}

数组的构造器引用:数组类型::new

/**
 * 定义一个创建数组的函数式接口
 *
 */
@FunctionalInterface
public interface ArrayBuilder {
    //定义一个创建int类型数组的方法,参数传递数组的长度,返回创建好的int类型数组
    int[] builderArray(int length);
}
============================================================================================
/**
 * 数组的构造器引用
 *
 */
public class ArrayDemo {
    /**
     * 定义一个方法
     * 方法的参数传递创建数组的长度和ArrayBuilder接口
     * 方法内部根据传递的长度使用ArrayBuilder中的方法创建数组并返回
     *
     */
    public static int[] createArray(int length,ArrayBuilder ab){
        return ab.builderArray(length);
    }

    public static void main(String[] args) {
        //调用createArray方法,传递数组的长度和Lambda表达式
        int[] arr = createArray(10,(len)->{
            //根据数组长度,创建数组
            return new int[len];
        });
        System.out.println(arr.length);
        System.out.println("==================");

        /**
         * 使用方法引用优化Lambda表达式
         * int[]数组存在
         * 数组的长度也存在
         *
         * 所以就可以使用方法引用
         * int[]::new
         */
        int[] arr1 = createArray(10,int[]::new);
        System.out.println(arr1.length);
    }
}

需要遵循一个规范:
方法引用:方法参数列表、返回类型与函数接口参数列表与返回类型必须要保持一致。实际上就是将Lambda表达式中方法体直接引入方法。

public class Employee {
    private String name;
    private int age;

    public Employee() {
    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 1. 对象::实例方法
 * 2. 类::静态方法
 * 3. 类::实例方法
 * 4. 类::new
 */
public class Demo {
    public static void main(String[] args) {
        Consumer<String> consumer = s-> System.out.println(s);
        //对象::实例方法
        Consumer<String> consumer1 = System.out::println;
        consumer.accept("hello");

        Comparator<Integer> com = (o1,o2)->Integer.compare(o1,o2);
        //类::静态方法
        Comparator<Integer> com1 = Integer::compare;

        Function<Employee,String> function = e->e.getName();
        //类::实例方法
        Function<Employee,String> function1 = Employee::getName;
        System.out.println(function.apply(new Employee("xiaoming",50000)));

        //类::new
        Supplier<Employee> supplier = ()->new Employee();
        Supplier<Employee> supplier1 = Employee::new;

        Employee employee =supplier.get();
        System.out.println(employee.toString());
    }
}

Optional

Optional类是一个可以为null的容器,可以保存类型T的值。

empty:获取一个value为null的Optional对象

@Test
public void test01() {
  Optional<String> empty = Optional.empty();
}


ofNullable:可以允许传递一个null对象

@Test
public void test03() {
  Optional<String> nullable = Optional.ofNullable("Can be null");
}

of:不允许传递一个空值对象

@Test
public void test02() {
  Optional<String> string = Optional.of("Cant not be null");
}

get: 用于获取Optional中的value的值

@Test
public void test04() {
  Optional<Integer> integer = Optional.of(100);
  // 调用get方法获取 value 中保存的值
  Integer integer1 = integer.get();
}

isPresent:返回false,值为空;返回true,值不为空。

@Test
public void test05() {
  Optional<Integer> integer = Optional.of(100);
  // 值存在返回true 
  boolean present = integer.isPresent();
}

  • 使用get()获取值时,要与isPresent()配合起来使用,避免报异常"java.util.NoSuchElementException: No value present"
@Test
public void test02(){
   Optional<Employee> employee = Optional.of(this.employee);
   if(employee.isPresent()){
       System.out.println(employee.get());
   }

   Optional<Object> empty = Optional.empty();
   if(empty.isPresent()){
       System.out.println(empty.get());
   }
}

ifPresent:用于判断值是否存在

该方法接收一个Comsumer类型参数,用于判断值是否存在,如果存在就执行Comsumer操作

@Test
public void test06() {
  Optional<Integer> integer = Optional.of(100);
  // 如果值存在,将值打印出来
  integer.ifPresent(System.out::println);
}

操作值

filter: 过滤值

该方法接收一个Predicate参数,如果Optional中的值满足参数条件,就返回该Optional,否则返回空的Optional,如果原来Optional中值为null,新生成的Optional中值也为null

@Test
public void test07() {
  Optional<Integer> integer = Optional.of(100);
  // 因为100 不大于 200  所以返回的是一个 empty Optional
  Optional<Integer> filter = integer.filter(x -> x > 200);
}

map: 操作值返回新值

该方法接收一上Function类型对象,接收Optional中的值,生成一个新值包装成Optional并返回,如果原来Optional中值为null,新生成的Optional中值也为null

@Test
public void test08() {
  Optional<Integer> integer = Optional.ofNullable(100);
  // 将`Optional`中的值 100 + 20 返回 生成新的`Optional`返回
  Optional<Integer> integer1 = integer.map(x -> x + 20);
}
flatMap: 接收一个Function参数

该Function参数返回一个Optional对象

@Test
public void test09() {
  Optional<Integer> integer = Optional.of(100);
  // Optional<Long> longOptional 是由flatMap的参数定义生成的
  Optional<Long> longOptional = integer.flatMap(x -> Optional.ofNullable(x.longValue()));
}

orElse:如果值为空,可设定默认值

@Test
public void test10() {
  Optional<Integer> integer = Optional.ofNullable(null);
  // 因为 Optional 中的值为 null ,所以会生成一个值为20的新的
  Integer integer1 = integer.orElse(20);
}

orElseGet:如果值为空,可接收一个Supplier参数

该方法接收一个Supplier参数,用于在Optional中的值为null时返回Supplier生成的值

@Test
public void test11() {
  Optional<Integer> integer = Optional.ofNullable(null);
  Integer integer1 = integer.orElseGet(() -> 20);
}

orElseThrow: 如果值为空,可接受Supplier参数

该方法接收一个Supplier参数,该Supplier生成一个异常,用于在Optional中的值为null时抛出该异常

@Test
public void test12() {
  Optional<Integer> o = Optional.ofNullable(null);
  o.orElseThrow(RuntimeException::new);
}

Date

SimpleDateFormat线程安全问题

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test {
    public static void main(String[] args) throws Exception{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

        ExecutorService pool = Executors.newFixedThreadPool(10);

        Callable<Date> callable = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                //synchronized同步代码块解决线程不安全的问题,java.lang.NumberFormatException是因线程不安全造成的
                synchronized (sdf){
                    return sdf.parse("20200215");
                }
            }
        };

        List<Future<Date>> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Future<Date> task = pool.submit(callable);
            list.add(task);
        }

        for (Future<Date> future : list) {
            System.out.println(future.get());
        }

        pool.shutdown();
    }
}

class Test1{
    public static void main(String[] args) throws Exception{
        //JDK1.8新特性,避免了线程不安全的问题
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");

        ExecutorService pool = Executors.newFixedThreadPool(10);

        Callable<LocalDate> callable = new Callable<LocalDate>() {
            @Override
            public LocalDate call() throws Exception {
                return LocalDate.parse("20200215",dtf);
            }
        };

        List<Future<LocalDate>> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Future<LocalDate> task = pool.submit(callable);
            list.add(task);
        }

        for (Future<LocalDate> future : list) {
            System.out.println(future.get());
        }

        pool.shutdown();
    }
}

新时间API

在这里插入图片描述

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Set;

public class Test {
    public static void main(String[] args) throws Exception{
        //创建本地时间
        //方式一:
        LocalDateTime localDateTime = LocalDateTime.now();
        //方式二:
//        LocalDateTime localDateTime1 = LocalDateTime.of(2020,04,05,12,34);
        System.out.println(localDateTime);
        System.out.println(localDateTime.getYear());
        System.out.println(localDateTime.getMonthValue());
        System.out.println(localDateTime.getDayOfMonth());

        //添加两天
        LocalDateTime localDateTime1 = localDateTime.plusDays(2);
        System.out.println(localDateTime1);

        //减少一个月
        LocalDateTime localDateTime2 = localDateTime.minusMonths(1);
        System.out.println(localDateTime2);

        //Instant 时间戳
        Instant instant = Instant.now();
        System.out.println(instant.toString());
        System.out.println(instant.toEpochMilli());//毫秒
        System.out.println(System.currentTimeMillis());

        //添加减少时间
        Instant instant1 = instant.plusSeconds(10);
        System.out.println(Duration.between(instant,instant1).toMillis());//打印时间差

        //ZoneId 时区
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        for (String availableZoneId : availableZoneIds) {
            System.out.println(availableZoneId);
        }

        System.out.println(ZoneId.systemDefault().toString());//打印当前时区

        //Date--->Instant--->LocalDateTime的转换
        Date date = new Date();
        Instant instant2 = date.toInstant();
        System.out.println(instant2);

        LocalDateTime localDateTime3 = LocalDateTime.ofInstant(instant2,ZoneId.systemDefault());
        System.out.println(localDateTime3);

        System.out.println("------------------------------");
        //LocalDateTime--->Instant--->Date的转换
        Instant instant3 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
        System.out.println(instant3);
        Date from = Date.from(instant3);
        System.out.println(from);


        //DateTimeFormatter:格式化类,线程安全的类
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //把时间格式化字符串
        String format = dtf.format(LocalDateTime.now());
        System.out.println(format);

        //把字符串解析成时间
        LocalDateTime localDateTime4 = LocalDateTime.parse("2020-03-10 10:34:23",dtf);
        System.out.println(localDateTime4);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值