手机扫码查看
2020java教程:java8新特性
java8新特性
java8概述
java8简称jdk1.8是java语言开发的一个主要版本。
oracle公司于14年3月18日发布java8
支持Lambda表达式
函数式接口
新的Stream API
新的日期 API
其他特性
Lambda表达式
概述:特殊的匿名内部类,语法更简洁
Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递
import java.util.Comparator;
import java.util.TreeSet;
public class demos{
public static void main(String[] args) {
//匿名内部类
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("子线程执行了");
}
};
//Lambda表达式
Runnable runnable1=()->System.out.println("子线程1执行了");
new Thread(runnable1).start();
new Thread(()->System.out.println("子线程3执行了")).start();
//匿名内部类
Comparator<String> com=new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
};
//Lambda表达式
Comparator<String> com2=(String o1, String o2)-> {
return o1.length()-o2.length();
};
Comparator<String> com3=(o1,o2)->o1.length()-o2.length();
TreeSet<String> treeSet2=new TreeSet<>(com2);
TreeSet<String> treeSet3=new TreeSet<>(com3);
}
}
基本语法:
<函数式接口><变量名>=(参数1,参数2)->{
//方法体
};
Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分
左侧:(参数1,参数2…)表示参数列表
右侧:{}内部是方法体
注意事项:
形参列表的数据类型会自动判断
如果形参列表为空,只需保留()
如果形参只有一个,()可以省略,只需要参数的名称即可
如果执行语句只有一句,且无返回值,{}可以省略,若有返回值,则若想省去{}
则必须同时省略return,且执行语句也保证只有一句
Lambda不会生成一个单独的内部类文件
=============================
函数式接口
如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用
Lambda表达式,Lambda表达式会被匹配到这个抽象方法上。
@FunctionalInterface 注解检测接口是否符合函数式接口。
@FunctionalInterface public interface Usb { void service(); }
常见函数式接口
| 函数式接口 | 参数类型 | 返回类型 | 说明 |
|---|---|---|---|
| Consumer <T>消费型接口 | T | void | void accept(T t);对类型为T 的对象应用操作 |
| Supplier<T>供给型接口 | 无 | T | T get();返回类型为T的对象 |
| Fuction<T,R>函数型接口 | T | R | R apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象 |
| Predicate<T>断言型接口 | T | boolean | boolean test(T t);确定类型为T的对象是否满足条件,并返回Boolean类型 |
//消费型接口
import java.util.function.Consumer;
public class demos{
public static void main(String[] args) {
//匿名内部类
Consumer<Double> con=new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("消费1\t"+aDouble);
}
};
//Lambda表达式
Consumer<Double> con2=t-> System.out.println("消费2\t"+t);
happy(con,1000);
happy(con2,2000);
happy(t-> System.out.println("消费3\t"+t),3000);
}
public static void happy(Consumer<Double> consumer,double money){
consumer.accept(money);
}
}
//运行结果
消费1 1000.0
消费2 2000.0
消费3 3000.0
//供给型函数式接口
import java.util.Arrays;
import java.util.Random;
import java.util.function.Supplier;
public class demos{
public static void main(String[] args) {
//匿名内部类
Supplier<Integer> sup=new Supplier<Integer>() {
@Override
public Integer get() {
return new Random().nextInt(100);
}
};
//Lambda表达式
int[] nums = getNums(() -> new Random().nextInt(100), 5);
System.out.println(Arrays.toString(nums));
System.out.println("====");
int[] nums1 = getNums(sup, 6);
System.out.println(Arrays.toString(nums1));
}
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;
}
}
//结果
[80, 20, 60, 23, 52]
====
[86, 20, 10, 7, 61, 30]
//函数型接口
import java.util.function.Function;
public class demos{
public static void main(String[] args) {
System.out.println(handler(s -> s.toUpperCase(), "hello"));
System.out.println(handler(s ->{return s.toUpperCase();}, "world"));
System.out.println(handler(String::toUpperCase, "helloworld"));
}
public static String handler(Function<String,String> function,String str){
return function.apply(str);
}
}
//结果
HELLO
WORLD
HELLOWORLD
//断言型接口
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class demos{
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("zhangsan");
list.add("zhangwuji");
list.add("lisi");
list.add("lixiaolong");
list.add("wangwu");
List<String> result = find(s -> s.startsWith("zhang"), list);
System.out.println(result.toString());
List<String> result2 = find(s -> s.startsWith("li"), list);
System.out.println(result2.toString());
List<String> result3 = find(s -> s.contains("i"), list);
System.out.println(result3.toString());
List<String> result4 = find(s -> s.contains("a"), list);
System.out.println(result4.toString());
}
public static List<String> find(Predicate<String> predicate,List<String> list){
List<String> result=new ArrayList<>();
for (String s : list) {
if(predicate.test(s)){
result.add(s);
}
}
return result;
}
}
//结果
[zhangsan, zhangwuji]
[lisi, lixiaolong]
[zhangwuji, lisi, lixiaolong]
[zhangsan, zhangwuji, lixiaolong, wangwu]
=============================
方法引用
方法引用是Lambda表达式的一种简写形式。
如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。
常见形式:
对象::实例方法
类::静态方法
类::实例方法
类::new
public static void main(String[] args) {
//对象::实例方法
Consumer<String> con=System.out::println;
con.accept("hello");
//类::静态方法
Comparator<Integer> com=Integer::compare;
//类::实例方法
Function<Character,String> function=Character::getName;
System.out.println(function.apply('a'));
//类::new
Supplier<Student> sup=Student::new;
System.out.println(sup.get());
}
=============================
stream API
什么是stream?
流(stream)中保存对集合或数组数据的操作。和集合类似,但集合中保存的是数据。
stream特点:
stream自己不会存储元素。
stream不会改变元源对象。相反,他们会返回一个持有结果的新Stream
stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream使用步骤
创建:创建一个流
中间操作:在一个或多个步骤中,将初始stream转化到另一个stream的中间操作
终止操作:使用一个终止操作来产生一个结果。该操作会强制它之前的延迟操作立即执行。在这之后,该stream就不能使用了。
创建stream
1.通过Collection对象的stream()或paralleleStream()
List<String> list=new ArrayList<>();
list.add("huawei");
list.add("apple");
list.add("oppo");
list.add("vivo");
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
System.out.println("===");
Stream<String> stream2 = list.parallelStream();
stream2.forEach(System.out::println);
2.通过Arrays类的stream()方法
String[] s={"apple","banner","orange"};
Stream<String> stream = Arrays.stream(s);
stream.forEach(System.out::println);
3.通过Stream接口的of()、iterate()、generate()方法
Stream<Integer> stream = Stream.of(10, 20, 30);
stream.forEach(System.out::println);
System.out.println("==迭代流==");
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(5).forEach(System.out::println);
System.out.println("==生成流==");
Stream<Integer> generate = Stream.generate(() -> new Random().nextInt(999));
generate.limit(5).forEach(System.out::println);
4.通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法
IntStream stream=null;
stream=IntStream.of(10,20,30);
stream.forEach(System.out::println);
System.out.println("====");
stream=IntStream.range(0,50);//0~49
stream.forEach(System.out::println);
System.out.println("====");
stream=IntStream.rangeClosed(0,50);//0~50
stream.forEach(System.out::println);
中间操作、终止操作
中间操作
filter过滤、limit限制、skip跳过、distinct去重、sorted排序
public static void main(String[] args) {
List<Emp> list=new ArrayList<>();
list.add(new Emp("张三",15000));
list.add(new Emp("李四",17000));
list.add(new Emp("赵柳",5000));
list.add(new Emp("李三",8000));
list.add(new Emp("李三",8000));
//filter过滤
System.out.println("----filter过滤工资小于5000的----");
list.stream().filter(e->e.getBalance()>5000).forEach(System.out::println);
//limit限制
System.out.println("----limit限制,只显示3条数据----");
list.stream().limit(3).forEach(System.out::println);
//skip跳过
System.out.println("----skip跳过,跳过头两条数据----");
list.stream().skip(2).forEach(System.out::println);
//distinct去重,需重写hashcode和equals方法
System.out.println("---distinct去重---");
list.stream().distinct().forEach(System.out::println);
//sorted排序
System.out.println("---sorted排序---");
list.stream()
.sorted((e1,e2)->Double.compare(e1.getBalance(),e2.getBalance()))
.forEach(System.out::println);
}
map映射
list.stream().map(Emp::getName).forEach(System.out::println);
parallel并行流
//parallel调用toString()方法,采用多线程,效率快 list.stream().parallel().forEach(System.out::println);
并行流和串行流的区别
List<String> list=new ArrayList<>();
for(int i=0;i<5000000;i++){
list.add(UUID.randomUUID().toString());
}
System.out.println("添加完毕");
long s=System.currentTimeMillis();
//串行流,单线程,用时14秒
long count = list.stream().sorted().count();
//并行流,多线程,用时0.2秒
long count2 = list.stream().parallel().count();
System.out.println(count);
long e=System.currentTimeMillis();
System.out.println("用时"+(e-s));
终止操作
forEach遍历、min求最小值、max求最大值、count获取元素个数
//forEach遍历
list.stream().filter(t->t.getSalary()>5000)
.forEach(System.out::println);
//min
System.out.println("获取工资最低的数据");
Optional<Emp> min = list.stream()
.min((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
System.out.println(min.get());
//max
System.out.println("获取工资最高的数据");
Optional<Emp> max = list.stream()
.max((t1, t2) -> Double.compare(t1.getSalary(), t2.getSalary()));
System.out.println(max.get());
//count
System.out.println("获取元素个数");
System.out.println("数据有"+list.stream().count()+"条");
reduce规约求和、collect收集
//reduce规约
System.out.println("计算总工资");
Optional<Double> sum = list.stream().map(Emp::getSalary).reduce(Double::sum);
System.out.println("总工资为:"+sum.get());
//collect收集
System.out.println("collect收集");
List<String> name = list.stream().map(Emp::getName).collect(Collectors.toList());
for (String s : name) {
System.out.println(s);
}
=============================
新时间API
之前时间API存在问题,线程安全问题,设计混乱
解决方案
public static void main(String[] args)throws Exception {
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyyMMdd");
ExecutorService ex = Executors.newFixedThreadPool(10);
Callable<LocalDate> callable=()->LocalDate.parse("20201007",dtf);
List<Future<LocalDate>> list=new ArrayList<>();
for(int i=0;i<10;i++){
Future<LocalDate> future = ex.submit(callable);
list.add(future);
}
for (Future<LocalDate> f : list) {
System.out.println(f.get());
}
ex.shutdown();
}
本地化时间API
LocalDate、LocalTime、LocalDateTime
public static void main(String[] args) {
//获取本地时间
LocalDateTime ldt=LocalDateTime.now();
System.out.println("获取年份:"+ldt.getYear());
System.out.println("获取月份:"+ldt.getMonthValue());
System.out.println("获取日期:"+ldt.getDayOfMonth());
System.out.println("获取星期:"+ldt.getDayOfWeek());
//修改时间 plus增加 min减少
System.out.println("穿越到明早工作时间");
System.out.println(ldt.plusHours(17));
System.out.println("回到十年前");
System.out.println(ldt.minusYears(10));
}
Instant时间戳、ZoneId时区
public static void main(String[] args) {
//Instant时间戳
Instant instant=Instant.now();
System.out.println(instant.toString());
System.out.println(instant.toEpochMilli());
System.out.println(System.currentTimeMillis());
//添加减少时间
Instant instant2=instant.plusSeconds(10);
System.out.println(Duration.between(instant,instant2).toMillis());
Instant instant3=instant.minusSeconds(10);
System.out.println(Duration.between(instant,instant3).toMillis());
//ZoneId时区
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String str : zoneIds) {
System.out.println(str);
}
System.out.println("当前时区:"+ZoneId.systemDefault().toString());
}
Date、Instant、LocalDateTime的转换
DateTimeFormatter:格式化类
public static void main(String[] args) {
//DateTimeFormatter
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//把时间格式化成字符串
System.out.println(dtf.format(LocalDateTime.now()));
//把字符串解析成时间
LocalDateTime localDateTime=LocalDateTime.parse("2020-10-07 18:00:47",dtf);
System.out.println(localDateTime);
}
java8总结
Lambda表达式:允许把函数作为一个方法的参数传递。
函数式接口:
Consumer、Supplier、Function、predicte
StreamAPI
把对数据的操作封装成一个流
步骤:创建流、中间操作、终止操作
新时间API



发表回复