欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaSE之JDK1.8新特性

程序员文章站 2022-08-18 09:23:18
一、Lambda表达式1、Lambda表达式简介Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。lambda表达式的本质是一个匿名方。2、Lambda表达式使用前提使用Lambda必须具有且仅有一个抽象方法接口,且要求接口中有且仅有一个抽象方法。使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。3、Lambda表达式的格式Lambda省...

一、Lambda表达式

1、Lambda表达式简介

Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。lambda表达式的本质是一个匿名方。

2、Lambda表达式使用前提

  • 使用Lambda必须具有且仅有一个抽象方法接口,且要求接口中有且仅有一个抽象方法。
  • 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

3、Lambda表达式的格式

Lambda省去面向对象的条条框框,格式由3个部分组成:参数列表,箭头,实现代码;标准格式为:

        (参数类型 参数名称) ‐> { 代码语句 }
        格式说明:
                小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
                -> 是新引入的语法格式,代表指向动作。
                大括号内的语法与传统方法体要求基本一致。

4、Lambda表达式的使用

无参无返回值的Lambda表达式

// 使用匿名内部类
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程启动");
    }
});
 
// 使用Lambda表达式
new Thread(() -> { System.out.println(Thread.currentThread().getName() + "线程启动"); });
 
// 使用Lambda表达式简化形式
new Thread(() -> System.out.println(Thread.currentThread().getName() + "线程启动"));

有参有返回值的Lambda表达式

// 使用匿名内部类,获取该目录下所有的文件或者文件夹的File数组
File[] files = dir.listFiles(new FileFilter() {
    @Override
    public boolean accept(File pathname) {
        return pathname.isDirectory() || pathname.getName().endsWith(".java");
    }
});
 
// 使用Lambda表达式
files = dir.listFiles((File pathname) -> {
        return pathname.isDirectory() || pathname.getName().endsWith(".java");
    }
);
 
// 使用Lambda表达式的简化形式
files = dir.listFiles(pathname -> pathname.isDirectory() || pathname.getName().endsWith(".java"));

二、函数式接口

1、Supplier:生产数据

package com.wedu.test;

/**
 * public interface Supplier<T> 生产数据
 * T get():获得结果。
 */
import java.util.function.Supplier;

public class Demo {
    public static void main(String[] args) {
        //匿名内部类
        String str = method(new Supplier<String>() {
            @Override
            public String get() {
                return "Hello";
            }
        });
        System.out.println(str);
        
        //Lambda表达式
        str = method(()-> {
            return "Hello";
        });
        System.out.println(str);
        
        //简化Lambda
        str = method(()-> "Hello");
        System.out.println(str);
    }

    private static String method(Supplier<String> supplier){
        return supplier.get();
    }
}

2、 Consumer:消费数据

package com.wedu.test;

/**
 * java.util.function.Consumer<T>接口,与Supplier接口相反,消费数据
 */
import java.util.function.Consumer;

public class Demo {

    public static void main(String[] args) {
        testAccept();

        System.out.println("------------------------");

        testAndThen();
    }

    private static void testAndThen() {
        //匿名内部类
        method1("Hello", new Consumer<String>() {
            @Override
            public void accept(String name) {
                System.out.println(name.toLowerCase());
            }
        }, new Consumer<String>() {
            @Override
            public void accept(String name) {
                System.out.println(name.toUpperCase());
            }
        });

        //Lambda表达式
        method1("Hello", (String name) -> {
            System.out.println(name.toLowerCase());
        }, (String name) -> {
            System.out.println(name.toUpperCase());
        });

        //简化Lambda
        method1("Hello", name -> System.out.println(name.toLowerCase()), name -> System.out.println(name.toUpperCase()));
    }

    /**
     * default Consumer<T> andThen(Consumer<? super T> after):把两个Consumer接口组合到一起,在对数据进行消费(谁写前边谁先消费)
     * @param name 进行消费的数据
     * @param consumer1 数据消费的方式1
     * @param consumer2 数据消费的方式2
     */
    private static void method1(String name,Consumer<String> consumer1,Consumer<String> consumer2) {
        consumer1.andThen(consumer2).accept(name);
    }

