24_Java8
2022/7/6 14:25:37
本文主要是介绍24_Java8,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录- Java8
- 一. Java8概述
- 二. Lambda表达式
- 三. 函数式接口
- 四. 方法引用
- 五. Stream API
- (1) 创建Stream
- (2) 中间操作
- (3) 终止操作
- 六. 新时间 API
- (1) DateTimeFormatter
- (2) LocalDateTime
- (3) Instant: 时间戳 + ZoneId: 时区
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的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26手写消息中间件:从零开始的指南
- 2024-11-26Java语音识别项目资料:新手入门教程
- 2024-11-26JAVA语音识别项目资料:新手入门教程
- 2024-11-26Java语音识别项目资料:入门与实践指南
- 2024-11-26Java云原生资料入门教程
- 2024-11-26Java云原生资料入门教程
- 2024-11-26Java云原生资料:新手入门教程
- 2024-11-25Java创意资料:新手入门的创意学习指南
- 2024-11-25JAVA对接阿里云智能语音服务资料详解:新手入门指南
- 2024-11-25Java对接阿里云智能语音服务资料详解