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) { |
| |
| |
| Runnable runnable1 = new Runnable() { |
| @Override |
| public void run() { |
| System.out.println("子线程1运行了..."); |
| } |
| }; |
| new Thread(runnable1).start(); |
| |
| |
| |
| Runnable runnable2 = () -> System.out.println("子线程2运行了..."); |
| new Thread(runnable2).start(); |
| |
| new Thread(() -> System.out.println("子线程3运行了...")).start(); |
| |
| |
| |
| 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); |
| |
| |
| 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) { |
| |
| |
| 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) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| happy(aDouble -> System.out.println("聚餐消费: " + aDouble), 1000); |
| happy(aDouble -> System.out.println("唱歌消费: " + aDouble), 2000); |
| happy(aDouble -> System.out.println("跳舞消费: " + aDouble), 3000); |
| |
| |
| int[] arr = getNums(() -> new Random().nextInt(100), 5); |
| System.out.println(Arrays.toString(arr)); |
| int[] arr2 = getNums(() -> new Random().nextInt(100), 10); |
| System.out.println(Arrays.toString(arr2)); |
| |
| |
| String result1 = handleString(s -> s.toUpperCase(), "hello"); |
| System.out.println(result1); |
| String result2 = handleString(s -> s.trim(), " hello "); |
| System.out.println(result2); |
| |
| |
| 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); |
| System.out.println(result4); |
| } |
| |
| |
| public static void happy(Consumer<Double> consumer, double money){ |
| consumer.accept(money); |
| } |
| |
| 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; |
| } |
| |
| public static String handleString(Function<String, String> function, String str){ |
| return function.apply(str); |
| } |
| |
| 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) { |
| |
| |
| Consumer<String> consumer = s -> System.out.println(s); |
| consumer.accept("hello"); |
| |
| Consumer<String> consumer2 = System.out::println; |
| consumer2.accept("world"); |
| |
| |
| Comparator<Integer> com = (o1, o2) -> Integer.compare(o1, o2); |
| Comparator<Integer> com2 = Integer::compare; |
| |
| |
| Function<Person, String> function = person -> person.getName(); |
| Function<Person, String> function2 = Person::getName; |
| |
| System.out.println(function2.apply(new Person("张三", 13))); |
| |
| |
| 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) { |
| |
| |
| ArrayList<String> arrayList = new ArrayList<>(); |
| arrayList.add("瓜子"); |
| arrayList.add("花生"); |
| arrayList.add("啤酒"); |
| arrayList.add("饮料"); |
| Stream<String> stream = arrayList.parallelStream(); |
| |
| stream.forEach(System.out::println); |
| |
| |
| String[] arr = {"aaa", "bbb", "ccc"}; |
| Stream<String> stream2 = Arrays.stream(arr); |
| stream2.forEach(System.out::println); |
| |
| |
| |
| System.out.println("----------of()----------"); |
| Stream<Integer> stream3 = Stream.of(10, 20, 30, 40, 50); |
| stream3.forEach(System.out::println); |
| |
| |
| System.out.println("----------迭代流iterate()----------"); |
| Stream<Integer> iterate = Stream.iterate(0, x -> x + 2); |
| iterate.limit(10).forEach(System.out::println); |
| |
| |
| System.out.println("----------生成流generate()----------"); |
| Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(100)); |
| generate.limit(10).forEach(System.out::println); |
| |
| |
| 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)); |
| |
| |
| System.out.println("------filter------"); |
| list.stream() |
| .filter(e -> e.getAge() > 20) |
| .forEach(System.out::println); |
| |
| System.out.println("------limit------"); |
| list.stream() |
| .limit(2) |
| .forEach(System.out::println); |
| |
| System.out.println("------skip------"); |
| list.stream() |
| .skip(2) |
| .forEach(System.out::println); |
| |
| System.out.println("------distinct------"); |
| list.stream() |
| .distinct() |
| .forEach(System.out::println); |
| |
| |
| System.out.println("------sorted------"); |
| list.stream() |
| .sorted((p1, p2) -> Double.compare(p1.getAge(), p2.getAge())) |
| .forEach(System.out::println); |
| |
| |
| System.out.println("------map------"); |
| list.stream() |
| .map(e -> e.getName()) |
| .forEach(System.out::println); |
| |
| 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); |
| long end1 = System.currentTimeMillis(); |
| System.out.println("用时: " + (end1 - start1)); |
| |
| |
| long start2 = System.currentTimeMillis(); |
| long count2 = list.parallelStream().sorted().count(); |
| System.out.println(count2); |
| long end2 = System.currentTimeMillis(); |
| System.out.println("用时: " + (end2 - start2)); |
| |
| |
| } |
| } |
(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)); |
| |
| |
| System.out.println("------forEach------"); |
| list.stream() |
| .filter(p -> { |
| System.out.println("过滤了..."); |
| return p.getAge() > 17; |
| }) |
| .forEach(System.out::println); |
| |
| 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); |
| |
| |
| |
| System.out.println("------reduce------"); |
| Optional<Integer> sum = list.stream() |
| .map(p -> p.getAge()) |
| .reduce((x, y) -> x + y); |
| System.out.println("年龄和为: " + sum.get()); |
| |
| |
| |
| 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: 格式化类
DateTimeFormatter这个类它只提供了时间格式化的类型,就是按你指定的格式,或者按jdk默认的格式,需要进行调用的则是时间类本身来进行调用才能进行格式化
| public class Demo01 { |
| |
| public static void main(String[] args) { |
| |
| |
| DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| |
| String format = dtf.format(LocalDateTime.now()); |
| System.out.println(format); |
| |
| 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{ |
| |
| |
| 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) { |
| |
| |
| LocalDateTime localDateTime = LocalDateTime.now(); |
| |
| 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()); |
| |
| |
| LocalDateTime localDateTime1 = localDateTime.plusDays(2); |
| System.out.println(localDateTime1); |
| |
| |
| LocalDateTime localDateTime2 = localDateTime.minusMonths(2); |
| System.out.println(localDateTime2); |
| } |
| } |
(3) Instant: 时间戳 + ZoneId: 时区
| public class Demo04 { |
| |
| public static void main(String[] args) { |
| |
| |
| Instant instant = Instant.now(); |
| System.out.println(instant.toString()); |
| System.out.println(instant.toEpochMilli()); |
| System.out.println(System.currentTimeMillis()); |
| |
| |
| Instant instant1 = instant.plusMillis(TimeUnit.HOURS.toMillis(8)); |
| System.out.println(instant1); |
| System.out.println(Duration.between(instant, instant1).toMillis()); |
| |
| |
| Set<String> availableZoneIds = ZoneId.getAvailableZoneIds(); |
| for (String availableZoneId : availableZoneIds) { |
| |
| } |
| System.out.println(ZoneId.systemDefault().toString()); |
| |
| |
| System.out.println("---------Date ---> Instant ---> LocalDateTime---------"); |
| Date date = new Date(); |
| System.out.println(date); |
| Instant instant2 = date.toInstant(); |
| System.out.println(instant2); |
| |
| LocalDateTime localDateTime = LocalDateTime.ofInstant(instant2, ZoneId.systemDefault()); |
| System.out.println(localDateTime); |
| |
| |
| 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); |
| |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步