    private static void testAccept() {
        //匿名内部类
        method("Jack", new Consumer<String>() {
            @Override
            public void accept(String name) {
                System.out.println(new StringBuffer(name).reverse().toString());
            }
        });

        //Lambda表达式
        method("Jack",(String name) -> {
            System.out.println(new StringBuffer(name).reverse().toString());
        });

        //简化Lambda
        method("Jack",name -> System.out.println(new StringBuffer(name).reverse().toString()));
    }

    /**
     * void accept(T t):对给定的参数执行此操作。
     * @param name 进行消费的数据
     * @param consumer 数据消费的方式
     */
    private static void method(String name,Consumer<String> consumer){
        consumer.accept(name);
    }
}

3、Predicate:数据判断

package com.wedu.test;

import java.util.function.Predicate;

/**
 * java.util.function.Predicate<T>接口:对数据进行判断
 */
public class Demo {

    public static void main(String[] args) {
        isFlag();

        testAnd();
    }

    private static void testAnd() {
        //匿名内部类
        System.out.println(check("abcdef", new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length() > 3;
            }
        }, new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.contains("cd");
            }
        }));

        //Lambda表达式
        System.out.println(check("abcdef",(String str) -> {
            return str.length() > 3;
        },(String str) -> {
            return str.contains("cd");
        }));

        //简化Lambda
        System.out.println(check("abcdef",s -> s.length() >3,s -> s.contains("cd")));
    }

    /**
     * default Predicate<T> and(Predicate<? super T> other) 用于连接两个判断条件,两个都为真时为真
     * @param str 需要判断的数据
     * @param predicate1 判断条件1
     * @param predicate2 判断条件2
     * @return 判断结果
     */
    private static boolean check(String str,Predicate<String> predicate1,Predicate<String> predicate2){
        return predicate1.and(predicate2).test(str);
    }

    private static void isFlag() {
        //匿名内部类
        System.out.println(check("abcdef", new Predicate<String>() {
            @Override
            public boolean test(String str) {
                return str.length() > 3;
            }
        }));

        //Lambda表达式
        System.out.println(check("abcdef",(String str) -> {
            return str.length() > 3;
        }));

        //简化Lambda
        System.out.println(check("abcdef",str -> str.length() > 3));
    }

    /**
     * boolean test(T t):对指定数据类型数据进行判断
     * @param str 需要判断的数据
     * @param predicate 判断的条件
     * @return 判断结果
     */
    private static boolean check(String str, Predicate<String> predicate){
        return predicate.test(str);
    }
}

4、Function:根据一个类型的数据得到另一个类型的数据 

package com.wedu.test;

import java.util.function.Function;

/**
 * public interface Function<T,R> :根据一个类型的数据得到另一个类型的数据
 */
public class Demo {

    public static void main(String[] args) {
        testApply();

        testAndThen();
    }

    private static void testAndThen() {
        //匿名内部类
        changeType("1234", new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s) + 100;
            }
        }, new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) {
                return integer + "";
            }
        });

        //Lambda表达式
        changeType("1234",(String s) -> {
            return Integer.parseInt(s) + 100;
        },(Integer i) -> {
            return i + "";
        });

        //简化Lambda
        changeType("1234",s -> Integer.parseInt(s),i -> i + "");
    }

    /**
     * default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
     * @param s 使用的数据
     * @param fun1 数据类型转换1
     * @param fun2 数据类型转换2
     */
    private static void changeType(String s, Function<String,Integer> fun1,Function<Integer,String> fun2){
        System.out.println(fun1.andThen(fun2).apply(s));
    }

    private static void testApply() {
        //匿名内部类
        changeType("1234", new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s);
            }
        });

        //Lambda表达式
        changeType("1234",(String s) -> {
            return Integer.parseInt(s);
        });

        //简化Lambda
        changeType("1234",s -> Integer.parseInt(s));
    }

    /**
     * R apply(T t):根据类型T的参数获取类型R的结果
     * @param s 使用的数据
     * @param fun 数据类型转换
     */
    private static void changeType(String s, Function<String,Integer> fun){
        System.out.println(fun.apply(s));
    }
}

