java8(jdk1.8),是java语言的一个主要版本,oracle公司于2014年3月18日发布的。2017年之后oracle决定每半年发布一次版本。
- 支持Lambda表达式
- 函数式接口
- 新的Stream API
- 新的日期API
- 其他特性(接口变化:包含静态方法和默认方法)
Lambda表达式定义
Lambda表达式:特殊的匿名内部类,语法更简洁,允许把函数作为一个方法的参数
Lambda表达式语法
<函数式接口> <变量名> = (参数1,参数2...)->{
方法体;
}
Lambda表达式总结
- 箭头将表达式分为两部分,左侧为参数,右侧为方法体
- 形参类型可以自动推断
- 如果形参列表为空,只需保留()
- 如果形参只有1个,()可以省略,只需参数名即可
- 如果执行语句只有1句,且无返回值,{}可以省略,若有返回值,若想省去{},则必须同时省略returun,且执行语句也保证这有一句
- lambad不会生成内部类文件
public static void main(String[] args) {
System.out.println("主线程第一步");
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("正常匿名内部类无参");
}
};
//new Thread()省略了
//方法名称省略了
//()代表无参方法,不能省略
//->箭头表达式
//lambad如果方法体就一句话可以省略大括号
//Runnable接口中只有一个抽象方法
Runnable thread2 = () -> System.out.println("Lambda无参");
new Thread(runnable1).start();
new Thread(thread2).start();
new Thread(() -> System.out.println("正常匿名内部类无参")).start();
System.out.println("主线程第二步");
Comparator c1 = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
};
//方法名可以省略
//参数不能省略
// Comparator接口中只有一个抽象方法 equals数据Object类的 不算
Comparator<String> c2 = (String o1, String o2) -> {
return o1.length() - o2.length();
};
//参数类型可以省略
//参数名不可以省略
Comparator<String> c3 = (o1, o2) -> o1.length() - o2.length();
String[] str = {"aadsaf", "dqwd", "dqwfcsqc", "xqsccaac", "csfwffqaf", "czxca", "cas", "cacs", "casc"};
Arrays.sort(str, c3);
System.out.println(Arrays.toString(str));
}
函数式接口定义
- 如果一个接口只有一个抽象方法,则该接口称为函数式接口,函数式接口可以使用lambda表达式,lambda表达式会被匹配到这个抽象方法上
- @FunctionalInterface判断是否函数式接口,只有标记了该注解的接口,才能使用lambad表达式
jdk中常见的函数式接口
@FunctionalInterface
public interface Usb {
void service(String name);
}
public static void main(String[] args) {
//自定义函数式接口
Usb usb =name-> System.out.println("Usb接口实现--"+name);
usb.service("键盘");
paly(name-> System.out.println("Usb接口实现--"+name),"鼠标");
//常用函数式接口实现--消费型
consumer((t)-> System.out.println("聚餐消费:"+t),1000);
consumer((t)-> System.out.println("唱歌消费:"+t),500);
//常用函数式接口实现--供给型
System.out.println(Arrays.toString(supplier(()->new Random().nextInt(9),9)));
//常用函数式接口实现--函数型
System.out.println("把zhangsan编程大写:"+function(name->name.toUpperCase(),"zhangsan"));
//常用函数式接口实现--断言型
List<String> names = Arrays.asList("zhangsan", "lisi", "wangwu");
System.out.println("names集合中是否包含zhangsan:"+predicate(list->list.contains("zhangsan"),names));
}
public static Boolean predicate(Predicate<List<String>> predicate ,List<String> names){
return predicate.test(names);
}
public static String function(Function<String,String> function,String name){
return function.apply(name);
}
public static Integer[] supplier(Supplier<Integer> supplier,Integer count){
Integer[] arry = new Integer[count];
for (int i = 0; i < count; i++) {
arry[i]=supplier.get();
}
return arry;
}
public static void consumer(Consumer<Double> consumer,double money){
consumer.accept(money);
}
public static void paly(Usb usb,String name){
usb.service(name);
}
方法引用
方法引用是lambad表达式的一种简写形式。如果lambad表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用
常见形式
- 对象::实例方法
- 类::静态方法
- 类::实例方法
- 类::new
public static void main(String[] args) {
Consumer<String> consumer = fruits-> System.out.println(fruits);
consumer.accept("香蕉");
//如果lambad表达式中只调用了一个方法
//并且这个lambad表达式的特点和接口的特点一样:只有一个参数 没有返回值,可以同时省略匿名函数的参数列表,和方法体中的参数列表
//就可以使用方法引用 对象::实例方法
Consumer<String> consumer1 = System.out::println;
consumer1.accept("苹果");
//类::静态方法
Comparator<Integer> comparator1 = (o1,o2)->Integer.compare(o1,o2);
Comparator<Integer> comparator2 = Integer::compareTo;
Integer[] array = {9,8,7,6,5,4};
Arrays.sort(array, comparator2);
System.out.println(Arrays.toString(array));
//类::实例方法
Function<String,String> function1= name->name.toUpperCase();
System.out.println(function1.apply("zhangsan"));
Function<String,String> function2= String::toUpperCase;
System.out.println(function2.apply("zhangsan"));
//类::new
Supplier<ArrayList> supplier = ()->new ArrayList<>();
System.out.println(supplier.get());
Supplier<ArrayList> supplier1 = ArrayList::new;
System.out.println(supplier1.get());
}
Stream
流(Stream)中保存对集合或数组数据的操作,和集合类似,但集合中保存的是数据,类似流水线
特点
- Stream自己不会存储元素
- Stream不会改变源对象。相反,他们会返回一个特有结果的新的Stream
- Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行,也就是执行流的终止操作的时候才执行
- 每次创建的stream只能使用一次,否则异常:java.lang.IllegalStateException: stream has already been operated upon or closed
使用步骤
-
创建
新建一个流
public static void main(String[] args) { //通过Collection对象的stream()串行流 //通过Collection对象的parallelStream()并行流 List<String> list = new ArrayList<>(); list.add("苹果"); list.add("香蕉"); Stream<String> stream1 = list.stream(); stream1.forEach(item -> System.out.println(item)); System.out.println("通过Collection对象的stream()串行流----------------"); //通过 Arrays.stream()方法 int[] a = {0, 9, 8}; IntStream stream2 = Arrays.stream(a); stream2.forEach(System.out::println); System.out.println("Arrays.stream----------------"); //通过 Stream.of()、 Stream.iterate()、Stream.generate()方法 Stream<Integer> stream3 = Stream.of(1, 2, 3); stream3.forEach(System.out::println); System.out.println("Stream.of----------------"); //种子,一元操作符 从0开始 之后每次加2 Stream<Integer> stream4 = Stream.iterate(0, x -> x + 2); //limit取前10 stream4.limit(10).forEach(System.out::println); System.out.println(" Stream.iterate----------------"); Stream<Integer> stream5 = Stream.generate(() -> new Random().nextInt(100)); stream5.limit(2).forEach(System.out::println); System.out.println(" Stream.generate----------------"); //通过IntStream LongStream DoubleStream 接口中的 of range rangeClosed方法 IntStream stream6 = IntStream.of(1, 2); stream6.forEach(System.out::println); System.out.println("IntStream.of----------------"); //包括2 IntStream stream7 = IntStream.rangeClosed(0, 2); stream7.forEach(System.out::println); System.out.println("IntStream.rangeClosed----------------"); //不包括2 IntStream stream8 = IntStream.range(0, 2); stream8.forEach(System.out::println); System.out.println("IntStream.range----------------"); //public interface UnaryOperator<T> extends Function<T, T> //是函数型接口 UnaryOperator<Integer> dda = x -> x + 1; //11 System.out.println(dda.apply(1)); //a1 UnaryOperator<String> ddb = x -> x + 1; System.out.println(ddb.apply("aa")); }
-
中间操作
在一个或者多个操作步骤中,将初始化Stream转化到另一个Stream的中间操作
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(1); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(6); list.stream() .filter(item->item>5) .forEach(System.out::println); System.out.println("过滤大于5的数----------"); list.stream() .limit(2) .forEach(System.out::println); System.out.println("取前两个----------"); list.stream() .skip(2) .forEach(System.out::println); System.out.println("跳过前两个----------"); list.stream() .distinct() .forEach(System.out::println); System.out.println("去重----------"); list.stream() .sorted((o1,o2)->o2-o1) .forEach(System.out::println); System.out.println("从大到小排序----------"); list.stream() .map(e->e.doubleValue()) .forEach(System.out::println); System.out.println("把一组数据映射成另外一组数据----------"); list.parallelStream() .forEach(System.out::println); System.out.println("并行流----------"); }
-
终止操作
使用一个终止操作来产生一个结果。该操作会强制它之前的延迟操作立即执行。在这之后,该stream就不会使用了
public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(1); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(6); //forEach list.stream().forEach(System.out::println); System.out.println("forEach------------"); System.out.println(list.stream().min((o1, o2) -> o1 - o2).get()); System.out.println("min------------"); System.out.println(list.stream().max((o1, o2) -> o1 - o2).get()); System.out.println("max------------"); System.out.println(list.stream().max((o1, o2) -> o1 - o2).get()); System.out.println(list.stream().count()); System.out.println("count------------"); System.out.println(list.stream().reduce((x, y) -> x + y).get()); System.out.println("reduce------------"); System.out.println(list.stream().collect(Collectors.toSet())); System.out.println("collect------------"); }
新时间Api
之前时间Api存在的问题:新城安全问题,设计混乱
老的时间apid存在的线程安全问题演示
public static void main(String[] args) throws Exception{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Future<Date>> list = new ArrayList<>();
for (int i = 0; i <100; i++) {
//submit有返回值 execute不能有返回值
Future<Date> submit = executorService.submit(() -> sdf.parse("2021-04-18"));
//放到集合里的目的是运行出下面的错误
list.add(submit);
}
for (Future<Date> dateFuture : list) {
System.out.println(dateFuture.get());
}
executorService.shutdown();
}
多运行几次出现的bug
Exception in thread “main” java.util.concurrent.ExecutionException: java.lang.NumberFormatException: For input string: “”
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at time.Problem.main(Problem.java:22)
Caused by: java.lang.NumberFormatException: For input string: “”
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at time.Problem.lambda$main
0
(
P
r
o
b
l
e
m
.
j
a
v
a
:
17
)
a
t
j
a
v
a
.
u
t
i
l
.
c
o
n
c
u
r
r
e
n
t
.
F
u
t
u
r
e
T
a
s
k
.
r
u
n
0(Problem.java:17) at java.util.concurrent.FutureTask.run
0(Problem.java:17)atjava.util.concurrent.FutureTask.run$
c
a
p
t
u
r
e
(
F
u
t
u
r
e
T
a
s
k
.
j
a
v
a
:
266
)
a
t
j
a
v
a
.
u
t
i
l
.
c
o
n
c
u
r
r
e
n
t
.
F
u
t
u
r
e
T
a
s
k
.
r
u
n
(
F
u
t
u
r
e
T
a
s
k
.
j
a
v
a
)
a
t
j
a
v
a
.
u
t
i
l
.
c
o
n
c
u
r
r
e
n
t
.
T
h
r
e
a
d
P
o
o
l
E
x
e
c
u
t
o
r
.
r
u
n
W
o
r
k
e
r
(
T
h
r
e
a
d
P
o
o
l
E
x
e
c
u
t
o
r
.
j
a
v
a
:
1149
)
a
t
j
a
v
a
.
u
t
i
l
.
c
o
n
c
u
r
r
e
n
t
.
T
h
r
e
a
d
P
o
o
l
E
x
e
c
u
t
o
r
capture(FutureTask.java:266) at java.util.concurrent.FutureTask.run(FutureTask.java) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor
capture(FutureTask.java:266)atjava.util.concurrent.FutureTask.run(FutureTask.java)atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)atjava.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
LocalDateTime LocalDate LocalTime用法一样
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
System.out.println(now.getYear());
System.out.println(now.getMonth());
System.out.println(now.getMonthValue());
//新的时间对象
LocalDateTime localDateTime = now.plusDays(2);
System.out.println(localDateTime);
System.out.println(now.minusMonths(1));
}
Instant、 ZoneId、以及三种时间格式的转化
public static void main(String[] args) {
Instant now = Instant.now();
//咱们地区和格林泥治时间差了8个小时
System.out.println(now.toString());
//比1970-01-01所差时间不差
System.out.println(now.toEpochMilli());
System.out.println(System.currentTimeMillis());
//添加和减少时间
Instant instant = now.plusSeconds(2);
System.out.println(Duration.between(now,instant).getSeconds());
//获取所有时区
Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
for (String availableZoneId : availableZoneIds) {
System.out.println(availableZoneId);
}
//获取当前时区
System.out.println( ZoneId.systemDefault());
//Date--->Instant---->LocalDateTime
System.out.println("Date--->Instant---->LocalDateTime");
Date date = new Date();
System.out.println(date);
Instant instant1 = date.toInstant();
System.out.println(instant1);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault());
System.out.println(localDateTime);
System.out.println("LocalDateTime--->Instant---->Date");
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
Instant instant2 = zonedDateTime.toInstant();
System.out.println(instant2);
Date from = Date.from(instant2);
System.out.println(from);
}
DateTimeFormatter 的使用
public static void main(String[] args) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String format = dateTimeFormatter.format(LocalDate.now());
System.out.println(format);
LocalDate parse = LocalDate.parse("2021-04-18", dateTimeFormatter);
System.out.println(parse);
}
其他新特性:接口中可以包含的组成部分
1.抽象方法
2.常量
3.默认方法(JDK8)
4.静态方法(JDK8)
5.私有方法(JDK9)