Java8

一. Java8概述

  • Java8(又称JDK1.8)是Java语言开发的一个主要版本. Oracle公司于2014年3月18日发布Java8

    • 支持Lambda表达式
    • 函数式接口
    • 新的Stream API
    • 新的日期 API
    • 其他特性

二. Lambda表达式

  • Lambda表达式: 特殊的匿名内部类, 语法更简洁
  • Lambda表达式允许把函数作为一个方法的参数(函数作为方法的参数传递), 将代码像数据一样传递
  • 基本语法
    • <函数式接口> <变量名> = (参数1, 参数2...) -> {//方法体};
  • Lambda引入了新的操作符: -> (箭头操作符), -> 将表达式分成两部分
    • 左侧: (参数1, 参数2...)表示参数列表
    • 右侧: {}内部是方法体
  • 注意事项
    • 形参列表的数据类型会自动推断
    • 如果形参列表为空, 只需保留()
    • 如果形参只有一个, ()可以省略, 只需要参数的名称即可
    • 如果执行语句只有一句, 且无返回值, {}可以省略, 若有返回值, 则若想省去{}, 则必须同时省略return, 且执行语句也保证只有一句
    • Lambda不会生成一个单独的内部类文件
public class TestLambda {

    public static void main(String[] args) {

        //1. 匿名内部类
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("子线程1运行了...");
}
};
new Thread(runnable1).start(); //2. Lambda表达式
//2.1 将匿名内部类简化为Lambda表达式
Runnable runnable2 = () -> System.out.println("子线程2运行了...");
new Thread(runnable2).start();
//2.2 把Lambda表达式作为参数传递
new Thread(() -> System.out.println("子线程3运行了...")).start(); //3. Lambda表达式
//匿名内部类
Comparator<String> comparator1 = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
};
TreeSet<String> treeSet1 = new TreeSet<>(comparator1); //3.1 将匿名内部类简化为Lambda表达式
Comparator<String> comparator2 = (o1, o2) -> o1.length() - o2.length();
TreeSet<String> treeSet2 = new TreeSet<>(comparator2); }
}

三. 函数式接口

  • 如果一个接口只有一个抽象方法, 则该接口称之为函数式接口, 函数式接口可以使用Lambda表达式, Lambda表达式会被匹配到这个抽象方法上
  • @FunctionalInterface 注解检测接口是否符合函数式接口
//函数式接口: 接口中只有一个抽象方法
@FunctionalInterface //验证是否是函数式接口
public interface Usb { void service(); }
public class Demo01 { public static void main(String[] args) { //1. 匿名内部类
Usb mouse = new Usb() {
@Override
public void service() {
System.out.println("鼠标开始工作了...");
}
};
run(mouse); Usb keyBoard = () -> System.out.println("键盘开始工作了");
run(keyBoard);
} public static void run(Usb usb){
usb.service();
}
}

常用函数式接口

函数式接口 参数类型 返回类型 说明
Consumer消费型接口 T void void accept(T,t);对类型为T的对象应用操作
Supplier供给型接口 T T get();返回类型为T的对象
Function<T,R>函数型接口 T R R apply(T,t);对类型为T的对象应用操作, 并返回类型为R的对象
Predicate断言型接口 T boolean boolean test(T t);确定类型为T的对象是否满足条件, 并返回boolean类型
public class Demo02 {

