电子商务网站建设课外实训,重庆网站推广产品企业,网络服务提供者不是网络运营者对不对,百度站长平台网页手机技术分享——Java8新特性1.背景2. 新特性主要内容3. Lambda表达式4. 四大内置核心函数式接口4.1 ConsumerT消费型接口4.2 SupplierT供给型接口4.3 FunctionT,R函数型接口4.4 PredicateT 断定型接口5. Stream流操作5.1 什么是流以及流的类型5.2…
技术分享——Java8新特性1.背景2. 新特性主要内容3. Lambda表达式4. 四大内置核心函数式接口4.1 ConsumerT消费型接口4.2 SupplierT供给型接口4.3 FunctionT,R函数型接口4.4 PredicateT 断定型接口5. Stream流操作5.1 什么是流以及流的类型5.2 流操作5.2.1 创建Stream5.2.2 Stram流 筛选与切片5.2.3 映射5.2.4 排序5.2.5 匹配与查找5.2.6 规约与收集6. 并行流 parallelStream7. Optional 类8. 新的时间API8.1 java.time 主要类8.2 应用对比8.2.1 格式化对比8.2.2 字符串转日期格式8.2.3 日期计算8.2.4 获取指定日期1.背景
目前企业级开发语言主要是JavaJava 8 是目前最常用的 JDK 版本相比 Java 7 增加了很多功能比如 Lambda表达式、Stream 流操作、并行流ParallelStream、Optional 可空类型、新时间API等。
新特性给我们带来的好处
代码量更少(lambda表达式)强大的Stream API(提供了一种新的处理集合数据的方式允许以声明性的方式处理数据)便于并行(ParallelStream)最大化减少NPE(Optional)
2. 新特性主要内容
Lambda表达式
四大内置核心函数式接口
Stream流操作
ParallelStrean并行流
Optional类
新的时间API3. Lambda表达式
Lambda表达式是一个匿名函数我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格使Java的语言表达能力得到了提升。
语法格式
左侧Lambda表达式的参数列表
右侧Lambda表达式中所需执行的功能既Lambda体 语法格式一无参数无返回值
Runnable r1 ()- System.out.println(Hello World);语法格式二有一个参数并无返回值
ConsumerString con (x)- System.out.println(x);语法格式三若只有一个参数参数的()可以不写
ConsumerString con x- System.out.println(x);语法格式四有两个以上参数有返回值并且Lambda体中有多条语句
ComparatorInteger com (x, y) - {System.out.println(Hello World);return Integer.compare(x, y);
};语法格式五若Lambda体中只有一条语句return和{}都可以不写
ComparatorInteger com (x, y) - Integer.compare(x, y);这里注意Lambda表达式需要函数式接口的支持。 函数式接口接口中只有一个抽象方法称为函数式接口(FunctionalInterface 注解声明该接口是一个函数式接口)。 2. 举个
匿名内部类的格式
new 父类或接口(){//进行方法重写
};// 用匿名内部类的方式来创建线程
new Thread(new Runnable() {Overridepublic void run() {System.out.println(The runable now is using!);}
}).start();------------------------------------------------------------------------
// 使用Lambda来创建线程返回的是Runnable对象实例
new Thread(() - System.out.println(The runable now is using!)).start();4. 四大内置核心函数式接口 4.1 Consumer消费型接口
接受一个参数无返回值常用于对参数进行处理、修改等操作。 举个
public static void main(String[] args) {ConsumerInteger consumer i - {System.out.println(Consumer 接收 参数 i 开始处理);int step 1;System.out.printf(Consumer 输入%d, 输出%d%n, i, i step);};ListInteger list Arrays.asList(4, 2, 6);list.forEach(consumer);
}
result:Consumer 接收 参数 i 开始处理Consumer 输入4, 输出5Consumer 接收 参数 i 开始处理Consumer 输入2, 输出3Consumer 接收 参数 i 开始处理Consumer 输入6, 输出74.2 Supplier供给型接口
不接受参数返回一个结果常用于生成某些对象。 举个
// 获取长度为10的整数集合
public static ListInteger getNumList(int num, SupplierInteger sup) {ListInteger list new ArrayList();for (int i 0; i num; i) {Integer n sup.get();list.add(n);}return list;
}getNumList(10, () - (int) (Math.random() * 100));4.3 FunctionT,R函数型接口
接受一个参数返回一个结果常用于对参数进行处理、转换等操作。 这里举个 有User、UserEntity两个实体类定义如下
Data
AllArgsConstructor
public class User {private Integer age;private String name;
} Data
AllArgsConstructor
public class UserEntity{private Integer age;private String name;private Integer type;
}将一组User转换成一组UserEntity, 根据User的年龄来定义用户级别普通用户,vip,svip其中用户级别是User Entity的一个字段所以输入参数是List,返回结果是List 。 构造数据
ListUser users new ArrayList();
users.add(new User(10, 张三));
users.add(new User(15, 李四));
users.add(new User(16, 王五));
users.add(new User(20, 赵六));
users.add(new User(25, 田七));private static FunctionListUser, ListUserEntity multiUsersToEntities(ListUser users) {FunctionListUser, ListUserEntity function t - {ListUserEntity userEntityList new ArrayList();for (User user : t) {UserEntity userEntity new UserEntity(user.getAge(), user.getName(), 普通用户);Integer age user.getAge();if (age 15 age 20) {userEntity.setType(vip);}if (age 20) {userEntity.setType(svip);}userEntityList.add(userEntity);}return userEntityList;};return function;
}ListUserEntity uEntities multiUsersToEntities(users).apply(users);4.4 Predicate 断定型接口
接受一个参数返回一个布尔值常用于条件判断、筛选等操作。
PredicateString predicate p - p.length() 21;
StreamString stream stringList().stream().filter(predicate);总结 这四个接口的作用在于提供常用的函数式编程中常用的基础操作提高了代码的复用性和简洁性。它们可以被Java8中的Lamba表达式直接调用从而实现更加简洁而清晰的代码。 如果你需要进行一些简单的操作这些接口可以让你无需自己编写函数或者创建单独的类而使用Java8提供的函数式编程工具来解决问题。 除了四大核心函数接口外Java8还提供了一些其他的函数式接口。
5. Stream流操作
5.1 什么是流以及流的类型 流是Java API的新成员它允许通过声明的方式处理数据集合。我们可以把他看成遍历数据集的高级迭代器。它的源数据可以是 Collection、Array 等。由于它的方法参数都是函数式接口类型所以一般和 Lambda 配合使用。 流的类型有stream 串行流和parallelStream 并行流parallelStream可多线程执行。 特点
Stream不会自己存储元素Stream不会改变源对象相反他们会返回一个持有新结果的新Strream。Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
5.2 流操作
Stram的操作三个步骤
创建Stream 一个数据源(如集合、数组)获取一个流。中间操作 一个中间操作对数据源的数据进行处理。中间操作可以连成一条流水线。终端操作 一个终端操作执行中间操作链并产生结果。终端操作的作用是关闭流水线。 5.2.1 创建Stream
Collection系列集合提供的stream()方法或者parallelStream()创建Stream
ListString list new ArrayList();
StreamString stream list.stream();Arrays类中的静态方法stream()
Employee[] emps new Employee[10];
StreamEmployee stream Arrays.stream(emps);通过Stream类中的静态方法of
StreamString stream Stream.of(aa, bb, cc);5.2.2 Stram流 筛选与切片
filter——接收Lambda, 从流中排除某些元素
StreamT filter(Predicate? super T predicate); 断言型接口ListString s Arrays.asList(a,b,c,null);ListString s2 s.stream().filter(e - e ! null).collect(Collectors.toList());
System.out.println(s2);
// result:[a, b, c] limit ——截断流,使其不超过给定的数量
ListString s Arrays.asList(a,b,c);ListString s2 s.stream().limit(2L).collect(Collectors.toList());
System.out.println(s2);
// result:[a, b]skip(n)—— 跳过元素返回一个扔掉了前n个元素的流。若流中元素不足n个则返回一个空流
ListString s Arrays.asList(a,b,c);ListString resultList demoList.stream().skip(2).collect(Collectors.toList());
System.out.println(resultList);
// result: [c]distinct——筛选通过流所生成元素的hashCode()和equals()去除重复元素
ListString s Arrays.asList(a,a,b,c);ListString resultList s.stream().distinct().collect(Collectors.toList());
System.out.println(resultList);
// result: [a,b,c]5.2.3 映射
map——支持Lambda语法将元素转换成其他形式提取信息。接受一个函数作为参数该函数会被应用到每个元素上并将其映射成一个新的元素。
ListString demoList Arrays.asList(aaa, bbb, ccc, ddd, eee);ListString result demoList.stream().map(str - str.toUpperCase()).collect(Collectors.toList());
System.out.println(result);
// result: [AAA, BBB, CCC, DDD, EEE]flatMap——将流中的每个值都替换成另一个流然后把所有的流连接成一个流。 举个 给定的单词集合[hello,world],返回集合[h,e,l,l,o, w,o,r,l,d]
ListString stringList Arrays.asList(hello, world);
ListString[] collect stringList.stream().map(str - str.split()).collect(Collectors.toList());
collect.forEach(col - System.out.println(Arrays.toString(col)));/* result:[h, e, l, l, o][w, o, r, l, d]
*/大家可以看到返回结果是两个数组并没有达到我们的要求。map的操作只是将元素放入map中的函数中使其返回另一个StreamString[]类型的但我们真正想要的是一个Stream类型的所以我们需要扁平化处理将多个数组放入一个数组中。
ListString stringList Arrays.asList(hello, world);
ListString collect stringList.stream().map(str - str.split()).flatMap(item - {return Arrays.stream(item);}).collect(Collectors.toList());System.out.println(collect);// result:[h, e, l, l, o, w, o, r, l, d]5.2.4 排序
sorted()——自然排序(实现Comparable的compareTo方法)
ListString list Arrays.asList(ccc, aaa, bbb, ddd, eee);
list.stream().sorted().forEach(System.out::println);/* result: aaabbbcccdddeee
*/sorted(Comparator com)——定制排序 StreamT sorted(Comparator? super T comparator);
ListEmployee employeeList new ArrayListEmployee();
employeeList.add(new Employee(15, 18801171255, 张三, 8000));
employeeList.add(new Employee(18, 18801171256, 李四, 9000));
employeeList.add(new Employee(20, 18801171257, 王五, 1000));
employeeList.add(new Employee(20, 18801171258, 赵六, 1000));employeeList.stream().sorted((e1,e2)-{if(e1.getAge().equals(e2.getAge())){return e1.getName().compareTo(e2.getName());}else{return e1.getAge().compareTo(e2.getAge());}}).collect(Collectors.toList());System.out.println(employeeList);
/*retult:[Employee{age15, mobile18801171255, name张三, salary8000}, Employee{age18, mobile18801171256, name李四, salary9000}, Employee{age20, mobile18801171257, name王五, salary1000}, Employee{age20, mobile18801171258, name赵六, salary1000}]
*/5.2.5 匹配与查找
allMatch——检查是否匹配所有元素 判断数据列表中全部元素都符合设置的predicate条件如果是就返回true否则返回false流为空时总是返回true。 boolean allMatch(Predicate? super T predicate);
ListString typeList1 Arrays.asList(1, 2);
ListString typeList2 Arrays.asList(1, 2, 3, 4);
// 集合列表中全部元素必须在allMatch里面的那些字符串只要全部元素中有任意一个不同的元素在AllMatch中就返回false
boolean isMatch1 typeList1.stream().allMatch(a - a.equals(1) || a.equals(2) || a.equals(3));
boolean isMatch2 typeList2.stream().allMatch(a - a.equals(1) || a.equals(2) || a.equals(3));
System.out.println(isMatch1); // result:true
System.out.println(isMatch2); // fresult:falseanyMatch——检查是否至少匹配一个元素(只要有一个满足条件就返回true)
ListInteger list Arrays.asList(10, 12, 14, 16);
boolean flag list.stream().anyMatch(item - item 13);
System.out.println(flag); // result:truenoneMath——检查是否没有匹配所有元素 判断数据列表中全部元素都不符合设置的predicate条件如果是就返回true否则返回false流为空时总是返回true。
ListString list Arrays.asList(dddd, ee, qqq, bcfff);
boolean isMatch list.stream().noneMatch(str - str.startsWith(a));
System.out.println(isMatch); // result:truefindFirst——返回第一个元素 OptionalT findFirst();
ListString list Arrays.asList(dddd, ee, qqq, bcfff);
OptionalString result list.stream().findFirst();
System.out.println(result.get()); // result:ddddfindAny——返回当前流中的任意元素。返回的元素是不确定的对于同一个列表多次调用findAny()有可能会返回不同的值。count——返回流中元素的总个数max——返回流中最大值、min——返回流中最小值
ListEmployee employeeList new ArrayListEmployee();
employeeList.add(new Employee(15, 18801171255, 张三, 8000));
employeeList.add(new Employee(18, 18801171256, 李四, 9000));
employeeList.add(new Employee(20, 18801171257, 王五, 1000));
employeeList.add(new Employee(30, 18801171258, 赵六, 1000));Employee maxAgeemployee employeeList.stream().max((e1, e2) - Integer.compare(e1.age, e2.getAge())).get();
System.out.println(maxAgeemployee);
// result:Employee{age30, mobile18801171258, name赵六, salary1000}Employee minAgeemployee employeeList.stream().min((e1, e2) - Integer.compare(e1.age, e2.getAge())).get();
System.out.println(minAgeemployee);
// result:Employee{age15, mobile18801171255, name张三, salary8000}5.2.6 规约与收集
Reduce——它将所有元素组合成单个结果。Reduce的目的是提供一种累积元素的方法将所有元素组合为同一结果可以使用reduce进行summinmaxcount等操作
ListInteger list Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum list.stream().reduce(0, (x, y) - x y);
System.out.println(sum); // result: 55收集 collect——将流转化为其他形式。接收一个Collector接口的实现。Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法可以方便地创建常见的收集器实例。
ListEmployee employeeList new ArrayListEmployee();
employeeList.add(new Employee(15, 18801171255, 张三, 8000));
employeeList.add(new Employee(18, 18801171256, 李四, 9000));
employeeList.add(new Employee(20, 18801171257, 王五, 1000));
employeeList.add(new Employee(30, 18801171258, 赵六, 1000));// 把名字收集成List集合
ListString nameList employeeList.stream().map(Employee::getName).collect(Collectors.toList());// 把年龄收集成set集合
SetInteger ageList employeeList.stream().map(Employee::getAge).collect(Collectors.toSet());// 收集成Map key:age valuemobile
MapInteger, String ageAndMobileMap employeeList.stream().collect(Collectors.toMap(Employee::getAge, Employee::getMobile));6. 并行流 parallelStream 并行流就是把一个内容分成多个数据块并用不同的线程分别处理每个数据块的流。 Java8中将并行流进行了优化我们可以很容易的对数据进行并行操作Stream API 可以声明性地通过parallel()与sequential()在并行流与顺序流之间进行切换。 这里举个
Integer sum Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8).parallelStream().reduce(0, Integer::sum);注意
顺序问题
ListInteger list Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);list.parallelStream().forEach(System.out::print);
// 65148723list.stream().forEach(System.out::print);
// 12345678list.parallelStream().forEachOrdered(System.out::print);
// 12345678线程安全问题
public static void main(String[] args) {printFun();
}
public static void printFun() {ListInteger integersList new ArrayList();for (int i 0; i 100; i) {integersList.add(i);}//普通集合 存储ListInteger parallelStorage new ArrayList();//同步集合 存储ListInteger parallelStorage2 Collections.synchronizedList(new ArrayList());//通过并行流存入普通集合parallelStorage中integersList.parallelStream().filter(i - i % 2 0).forEach(i - parallelStorage.add(i));System.out.println(开始打印普通集合parallelStorage);parallelStorage.stream().forEach(e - System.out.print(e ));System.out.println();System.out.print(------------------------------------);System.out.println();//通过并行流存入同步集合parallelStorage2中integersList.parallelStream().filter(i - i % 2 0).forEach(i - parallelStorage2.add(i));System.out.println(开始打印同步集合parallelStorage);parallelStorage2.stream().forEach(e - System.out.print(e ));
}ListString resultList new CopyOnWriteArrayList();
ListString resultList Collections.synchronizedList(new ArrayList());7. Optional 类 OptionalT类(java.util.Optional)是一个容器类代表一个值存在或者不存在原来用null表示一个值不存在现在Optional可以更好的表达这个概念并且可以避免空指针异常。 常用方法
Optional.of(T t)创建一个Optional实例
OptionalPerson op Optional.of(new Employee());
op.get();Optional.empty()创建一个空的Optional实例
Optional op Optional.empty();
op.get();
// NoSuchElementExceptionOptional.ofNullable(T t)若t不为null创建Optional实例否则创建空实例
OptionalPerson op Optional.ofNullable(new Employee());
System.out.println(op.get());
// result: Employee{agenull, mobilenull, namenull, salarynull}orElse(T t)如果调用对象包含值返回该值否则返回t
OptionalEmployee op Optional.ofNullable(null);
Employee employee op.orElse(new Employee(15, 18801171255, 张三, 8000));
System.out.println(employee);
// result: Employee{age15, mobile18801171255, name张三, salary8000}orElseGet(Supplier s)如果调用对象包含值返回该值否则返回s获取到的值
OptionalEmployee op Optional.ofNullable(null);
Employee employee op.orElseGet(() - new Employee(15, 18801171255, 张三, 8000));
System.out.println(employee);
// result: Employee{age15, mobile18801171255, name张三, salary8000}map(Function f)如果有值对其处理并返回处理后的Optional否则返回Optional.empty()
OptionalEmployee op Optional.ofNullable(new Employee(15, 18801171255, 张三, 8000)));
OptionalString opStr op.map(e - e.getName());
System.out.println(opStr.get());
// result:张三flatMap(Function mapper)与map类似要求返回值必须是Optional
OptionalEmployee op Optional.ofNullable(new Employee(15, 18801171255, 张三, 8000));
OptionalString opStr op.flatMap(e - Optional.of(e.getName()));
System.out.println(opStr.get());
// result:张三8. 新的时间API 8.1 java.time 主要类
LocalDateTime.class //日期时间 format: yyyy-MM-ddTHH:mm:ss.SSS
LocalDate.class //日期 format: yyyy-MM-dd
LocalTime.class //时间 format: HH:mm:ss8.2 应用对比
8.2.1 格式化对比
Java 8 之前
import java.text.SimpleDateFormat;
import java.util.Date;public void oldFormat(){Date now new Date();//format yyyy-MM-dd HH:mm:ssSimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd);String date sdf.format(now);System.out.println(String.format(date format : %s, date));result: date format : 2023-03-14
------------------------------------------------------------------//format HH:mm:ssSimpleDateFormat sdft new SimpleDateFormat(HH:mm:ss);String time sdft.format(now);System.out.println(String.format(time format : %s, time));result: time format : 15:45:32
------------------------------------------------------------------//format yyyy-MM-dd HH:mm:ssSimpleDateFormat sdfdt new SimpleDateFormat(yyyy-MM-dd HH:mm:ss);String datetime sdfdt.format(now);System.out.println(String.format(dateTime format : %s, datetime));dateTime format : 2023-03-14 15:45:32
}Java 8 之后:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;public void newFormat(){//format yyyy-MM-ddLocalDate date LocalDate.now();System.out.println(String.format(date format : %s, date));result:date format : 2023-03-14
------------------------------------------------------------------//format HH:mm:ssLocalTime time LocalTime.now().withNano(0);System.out.println(String.format(time format : %s, time));result:time format : 15:49:16
------------------------------------------------------------------//format yyyy-MM-dd HH:mm:ssLocalDateTime dateTime LocalDateTime.now();DateTimeFormatter dateTimeFormatter DateTimeFormatter.ofPattern(yyyy-MM-dd HH:mm:ss);String dateTimeStr dateTime.format(dateTimeFormatter);System.out.println(String.format(dateTime format : %s, dateTimeStr));result:dateTime format : 2023-03-14 15:49:16
}8.2.2 字符串转日期格式
Java 8 之前
SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd);
Date date1 sdf.parse(2022-09-20);Java 8 之后:
public static LocalDate parse(CharSequence text) {return parse(text, DateTimeFormatter.ISO_LOCAL_DATE);
}LocalDate.parse(2022-07-06);LocalDateTime.parse(2021-01-26 12:12:22);LocalTime.parse(12:12:22);8.2.3 日期计算
Java 8 之前
SimpleDateFormat formatDate new SimpleDateFormat(yyyy-MM-dd);
Calendar ca Calendar.getInstance();
ca.add(Calendar.DATE, 7);
Date d ca.getTime();
String after formatDate.format(d);
System.out.println(一周后日期 after);result:一周后日期2023-03-21
-----------------------------------------------------------------------//算两个日期间隔多少天计算间隔多少年多少月方法类似
String dates1 2023-12-23;
String dates2 2023-02-26;
SimpleDateFormat format new SimpleDateFormat(yyyy-MM-dd);
Date date1 format.parse(dates1);
Date date2 format.parse(dates2);
int day (int) ((date1.getTime() - date2.getTime()) / (1000 * 3600 * 24));
System.out.println(dates2 和 dates2 相差 day 天);result:2023-02-26和2023-02-26相差300天Java 8 之后:
public void pushWeek(){//一周后的日期LocalDate localDate LocalDate.now();//方法1LocalDate after localDate.plus(1, ChronoUnit.WEEKS);//方法2LocalDate after2 localDate.plusWeeks(1);System.out.println(一周后日期 after);result:一周后日期2023-03-21
-----------------------------------------------------------------------//算两个日期间隔多少天计算间隔多少年多少月LocalDate date1 LocalDate.parse(2021-02-26);LocalDate date2 LocalDate.parse(2021-12-23);Period period Period.between(date1, date2);System.out.println(date1 到 date2 相隔 period.getYears() 年 period.getMonths() 月 period.getDays() 天);result:date1 到 date2 相隔0年9月27天
------------------------------------------------------------------------- //这里period.getDays()得到的天是抛去年月以外的天数并不是总天数//如果要获取纯粹的总天数应该用下面的方法long day date2.toEpochDay() - date1.toEpochDay();System.out.println(date2 和 date2 相差 day 天);result:2023-12-23和2023-12-23相差300天
}8.2.4 获取指定日期
Java 8 之前
public void getDay() {SimpleDateFormat format new SimpleDateFormat(yyyy-MM-dd);//获取当前月第一天Calendar c Calendar.getInstance();c.set(Calendar.DAY_OF_MONTH, 1);String first format.format(c.getTime());System.out.println(first day: first);//获取当前月最后一天Calendar ca Calendar.getInstance();ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));String last format.format(ca.getTime());System.out.println(last day: last);//当年最后一天Calendar currCal Calendar.getInstance();Calendar calendar Calendar.getInstance();calendar.clear();calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));calendar.roll(Calendar.DAY_OF_YEAR, -1);Date time calendar.getTime();System.out.println(last day: format.format(time));
}Java 8 之后:
public void getDayNew() {LocalDate today LocalDate.now();//获取当前月第一天LocalDate firstDayOfThisMonth today.with(TemporalAdjusters.firstDayOfMonth());// 取本月最后一天LocalDate lastDayOfThisMonth today.with(TemporalAdjusters.lastDayOfMonth());//取下一天LocalDate nextDay lastDayOfThisMonth.plusDays(1);//当年最后一天LocalDate lastday today.with(TemporalAdjusters.lastDayOfYear());//2023年最后一个周日如果用Calendar是不得烦死。LocalDate lastMondayOf2023 LocalDate.parse(2023-12-31).with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
}