三、方法引用和构造器引用

1、方法引用的概念

双冒号:: 为引用运算符,而它所在的表达式被称为方法引用。

如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。(可以将方法引用理解为 Lambda 表达式的另外一种表现形式)。

方法引用的前提:对象和方法必须已经存在。

2、方法引用的方式

对象 :: 实例方法名

Employee employee = new Employee(101, "张三", 18, 9999.99);

// 匿名函数
Supplier<String> supplier = new Supplier<String>() {
    @Override
    public String get() {
        return employee.getName();
    }
};
System.out.println(supplier.get());

// Lambda表达式
supplier = () -> employee.getName();
System.out.println(supplier.get());

// 方法引用
supplier = employee::getName;
System.out.println(supplier.get());

类名 :: 静态方法名

// 匿名函数
BiFunction<Double, Double, Double> biFunction = new BiFunction<Double, Double, Double>() {
    @Override
    public Double apply(Double x, Double y) {
        return Math.max(x,y);
    }
};
System.out.println(biFunction.apply(98.0,98.0));

// Lambda表达式
biFunction = (x,y) -> Math.max(x,y);
System.out.println(biFunction.apply(97.0,55.0));

// 方法引用
biFunction = Math::max;
System.out.println(biFunction.apply(55.0,99.0));

 类名 :: 实例方法名

// 匿名函数
BiPredicate<String,String> biPredicate = new BiPredicate<String, String>() {
    @Override
    public boolean test(String x, String y) {
        return x.equals(y);
    }
};
System.out.println(biPredicate.test("hello","hello"));

// Lambda表达式
biPredicate = (x,y) -> x.equals(y);
System.out.println(biPredicate.test("Hello","hello"));

// 方法引用
biPredicate = String::equals;
System.out.println(biPredicate.test("Hello world","Hello world"));

注意:

  • 方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
  • 若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName。

构造器引用:类名 :: new

// 匿名函数
Supplier<Employee> supplier = new Supplier<Employee>() {
    @Override
    public Employee get() {
        return new Employee();
    }
};
System.out.println(supplier.get());

// Lambda表达式
supplier = () -> new Employee();
System.out.println(supplier.get());

// 方法引用
supplier = Employee::new;
System.out.println(supplier.get());

 注意:构造器的参数列表,需要与函数式接口中参数列表保持一致!

四、Stream流

1、创建 Stream

//1. Collection 提供了两个方法  stream() 与 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream();
Stream<String> parallelStream = list.parallelStream();

//2. 通过 Arrays 中的 stream() 获取一个数组流
Stream<Integer> integerStream = Arrays.stream(new Integer[10]);

//3. 通过 Stream 类中静态方法 of()
integerStream = Stream.of(1, 2, 3, 4, 5, 6);

//4. 创建无限流(迭代)
integerStream = Stream.iterate(0, x -> x + 2).limit(10);
integerStream.forEach(System.out::println);

//5. 生成
Stream<Double> doubleStream = Stream.generate(Math::random).limit(2);
doubleStream.forEach(System.out::println);

2、中间操作

数据准备

List<Employee> emps = Arrays.asList(
        new Employee(102, "李四", 59, 6666.66),
        new Employee(101, "张三", 18, 9999.99),
        new Employee(103, "王五", 28, 3333.33),
        new Employee(104, "赵六", 8, 7777.77),
        new Employee(104, "赵六", 8, 7777.77),
        new Employee(104, "赵六", 8, 7777.77),
        new Employee(105, "田七", 38, 5555.55)
);

List<String> stringList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");

filter——接收 Lambda , 从流中排除某些元素(内部迭代:迭代操作 Stream API 内部完成)