    public static void main(String[] args) {

//        //匿名内部类
// Consumer<Double> consumer = new Consumer<Double>() {
// @Override
// public void accept(Double aDouble) {
// System.out.println("聚餐消费: " + aDouble);
// }
// };
//Lambda表达式
//Consumer<Double> consumer = aDouble -> System.out.println("聚餐消费: " + aDouble); //Consumer 消费型接口
happy(aDouble -> System.out.println("聚餐消费: " + aDouble), 1000);//聚餐消费: 1000.0
happy(aDouble -> System.out.println("唱歌消费: " + aDouble), 2000);//唱歌消费: 2000.0
happy(aDouble -> System.out.println("跳舞消费: " + aDouble), 3000);//跳舞消费: 3000.0 //Supplier 供给型接口
int[] arr = getNums(() -> new Random().nextInt(100), 5);
System.out.println(Arrays.toString(arr));//[93, 9, 13, 1, 56] 5个随机数
int[] arr2 = getNums(() -> new Random().nextInt(100), 10);
System.out.println(Arrays.toString(arr2));//[53, 94, 55, 59, 76, 74, 21, 61, 32, 94] 10个随机数 // Function 函数型接口
String result1 = handleString(s -> s.toUpperCase(), "hello");//转换为大写
System.out.println(result1);//HELLO
String result2 = handleString(s -> s.trim(), " hello ");//去掉首尾空格
System.out.println(result2);//hello // Predicate 断言型接口
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("李五");
list.add("张四");
List<String> result3 = filterNames(s -> s.startsWith("张"), list);//返回以"张"开头的字符串
System.out.println(result3.toString());//[张三, 张四]
List<String> result4 = filterNames(s -> s.length() > 1, list);//返回长度大于1的字符串
System.out.println(result4);//[张三, 李四, 李五, 张四]
} //1. Consumer 消费型接口
public static void happy(Consumer<Double> consumer, double money){
consumer.accept(money);
}
//2. 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;
}
//3. Function 函数型接口
public static String handleString(Function<String, String> function, String str){
return function.apply(str);
}
//4. Predicate 断言型接口
public static List<String> filterNames(Predicate<String> predicate, List<String> list){
List<String> resultList = new ArrayList<String>();
for (String s : list) {
if (predicate.test(s)){
resultList.add(s);
}
}
return resultList;
} }

四. 方法引用

  • 方法调用时Lambda表达式的一种简写形式. 如果Lambda表达式方法体中只是调用一个人特定的已经存在的方法, 则可以使用方法引用
  • 常见形式
    • 对象::实例方法
    • 类::静态方法
    • 类::实例方法
    • 类::new
public class Demo03 {

    public static void main(String[] args) {

        //1. 对象::实例方法
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("hello"); Consumer<String> consumer2 = System.out::println;
consumer2.accept("world"); //2. 类::静态方法
Comparator<Integer> com = (o1, o2) -> Integer.compare(o1, o2);
Comparator<Integer> com2 = Integer::compare; //3. 类::实例方法
Function<Person, String> function = person -> person.getName();
Function<Person, String> function2 = Person::getName; System.out.println(function2.apply(new Person("张三", 13))); //4. 类::new
Supplier<Person> supplier = () -> new Person();
Supplier<Person> supplier2 = Person::new; Person person = supplier2.get();
System.out.println(person.toString());
}
}

五. Stream API

1. 什么是Stream

  • 流(Stream)中保存对集合或数组数据的操作. 和集合类似, 但集合中保存的是数据

2. Stream特点

  • Stream自己不会存储元素
  • Stream不会改变源对象. 相反, 他们会返回一个持有结果的新Stream
  • Stream操作是延迟执行的. 这意味着他们会等到需要结果的时候才执行

3. Stream使用步骤

  • (1) 创建

    • 新建一个流
  • (2) 中间操作
    • 在一个或多个步骤中, 将初始Stream转化到另一个Stream的中间操作
  • (3) 终止操作
    • 使用一个终止操作来产生一个结果. 该操作会强制它之前的延迟操作立即执行. 在这之后, 该Stream就不能使用了

(1) 创建Stream

  • 通过Collection对象的stream()或parallelStream()方法
  • 通过Arrays类的stream()方法
  • 通过Stream接口的of(), iterate(), generate()方法
  • 通过IntStream, LongStream, DoubleStream接口中的of, range, rangeClosed方法
public class Demo04 {

