Java8新特性
一、Lambda表达式
lambda表达式的基础语法:
-
Java8中引入了一个新的操作符“->"该操作符称为箭头操作符或Lanbdam操作符
-
箭头操作符将Lambda表达式拆成两部分
左侧:Lambda表达式的参数列表
右侧:Lambda表达式中所需执行的功能,即Lambda体
-
语法格式一:无参,无返回值
() -> System.out.println("Hello Lambda!");
//无参,无返回值的Lambda表达式 @Test public void test1() { Runnable r1 = () -> System.out.println("Hello Lambda!"); r1.run(); }
-
语法格式二:有一个参数,并且无返回值
(x) -> System.out.println(x);
//有参,无返回值的Lambda表达式 @Test public void test2() { Consumer<String> con = (x) -> System.out.println(x); con.accept("嘻嘻嘻"); }
-
语法格式三:如果只有一个参数,并且无返回值,小括号可以省略
x -> System.out.println(x);
//有参,无返回值的Lambda表达式 @Test public void test2() { Consumer<String> con = x -> System.out.println(x); con.accept("嘻嘻嘻"); }
-
语法格式四:如果有两个以上的参数,有返回值,并且Lambda体中有多条语句
Comparator<Integer> com = (x , y) -> { System.out.println("函数式接口!"); return Integer.compare(x,y); };
//有多个参数,并且Lamdba体中有多条语句 @Test public void test3() { Comparator<Integer> com = (x , y) -> { System.out.println("函数式接口!"); return Integer.compare(x,y); }; }
-
语法格式五:如果有两个以上的参数,有返回值,并且Lambda体中只有一条语句,大括号和return都可以省略不写
Comparator<Integer> com = (x , y) -> Integer.compare(x,y);
-
语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器会通过上下文推断数据类型,即”类型推断“。
Lamdba表达式需要”函数式接口“的支持
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface修饰,可以标明该接口为函数式接口
二、Java8内置的四大核心函数式接口
-
Consumer<T>:消费型接口
void accept(T t);
-
Supplier<T>:供给型接口
T get();
-
Function<T, R>:函数型接口
R apply(T t);
-
Predicate<T>:断言型接口
boolean test(T t);
三、引用
方法引用
方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用”方法引用“(可以理解成方法引用就是Lambda表达式的另一种表现方式)
主要有三种方式:
-
对象::实例方法名
-
类::静态方法名
-
类::实例方法名
对象::实例方法名
@Test public void test1() { //传统方式 PrintStream ps1 = System.out; Consumer<String> con1 = (x) -> ps1.println(x); //对象::实例方法名 PrintStream ps2 = System.out; Consumer<String> con2 = ps2::println; Consumer<String> con3 = System.out::println; con3.accept("嘻嘻嘻"); }
类::静态方法名:Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回类型一致
@Test public void test2() { //传统方式 Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y); //类::静态方法名 Comparator<Integer> com2 = Integer::compare; }
类::实例方法名:若Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method;
@Test public void test3() { //传统方式 BiPredicate<String, String> bp1 = (x, y) -> x.equals(y); //类::方法名 BiPredicate<String, String> bp2 = String::equals; }
构造器引用
ClassName::new;
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!
//构造器引用 @Test public void test4() { //传统方式 Supplier<String> sup = () -> new String(); //构造器引用方式 Supplier<String> sup1 = String::new; String s = sup1.get(); System.out.println(s); } @Test public void test5() { //传统方式 Function<String,String> fun = (x) -> new String(x); //构造器引用方式 Function<String,String> fun1 = String::new; String s = fun.apply("嘻嘻嘻"); System.out.println(s); }
数组引用
Type::new;
//数组引用 @Test public void test7() { //传统方式 Function<Integer, String[]> fun = (x) -> new String[x]; String[] strs = fun.apply(10); System.out.println(strs.length); //数组引用 Function<Integer, String[]> fun1 = String[]::new; String[] strs1 = fun.apply(10); System.out.println(strs1.length); }
四、Stream
Stream的三个操作步骤:
-
创建Stream
-
中间操作
-
终止操作(终端操作)
-
创建Stream
List<User> list = Arrays.asList( new User("张三", 78), new User("里斯", 28), new User("王五", 38), new User("赵六", 48), new User("天气", 58), new User("天气", 58), new User("天气", 58) );
//创建Stream @Test public void test1() { //1.通过Collection系列集合提供的stream()或parallelStream() List<String> list = new ArrayList<>(); Stream<String> stream1 = list.stream(); //2.通过Arrays中的静态方法stream获取数组流 String[] strs = new String[10]; Stream<String> stream2 = Arrays.stream(strs); //3.通过Stream类中的静态方法of() Stream<String> stream3 = Stream.of("aa","bb","cc"); //创建无限流 Stream<Integer> stream4 = Stream.iterate(0,(x) -> x + 2); }
-
中间操作:
filter——接收Lamdba,从流中排除某些元素。
@Test public void test2() { //中间操作,不会执行任何操作 Stream<User> stream = list.stream().filter((e) -> e.getAge() > 20); //终止操作:一次性执行全部内容,即“惰性求值” stream.forEach(System.out::println); }
limit——截断流,使其元素不超过给定数量
@Test public void test3() { //中间操作,不会执行任何操作 Stream<User> stream = list.stream().filter((e) -> e.getAge() > 20).limit(2); //终止操作:一次性执行全部内容,即“惰性求值” stream.forEach(System.out::println); }
skip——跳过元素,返回一个扔掉了前n个元素的流。若流中的元素不超过n个,则返回一个空流。与limit互补。
@Test public void test4() { //中间操作,不会执行任何操作 Stream<User> stream = list.stream().filter((e) -> e.getAge() > 20).skip(2); //终止操作:一次性执行全部内容,即“惰性求值” stream.forEach(System.out::println); }
distinct——筛选,通过流所生成元素的hashCode()和equals()去除重复元素
@Test public void test5() { //中间操作,不会执行任何操作 Stream<User> stream = list.stream().filter((e) -> e.getAge() > 20).distinct(); //终止操作:一次性执行全部内容,即“惰性求值” stream.forEach(System.out::println); }
映射:
map——接收Lambda,将元素转换成其他形式或提取信息。接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
@Test public void test6() { List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee"); list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println); }
@Test public void test7() { List<String> list1 = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee"); Stream<Stream<Character>> stream = list1.stream().map(StreamTest::getChar); stream.forEach((sm) -> { sm.forEach(System.out::println); }); }
flatmap——接收一个函数作为参数,将子流中的每个值都放到主流中,最终只有一个流,不包括子流。
@Test public void test8() { List<String> list1 = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee"); Stream<Character> stream = list1.stream().flatMap(StreamTest::getChar); stream.forEach(System.out::println); }
排序:
sorted()——自然排序(Comparable)
@Test public void test9() { List<String> list1 = Arrays.asList("aaa", "eee", "bbb", "ccc", "ddd"); Stream<String> stream = list1.stream().sorted(); stream.forEach(System.out::println); }
sorted(Comparator com)——定制排序(Comparator)
@Test public void test10() { list.stream().sorted((e1, e2) -> { if(e1.getAge() == (e2.getAge())) { return e1.getName().compareTo(e2.getName()); } else { return e1.getAge() - (e2.getAge()); } }).forEach(System.out::println); }
-
终止操作
查找与匹配
allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配所有元素
findFirst——返回第一个元素
findAny——返回当前流中的任意一个元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值
List<User> users = Arrays.asList( new User("里斯", 28, User.Status.free), new User("王五", 38,User.Status.busy), new User("赵六", 48,User.Status.busy), new User("天气", 58,User.Status.vocation), new User("张三", 78, User.Status.busy) ); @Test public void test1() { boolean b = users.stream().allMatch((e) -> e.getStatus().equals(User.Status.free)); System.out.println(b); boolean b1 = users.stream().anyMatch((e) -> e.getStatus().equals(User.Status.free)); System.out.println(b1); boolean b2 = users.stream().noneMatch((e) -> e.getStatus().equals(User.Status.free)); System.out.println(b2); Optional<User> user1 = users.stream().findFirst(); System.out.println(user1.get()); Optional<User> user2 = users.parallelStream().findAny(); System.out.println(user2.get()); Long count = users.stream().count(); System.out.println(count); Optional<User> user3 = users.stream().max((e1, e2) -> e1.getAge() - e2.getAge()); System.out.println(user3.get()); Optional<User> user4 = users.stream().min((e1, e2) -> e1.getAge() - e2.getAge()); System.out.println(user4.get()); }
规约:
reduce(T identity, BinaryOperator)( 得到一个T)/reduce(BinaryOperator) (得到一个Optional<T>)——可以将流中元素反复结合起来,得到一个值
@Test public void test2() { List<Integer> 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); Optional<Integer> sum1 = list.stream().reduce((x, y) -> x + y); System.out.println(sum1.get()); }
收集:
collect——将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
//将指定元素收集放在list集合中 @Test public void test3() { List<String> l = users.stream().map(User::getName).collect(Collectors.toList()); //l.forEach(System.out::println); l.forEach((x)-> System.out.println(x)); }
@Test public void test4() { //总数 Long count = users.stream().collect(Collectors.counting()); System.out.println(count); //平均值 Double avg = users.stream().collect(Collectors.averagingDouble(User::getAge)); System.out.println(avg); //总和 Double sum = users.stream().collect(Collectors.summingDouble(User::getAge)); System.out.println(sum); //最大值 Optional<User> max = users.stream().collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getAge(), e2.getAge()))); System.out.println(max); //最小值 Optional<User> min = users.stream().collect(Collectors.minBy((e1,e2) -> Double.compare(e1.getAge(), e2.getAge()))); System.out.println(min); }
//分组 @Test public void test5() { Map<User.Status,List<User>> map = users.stream().collect(Collectors.groupingBy(User::getStatus)); System.out.println(map); }
//分区 @Test public void test6() { Map<Boolean,List<User>> map = users.stream().collect(Collectors.partitioningBy((e) -> e.getAge() > 50)); System.out.println(map); }
//对指定的元素进行对各操作 @Test public void test7() { DoubleSummaryStatistics dss = users.stream().collect(Collectors.summarizingDouble(User::getAge)); System.out.println(dss.getMax()); System.out.println(dss.getAverage()); System.out.println(dss.getMin()); System.out.println(dss.getCount()); }
五、Optional
Optional<T>类是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念,并且可以避免空指针异常。
Optional.of(T t):创建一个Optional实例
@Test public void test1() { Optional<String> op = Optional.of(new String("嘻嘻嘻")); System.out.println(op.get()); }
Optional.empty():创建一个空的Optional实例
@Test public void test2() { Optional<String> op = Optional.empty(); System.out.println(op.get()); }
Optional.ofNullable(T t):如果T不为空,则创建一个Optional实例,否则创建空实例
@Test public void test3() { Optional<String> op = Optional.ofNullable(new String("嘻嘻嘻")); System.out.println(op.get()); }
isPresent():判断是否包含值
orElse(T t);如果该容器有值,则返回该值,否则返回T值
@Test public void test4() { Optional<String> op = Optional.ofNullable(null); if(op.isPresent()) { System.out.println(op.get()); } else { System.out.println("该容器没有值"); } System.out.println(op.orElse("代替的值")); }
orElseGet(Supplier s):如果该容器有值,则返回该值,否则返回s返回的值
@Test public void test5() { Optional<String> op = Optional.ofNullable(null); String s = op.orElseGet(() -> "2"); System.out.println(s); }
map(Function f):如果该容器有值,则返回经过f函数处理后的值,否则返回Optional.empty()
flatMap(Function mapper):与map类似,要求mapper返回值必须是Optional
@Test public void test6() { Optional<String> op = Optional.ofNullable(new String("aBcd")); Optional<String> op1 = op.map((x) -> x.toUpperCase()); System.out.println(op1.get()); Optional<String> op2 = op.flatMap((x) -> Optional.of(x.toLowerCase())); System.out.println(op2.get()); }
六、日期类
LocalDateTime
@Test public void test1() { //获取当前时间 LocalDateTime ldt1 = LocalDateTime.now(); System.out.println(ldt1); //创建指定时间的日期对象 LocalDateTime ldt2 = LocalDateTime.of(2020,10,10,12,23,30); System.out.println(ldt2); //对日期对象加操作 LocalDateTime ldt3 = ldt1.plusYears(1); System.out.println(ldt3); //对日期对象减操作 LocalDateTime ldt4 = ldt1.minusYears(1); System.out.println(ldt4); //获取日期的年,月,日等 System.out.println(ldt1.getYear()); System.out.println(ldt1.getMonth()); System.out.println(ldt1.getMonthValue()); System.out.println(ldt1.getDayOfMonth()); System.out.println(ldt1.getHour()); }
Instant:时间戳(以1970年1月1日00:00:00到某个时间之间的毫秒值)
@Test public void test2() { Instant ins1 = Instant.now();//默认获取UTC时区 System.out.println(ins1); OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8)); System.out.println(odt); //时间戳 System.out.println(ins1.toEpochMilli()); Instant ins2 = Instant.ofEpochSecond(60);//在1970/1/1 00:00:00基础上加秒 System.out.println(ins2); }
Duration:计算两个时间之间的间隔
@Test public void test3() { //获取时间戳间隔 Instant ins1 = Instant.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Instant ins2 = Instant.now(); Duration duration = Duration.between(ins1, ins2); System.out.println(duration.toMillis()); System.out.println("------------------------------"); //获取时间间隔 LocalTime lt1 = LocalTime.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } LocalTime lt2 = LocalTime.now(); Duration duration1 = Duration.between(lt1, lt2); System.out.println(duration1.toMillis()); }
Period:计算两个日期之间的间隔
//Period:获取日期之间的间隔 @Test public void test4() { LocalDate ld1 = LocalDate.now(); LocalDate ld2 = LocalDate.now().plusYears(1); Period period = Period.between(ld1, ld2); System.out.println(period); }
TemporalAdjuster:时间校正器
@Test public void test5() { LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt); //矫正时间 LocalDateTime ldt1 = ldt.withDayOfMonth(10); System.out.println(ldt1); //调用TemporalAdjusters实现的方法 LocalDateTime ldt2 = ldt.with(TemporalAdjusters.firstDayOfYear()); System.out.println(ldt2); //自定义实现方法:下一个工作日 LocalDateTime ldt4 = ldt.with((l) -> { LocalDateTime ldt3 = (LocalDateTime)l; DayOfWeek dow = ldt3.getDayOfWeek(); if(dow.equals(DayOfWeek.FRIDAY)) { return ldt3.plusDays(3); } else if(dow.equals(DayOfWeek.SATURDAY)){ return ldt3.plusDays(2); } else { return ldt3.plusDays(1); } }); System.out.println(ldt4); }
DateTimeFormatter:格式化时间
@Test public void test6() { //调用DateTimeFormatter方法指定格式 DateTimeFormatter dtf = DateTimeFormatter.BASIC_ISO_DATE; LocalDateTime ldt = LocalDateTime.now(); String str = ldt.format(dtf); System.out.println(str); //自定义 DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm:ss"); String str1 = ldt.format(dtf1); System.out.println(str1); //将字符串转换为日期 DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); LocalDateTime newDate = LocalDateTime.parse("2020/04/03 14:57:41",dtf2); System.out.println(newDate); }