//所有的中间操作不会做任何的处理
Stream<Employee> stream = emps.stream().filter(employee -> employee.getAge() <= 35);
//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
stream.forEach(System.out::println);

 limit——截断流,使其元素不超过给定数量。

emps.stream()
        .filter(employee -> employee.getSalary() > 5000)
        .limit(3)
        .forEach(System.out::println);

skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补

emps.parallelStream()
        .filter(employee -> employee.getSalary() > 5000)
        .skip(2)
        .forEach(System.out::println);

distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素

emps.stream()
        .distinct()
        .forEach(System.out::println);

map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

private static void test5(List<String> stringList) {
    stringList.stream().map(String::toUpperCase).forEach(System.out::println);

    stringList.stream()
            .map(MiddleOperationStreamTest::filterCharacter)
            .forEach(stream -> stream.forEach(System.out::println));
}

private static Stream<Character> filterCharacter(String s) {
    List<Character> list = new ArrayList<>();
    for (char ch : s.toCharArray()) {
        list.add(ch);
    }
    return list.stream();
}

flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

stringList.stream()
        .flatMap(MiddleOperationStreamTest::filterCharacter)
        .forEach(System.out::println);

sorted()——自然排序

emps.stream()
        .map(Employee::getName)
        .distinct()
        .sorted()
        .forEach(System.out::println);

 sorted(Comparator com)——定制排序

emps.stream()
        .distinct()
        .sorted((x,y) -> {
            if(x.getAge() == y.getAge()) {
                return x.getName().compareTo(x.getName());
            } else {
                return Integer.compare(x.getAge(),y.getAge());
            }
        }).forEach(System.out::println);

3、终止操作(终端操作)

//allMatch——检查是否匹配所有元素
boolean flag = emps.stream()
        .distinct()
        .allMatch(employee -> employee.getStatus().equals(Employee.Status.BUSY));
System.out.println(flag);

//anyMatch——检查是否至少匹配一个元素
flag = emps.stream().anyMatch(employee -> employee.getStatus().equals(Employee.Status.BUSY));
System.out.println(flag);

//noneMatch——检查是否没有匹配的元素
flag = emps.stream().noneMatch(employee -> employee.getStatus().equals(Employee.Status.BUSY));
System.out.println(flag);

//findFirst——返回第一个元素
Optional<Employee> optional = emps.stream()
        .sorted(Comparator.comparing(Employee::getStatus)).findFirst();
System.out.println(optional.get());

//findAny——返回当前流中的任意元素
optional = emps.parallelStream()
        .filter(employee -> employee.getStatus().equals(Employee.Status.FREE))
        .findAny();
System.out.println(optional.get());

//count——返回流中元素的总个数
long count = emps.stream()
        .filter(employee -> employee.getStatus().equals(Employee.Status.FREE))
        .count();
System.out.println(count);

//max——返回流中最大值
Optional<Double> optional = emps.stream()
        .map(Employee::getSalary)
        .max(Double::compare);
System.out.println(optional.get());

//min——返回流中最小值
Optional<Employee> employeeOptional = emps.stream().min(Comparator.comparing(Employee::getSalary));
System.out.println(employeeOptional.get());

五、时间日期API

1、Instant : 时间戳

Instant ins1 = Instant.now();

System.out.println("--------------------");
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
}

Instant ins2 = Instant.now();

Duration duration = Duration.between(ins1, ins2);
System.out.println(duration.toMillis());

2、DateTimeFormatter : 解析和格式化日期或时间

DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;
LocalDateTime ldt = LocalDateTime.now();
String strDate = ldt.format(dtf);
System.out.println(strDate);

System.out.println("------------------------");

dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
ldt = LocalDateTime.now();
strDate = ldt.format(dtf);
System.out.println(strDate);

LocalDateTime newLdt = ldt.parse(strDate, dtf);
System.out.println(newLdt);

本文地址:https://blog.csdn.net/yu1755128147/article/details/107685948

相关标签: Java SE