    public static void main(String[] args) {

        //1. 通过Collection对象的stream()或parallelStream()方法
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("瓜子");
arrayList.add("花生");
arrayList.add("啤酒");
arrayList.add("饮料");
Stream<String> stream = arrayList.parallelStream();//parallelStream 并行流
//遍历
stream.forEach(System.out::println);//方法引用 //2. 通过Arrays类的stream()方法
String[] arr = {"aaa", "bbb", "ccc"};
Stream<String> stream2 = Arrays.stream(arr);
stream2.forEach(System.out::println); //3. 通过Stream接口的of(), iterate(), generate()方法
//3.1 of()
System.out.println("----------of()----------");
Stream<Integer> stream3 = Stream.of(10, 20, 30, 40, 50);
stream3.forEach(System.out::println); //3.2 迭代流iterate()
System.out.println("----------迭代流iterate()----------");
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(10).forEach(System.out::println); //3.3 生成流generate()
System.out.println("----------生成流generate()----------");
Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(100));
generate.limit(10).forEach(System.out::println); //4. 通过IntStream, LongStream, DoubleStream接口中的of, range, rangeClosed方法
IntStream stream4 = IntStream.of(100, 200,300);
stream4.forEach(System.out::println);
IntStream range = IntStream.range(0, 50);
range.forEach(System.out::println);
}
}

(2) 中间操作

  • 中间操作

    • filter, limit, skip, distinct, sorted
    • map
    • parallel
public class Demo05 {

    public static void main(String[] args) {

        ArrayList<Person> list = new ArrayList<>();
list.add(new Person("小一", 18));
list.add(new Person("小三", 20));
list.add(new Person("小二", 19));
list.add(new Person("小四", 21));
list.add(new Person("小二", 19));
list.add(new Person("小四", 21));
list.add(new Person("小五", 22));
//中间操作一: 1. filter过滤, 2. limit限制, 3. skip跳过, 4. distinct去重, 5. sorted排序
//1. filter过滤
System.out.println("------filter------");
list.stream()
.filter(e -> e.getAge() > 20)
.forEach(System.out::println);
//2. limit限制
System.out.println("------limit------");
list.stream()
.limit(2)
.forEach(System.out::println);
//3. skip跳过
System.out.println("------skip------");
list.stream()
.skip(2)
.forEach(System.out::println);
//4. distinct去重(需重写hashcode和equals)
System.out.println("------distinct------");
list.stream()
.distinct()
.forEach(System.out::println); //5. sorted排序
System.out.println("------sorted------");
list.stream()
.sorted((p1, p2) -> Double.compare(p1.getAge(), p2.getAge()))
.forEach(System.out::println); //中间操作二: map
System.out.println("------map------");
list.stream()
.map(e -> e.getName())
.forEach(System.out::println);
//中间操作三: parallel 并行: 采用多线程, 效率高
System.out.println("------parallel------");
list.parallelStream()
.forEach(System.out::println); }
}

串行流和并行流的区别(并行流效率更高)

public class Demo06 {

    public static void main(String[] args) {

        //串行流和并行流的区别
ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 5000000; i++) {
list.add(UUID.randomUUID().toString());
}
//串行
long start1 = System.currentTimeMillis();
long count1 = list.stream().sorted().count();
System.out.println(count1);//5000000
long end1 = System.currentTimeMillis();
System.out.println("用时: " + (end1 - start1));//用时: 6750 //并行
long start2 = System.currentTimeMillis();
long count2 = list.parallelStream().sorted().count();
System.out.println(count2);//5000000
long end2 = System.currentTimeMillis();
System.out.println("用时: " + (end2 - start2));//用时: 3099 }
}

(3) 终止操作

  • 终止操作

    • forEach, min, max, count
    • reduce, collect
public class Demo07 {

