JAVA8新特性
1、Lambda表达式
1.1 Lambda表达式的介绍
-
定义:特殊的匿名内部类 匿名内部类一种简化写法
-
作用:使特殊的匿名内部类语法更简洁
-
语法:
<函数式接口> <变量名> =(参数1,参数2…)- >{
//方法体
};
定义一个函数式接口
package com.my;
/**
* 函数式接口 --一个接口只有一个抽象方法
*
* @FunctionalInterface 检测是否是函数式接口
*/
@FunctionalInterface
public interface Demo_Interface {
void service();
}
1.2 Lambda的使用一
package com.my;
import java.util.Comparator;
import java.util.TreeSet;
/**
* Lambda表达式
*
* 定义:特殊的匿名内部类 匿名内部类一种简化写法
*
* 作用:使特殊的匿名内部类语法更简洁
*
* 语法:
* <函数式接口> <变量名> =(参数1,参数2...)- >{
* //方法提
* };
*
*/
public class Demo {
public static void main(String[] args) {
Demo_Interface demo=()-> System.out.println("Demo_Interface--被三次调用");
run(demo);
//Runnable创建线程
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("runnable被执行一次");
}
};
new Thread(runnable).start();
Runnable runnable2=()->System.out.println("runnable被执行二次");//方法体只有一句 可省略大括号
new Thread(runnable2).start();
new Thread(()-> System.out.println("runnable被执行三次")).start();//把lambda表达式当作参数传递
//comparator比较器
Comparator<String> comparable=new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
};
//Lambda表达式简化
Comparator<String> comparable2=(o1, o2) ->o1.length()-o2.length();
Comparator<String> comparable3=(String o1, String o2) ->{
return o1.length()-o2.length();
};
//TreeSet中的比较器
TreeSet<String> treeSet=new TreeSet<>(comparable);
TreeSet<String> treeSet2=new TreeSet<>(comparable2);
TreeSet<String> treeSet3=new TreeSet<>(comparable3);
}
public static void run(Demo_Interface demoInterface) {
demoInterface.service();
}
}
1.3 Lambda的使用二
package com.my;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class Demo02 {
public static void main(String[] args) {
//匿名内部类方式 Consumer消费接口
Consumer<Double> consumer=new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("第一次聚餐消费:"+aDouble);
}
};
//Lambda表达式
Consumer<Double> consumer2=(Double aDouble)-> System.out.println("第二次聚餐消费:"+aDouble);
happy(consumer,200);
happy(consumer2,400);
happy(aDouble-> System.out.println("第三次聚餐消费:"+aDouble),600);
int[] arr = getNums(() -> new Random().nextInt(100), 5);
System.out.println(Arrays.toString(arr));
String s1 = handlerString(s -> s.toUpperCase(), " hello bb");
String s2 = handlerString(s -> s.trim(), " hello bb");
System.out.println(s1);
System.out.println(s2);
List<String> names=new ArrayList<String>();
names.add("张国光");
names.add("李鸿章");
names.add("张玲玲");
names.add("王琦");
List<String> stringList = filterName(s -> s.startsWith("张"), names);
System.out.println(stringList.toString());
List<String> stringList2 = filterName(s -> s.length()>2, names);
System.out.println(stringList2.toString());
}
//Consumer 消费型接口
public static void happy(Consumer<Double> consumer,double money){
consumer.accept(money);
}
//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;
}
//Function 函数型接口 --既有参数又有返回值
public static String handlerString(Function<String,String> function,String str){
return function.apply(str);
}
//Predicate 断言型接口
public static List<String> filterName(Predicate<String> predicate,List<String> list){
List<String> resultList=new ArrayList<String>();
for (String str:list){
if(predicate.test(str)){
resultList.add(str);//如果符合要求放进集合
}
}
return resultList;
}
}
1.4 方法引用
-
定义:对Lambda表达式的简写形式
-
条件:Lambda表达式方法体中只是调用一个特定已经存在的方法
- 常见形式:
-
对象::实例方法
-
类::静态方法
-
类::实例方法
-
类::new
-
package com.my;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* 方法引用的使用
*/
public class Demo04 {
public static void main(String[] args) {
//对象::实例方法
Consumer<String> consumer=s-> System.out.println(s);
consumer.accept("hello");
Consumer<String> consumer1=System.out::println;
//类::静态方法
Comparator<Integer> comparator=(o1,o2) ->Integer.compare(o1,02);
Comparator<Integer> comparator1=Integer::compare;
//类::实例方法
Function<User,Integer> user=u->u.getAge();
Function<User,String> user2=User::getName;
System.out.println(user.apply(new User("张三", 19)));
//类::new
}
}
2、Stream
2.1 什么是Stream?
流(Stream)中保存对集合或数组数据的操作。和集合类似,但集合中保存的是数据。这个流类似生活中的流水线,由原料用过一系列操作成产品
2.2 Stream特点
- 不会存储数据
- 不会改变源对象,会返回一个持有结果的新Stream
- 操作是延迟执行,意味它们会等到需要结果的时候才执行
2.3 Stream使用步骤
- 创建
- 新建一个流
- 中间操作
- 在一个或多个步骤中,将初始化Stream转化到另一个Stream的中间操作
- 终止操作
- 使用一个终止操作来产生一个结果,该操作会强制它之前的延迟操作立即执行。在这之后,该Stream再无法使用
2.4 创建Stream的几种方法
-
通过Collection对象的Stream()–(单线程)或parallelStream()–(多线程可使用)方法
-
通过Arrays类的stream()方法
-
通过Stream接口of()、iterate()、generate()方法
-
通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法
package com.my; import java.util.ArrayList; import java.util.Arrays; import java.util.Random; import java.util.stream.IntStream; import java.util.stream.Stream; /** * Stream的创建方式 */ public class Demo05 { public static void main(String[] args) { System.out.println("--------1、Collection对象的Stream()----------"); ArrayList<String> list=new ArrayList<>(); list.add("哈哈"); list.add("好好"); list.add("嘿嘿"); list.add("嘻嘻"); list.add("嘎嘎"); Stream<String> stream=list.stream(); // Lambda遍历 //stream.forEach(s->System.out.println(s)); stream.forEach(System.out::println); System.out.println("--------2、Arrays的工具类的Stream方法----------"); //2、Arrays的工具类的Stream方法 String[] arr={"aa","bb","cc"}; Stream<String> stringStream= Arrays.stream(arr); stringStream.forEach(System.out::println); //3、Stream接口中的of iterate generate方法 System.out.println("--------Stream接口中的方法----------"); //of Stream<Integer> stream1=Stream.of(10,20,30,40,50); stream1.forEach(System.out::println); System.out.println("--------迭代流---------"); //迭代流 iterate Stream<Integer> iterate = Stream.iterate(0, x -> x + 2); //中间操作 十个数 0-10 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); //4、通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法 System.out.println("-----IntStream的of------"); IntStream stream2=IntStream.of(100,200,300); stream2.forEach(System.out::println); System.out.println("-----IntStream的range------"); //IntStream的range开合 rangeClosed方法闭合 IntStream stream3=IntStream.range(0,10); stream3.forEach(System.out::println); IntStream stream4=IntStream.rangeClosed(0,5); stream4.forEach(System.out::println); } }
2.5 常见的Stream中间操作、终止操作
2.5.1 中间操作
- filter:过滤 limit限制 skip跳过 distinct去重 sorted排序
- map 映射成另一组数据
- parallel
2.5.2 终止操作
-
forEach min max count
-
reduce collect
package com.my; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; /** * 关于Stream的中间操作、终止操作 */ public class Demo06 { public static void main(String[] args) { ArrayList<User> list=new ArrayList<User>(); list.add(new User("哈哈",20)); list.add(new User("嘻嘻",66)); list.add(new User("嘿嘿",40)); list.add(new User("谔谔",88)); list.add(new User("嘻嘻",66)); //过滤filter System.out.println("过滤filter"); list.stream() .filter(e->e.getAge()>40) .forEach(System.out::println); //limit 限制 System.out.println("limit 限制"); list.stream().limit(2).forEach(System.out::println); //skip System.out.println("skip 跳过"); list.stream().skip(2).forEach(System.out::println); //distinct 去重 System.out.println("distinct 去重"); list.stream().distinct().forEach(System.out::println); //sorted parallelStream比stream效率高 并行的 System.out.println("sorted 排序"); list.parallelStream().sorted((e1,e2)->Double.compare(e1.getAge(),e2.getAge())) .forEach(System.out::println); //map 获取所有年龄 System.out.println("map方式------获取所有年龄"); list.stream().map(e->e.getAge()) .forEach(System.out::println); System.out.println("parallel 采用多线程效率"); //parallel 采用多线程效率高 list.stream().parallel().forEach(System.out::println); System.out.println("----------终止操作-------------------------"); list.stream().filter(e->{ System.out.println("终止操作过滤"); return e.getAge() > 40; }).forEach(System.out::println); System.out.println("-----------计算最小年龄----------"); Optional<User> user=list.stream() .min((e1,e2)->Double.compare(e1.getAge(),e2.getAge())); System.out.println(user.get()); System.out.println("计算数目"); long count=list.stream().count(); System.out.println("人数:"+count); System.out.println("终止操作reduce规约,计算所有任年龄和"); Optional<Integer> sum=list.stream() .map(e->e.getAge()) .reduce((x,y)->x+y); System.out.println(sum.get()); System.out.println("终止操作collect收集,获取所有人员信息,封装成一个List集合"); List<String> collect = list.stream() .map(s -> s.getName()) .collect(Collectors.toList()); for(String str:collect){ System.out.println(str); } } }
3、 新时间API
3.1 遗留时间问题
jdk1.8之前时间API存在线程安全问题,设计混乱
注释的为jdk1.8之前,多线程运行多次会出现异常,注释下面的代码为jdk1.8的日期使用,避免问题
package com.my;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
/**
* 存在线程安全问题
*/
public class Demo07 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//jdk1.6
//SimpleDateFormat simple=new SimpleDateFormat("yyyyMMdd");
//jdk1.8 解决以前时间线程安全问题
DateTimeFormatter date = DateTimeFormatter.ofPattern("yyyyMMdd");
//创建固定大小线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//提交十个任务 每个任务都获取时间
//Callable<Date> callable=new Callable<Date>() {
Callable<LocalDate> callable = new Callable<LocalDate>() {
/*@Override
public Date call() throws Exception {
//采用同步块使线程安全
synchronized (simple){
return simple.parse("20200606");
}
}*/
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("20200606", date);
}
};
//List<Future<Date>> list=new ArrayList<>();
List<Future<LocalDate>> list=new ArrayList<>();
for (int i=0;i<10;i++){
//Future<Date> future=executorService.submit(callable);
Future<LocalDate> future=executorService.submit(callable);
list.add(future);
}
//for(Future<Date> future:list){
for(Future<LocalDate> future:list){
System.out.println(future.get());
}
executorService.shutdown();
}
}
3.2 LocalDateTime的使用
package com.my;
import java.time.LocalDateTime;
public class Demo08 {
public static void main(String[] args) {
//LocalDateTime的使用
LocalDateTime localDateTime=LocalDateTime.now();
System.out.println(localDateTime);
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
//添加时间 两天
LocalDateTime localDateTime1=localDateTime.plusDays(2);
System.out.println(localDateTime1);
//减少时间
LocalDateTime localDateTime2=localDateTime.minusMonths(1);
System.out.println(localDateTime2);
}
}
3.3 Instant ZoneId的使用
package com.my;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Set;
public class Demo09 {
public static void main(String[] args) {
//创建时间戳
Instant instant=Instant.now();
//格林尼治时区 错差八个小时
System.out.println(instant.toString());
//自1970-01-01T00:00:00Z时代以来的毫秒数。
System.out.println(instant.toEpochMilli());
//当前时间毫米数
System.out.println(System.currentTimeMillis());
//获取某个毫秒数的时间 Instant.ofEpochMilli()
//获取某秒数的时间 Instant.ofEpochSecond()
//2 添加 减少时间
// 加 10s
Instant instant1=instant.plusSeconds(10);
//打印的是差毫秒单位
System.out.println(Duration.between(instant, instant1).toMillis());
//3 时区 当前系统支持时间的时区
Set<String> set= ZoneId.getAvailableZoneIds();
for (String str:set){
System.out.println(str);
}
//获取当前时区
System.out.println(ZoneId.systemDefault().toString());
}
}