    public static void main(String[] args) {

        ArrayList<Person> list = new ArrayList<>();
list.add(new Person("one", 18));
list.add(new Person("two", 20));
list.add(new Person("three", 19));
list.add(new Person("four", 21));
list.add(new Person("five", 19));
list.add(new Person("six", 21));
list.add(new Person("seven", 22)); //终止操作 forEach
System.out.println("------forEach------");
list.stream()
.filter(p -> {
System.out.println("过滤了...");
return p.getAge() > 17;
})
.forEach(System.out::println);
//终止操作 min max count
System.out.println("------min------");
Optional<Person> min = list.stream()
.min((p1, p2) -> Double.compare(p1.getAge(), p2.getAge()));
System.out.println(min.get());
System.out.println("------max------");
Optional<Person> max = list.stream()
.max((p1, p2) -> Double.compare(p1.getAge(), p2.getAge()));
System.out.println(max.get());
System.out.println("------count------"); long count = list.stream().count();
System.out.println("学生个数: " + count); //终止操作 reduce 规约
//计算所有学生的年龄和
System.out.println("------reduce------");
Optional<Integer> sum = list.stream()
.map(p -> p.getAge())
.reduce((x, y) -> x + y);
System.out.println("年龄和为: " + sum.get()); //终止方法 collect 收集
//获取所有学生姓名, 封装成一个list集合
List<String> names = list.stream()
.map(Person::getName)
.collect(Collectors.toList());
for (String name : names) {
System.out.println(name);
} }
}

六. 新时间 API

  • 之前时间API存在问题: 线程安全问题, 设计混乱
  • 所有新的日期时间 API 类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分
  • Java 8 中新的时间与日期 API 中的所有类都是不可变且线程安全的,任何修改操作都会返回一个新的实例
  • 新的 API 区分各种日期时间概念并且各个概念使用相似的方法定义模式,这种相似性非常有利于 API 的学习。总结一下一般的方法或者方法前缀:
    • of:静态工厂方法,用于创建实例
    • now:静态工厂方法,用当前时间创建实例
    • parse:静态工厂方法,从字符串解析得到对象实例
    • get:获取时间日期对象的部分状态。
    • is:检查某些东西的是否是 true,例如比较时间前后
    • with:返回一个部分状态改变了的时间日期对象拷贝
    • plus:返回一个时间增加了的、时间日期对象拷贝
    • minus:返回一个时间减少了的、时间日期对象拷贝
    • to:转换到另一个类型
    • at:把这个对象与另一个对象组合起来,例如 date.atTime(time)
    • format:提供格式化时间日期对象的能力
  • 本地化日期时间 API
    • LocalDate
    • LocalTime
    • LocalDateTime
  • Instant: 时间戳
  • ZoneId: 时区
  • Date, Instant, LocalDateTime的转换
  • DateTimeFormatter: 格式化类

(1) DateTimeFormatter

DateTimeFormatter这个类它只提供了时间格式化的类型,就是按你指定的格式,或者按jdk默认的格式,需要进行调用的则是时间类本身来进行调用才能进行格式化

public class Demo01 {

    public static void main(String[] args) {

        //创建DateTimeFormatter
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//(1)把时间格式化成字符串
String format = dtf.format(LocalDateTime.now());
System.out.println(format);
//(2)把字符串解析成时间
LocalDateTime localDateTime = LocalDateTime.parse("2021-03-13 23:01:35", dtf);
System.out.println(localDateTime); }
}

public class Demo02 { public static void main(String[] args) throws Exception{ //SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");//SimpleDateFormat类是线程不安全的
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("20210313", dtf);//将特定格式的文本字符串解析为时间并返回
}
};
List<Future<LocalDate>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Future<LocalDate> future = pool.submit(callable);
list.add(future);
} for (Future<LocalDate> future : list) {
System.out.println(future.get());
}
pool.shutdown();
}
}

(2) LocalDateTime

public class Demo03 {

    public static void main(String[] args) {

        //1. 创建本地时间
LocalDateTime localDateTime = LocalDateTime.now();//用当前时间创建实例
//LocalDateTime localDateTime1 = localDateTime.of();
System.out.println(localDateTime);//完整日期
System.out.println(localDateTime.getYear());//年
System.out.println(localDateTime.getMonth());//月
System.out.println(localDateTime.getDayOfMonth());//日
System.out.println(localDateTime.getDayOfWeek());//星期几
System.out.println(localDateTime.getHour());//时
System.out.println(localDateTime.getMinute());//分
System.out.println(localDateTime.getSecond());//秒 //2. 添加两天
LocalDateTime localDateTime1 = localDateTime.plusDays(2);//得到一个新的时间对象
System.out.println(localDateTime1); //3. 减少一个月
LocalDateTime localDateTime2 = localDateTime.minusMonths(2);
System.out.println(localDateTime2);
}
}

(3) Instant: 时间戳 + ZoneId: 时区

public class Demo04 {

    public static void main(String[] args) {

        //1. 创建 Instant 时间戳
Instant instant = Instant.now();
System.out.println(instant.toString());//2021-03-13T14:30:53.375Z 比北京时间少8小时
System.out.println(instant.toEpochMilli());//1615645853375
System.out.println(System.currentTimeMillis());//1615645853522 //2. 添加, 减少时间
Instant instant1 = instant.plusMillis(TimeUnit.HOURS.toMillis(8));//通过增加8小时,转化为北京时间
System.out.println(instant1);
System.out.println(Duration.between(instant, instant1).toMillis());//28800000 instant和instant1之间相差28800000毫秒,也就是8小时 //3. ZoneId
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for (String availableZoneId : availableZoneIds) {
//System.out.println(availableZoneId);
}
System.out.println(ZoneId.systemDefault().toString());//Asia/Shanghai //4. Date ---> Instant ---> LocalDateTime
System.out.println("---------Date ---> Instant ---> LocalDateTime---------");
Date date = new Date();
System.out.println(date);//Sat Mar 13 22:30:53 CST 2021
Instant instant2 = date.toInstant();//Date转为Instant
System.out.println(instant2);//2021-03-13T14:30:53.558Z LocalDateTime localDateTime = LocalDateTime.ofInstant(instant2, ZoneId.systemDefault());
System.out.println(localDateTime);//2021-03-13T22:30:53.558 //5. LocalDateTime ---> Instant ---> Date
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); }
}

24_Java8的更多相关文章

随机推荐

  1. 从编译器对指令集的要求看API设计原则

    摘要:最近看<计算机体系结构:量化研究方法(第五版)>,发现指令集设计中的一些原则,对API设计也同样适用,给大家分享一下. 本文中的所有内容来自工作和学习过程中的心得整理,如需转载请注明 ...

  2. Template -「高斯消元」

    #include <cstdio> #include <vector> #include <algorithm> using namespace std; doub ...

  3. c++头文件的一个误导

    通常情况下,我们都认为c++的头文件是这样的: #include <bits/stdc++.h> using namespace std; int main() 但c++也可以用c的头文件 ...

  4. 基于gitlab 15.1 pages 搭建内部博客一定行版本

    背景 基于 gitlab 15.1版 pages 搭建内部博客,参考官方文档,遇到一个又一个坑.之前看到别人吐槽说 gitlab 官方文档很差,我算是理解了.下面一个个说. 开始 按照官方文档的说法, ...

  5. python template生成模板文件

    简介 在实际项目中,可能会出现需要批量生成特定格式或者特定内容的文件,因此,使用template文件生成便适用于在文件中大部分格式内容都是一致的,部分内容需要替换的情况. 模板文件 name: $NA ...

  6. 使用python3.7和opencv4.1来实现人脸识别和人脸特征比对以及模型训练

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_126 OpenCV4.1已经发布将近一年了,其人脸识别速度和性能有了一定的提高,这里我们使用opencv来做一个实时活体面部识别的 ...

  7. Vue 引出声明周期 && 组件的基本使用

    1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8" /> 5 & ...

  8. docker 安装gitlab

    # docker 安装gitlab # 一.安装镜像(官网文档) export GITLAB_HOME=/srv/gitlab # 必须先设置它,它就是你存储代码仓库的位置.以后要移植的时候直接把这个 ...

  9. Geometrics类定义

    首先我的结构图是这样的,当然你自己喜欢怎么改都行.这个不影响,只要包含到正确的头文件就行. geometrics是几何类的基础,所有几何的碰撞都是从这个类继承下来的.书中也说的很清楚了,大家可以阅读对 ...

  10. .NET CORE 读书笔记之与.NET Framework对比

    .NET Framework存在的问题 它是属于系统级别安装的程序 操作系统内的所有程序共享一个.NET Framework实例,如果其中某一个应用程序需要升级Framework,其他程序也会收到影响 ...