Java16都快上线了,你该不会连Java8的特性都不会用吧?

简介: 2020年,Java16有了新的消息,预计将在2021年的3月16日正式发布。但是这一消息对于百分之九十的国内程序员来说都只是一个新闻而已,因为国内的绝大部分公司依然使用着Java8。这款发布于2014年的JDK版本深受各大公司的喜爱,最大的原因取决于它的稳定性。即使如此,依然有一半以上的程序员对于Java8的特性不了解,于是我用一个周末的时间把JDK8的”新“特性肝了一遍,希望对大家有所帮助。

听说微信搜索《Java鱼仔》会变更强哦!


本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看哦


(一)前言


2020年,Java16有了新的消息,预计将在2021年的3月16日正式发布。但是这一消息对于百分之九十的国内程序员来说都只是一个新闻而已,因为国内的绝大部分公司依然使用着Java8。这款发布于2014年的JDK版本深受各大公司的喜爱,最大的原因取决于它的稳定性。


即使如此,依然有一半以上的程序员对于Java8的特性不了解,于是我用一个周末的时间把JDK8的”新“特性肝了一遍,希望对大家有所帮助。


(二)Lambda表达式


Lambda是一个匿名函数,它允许你通过表达式来代替功能接口,使用lambda可以让代码变得更加简洁。简单来讲,lambda使用更简洁的方式给接口添加实现方法。


Lambda只能在函数式接口中使用,函数式接口就是那些只有一个抽象方法的接口,可以用注解@FunctionalInterface修饰,如果一个接口中有多个方法,就不能再使用Lambda了。


我们常用的Runnable、Comparator都是函数式接口:


网络异常,图片无法展示
|

网络异常,图片无法展示
|


lambda的语法格式如下:



(parameters) ->expression(parameters) ->{ statements; }

2.1 无参数、无返回值


lambda实现的是对功能接口代码的简洁化,比如下面这一段:


Runnablerunnable=newRunnable() {
@Overridepublicvoidrun() {
System.out.println("run");
    }
};

我们在创建一个Runnable对象的时候需要通过匿名内部类实现接口中定义的方法,而使用lambda表达式,上面的代码一行就可以搞定:


Runnablerunnable2= () ->System.out.println("run");

2.2 有参数,无返回值


我们先写一个这样的接口:


publicinterfaceStudent {
publicvoidgetAge(intage);
}

在以前的代码中,我们需要首先写一个类去继承这个接口,或者是写一个匿名内部类,如:


Studentstudent=newStudent() {
@OverridepublicvoidgetAge(intage) {
System.out.println(age);
    }
};

现在就变得简单了:


Studentstudent2=(age) -> { System.out.println(age); };

如果只有一个参数,小括号可以不写:


Studentstudent3=age-> { System.out.println(age); };

2.3 有参数,有返回值


写一个接口:


publicinterfaceStudent {
publicintgetAge(intage);
}

直接写lambda表达式了:


Studentstudent5=age-> { returnage; };
System.out.println(student5.getAge(1));

(三)内置函数式接口


在前面已经介绍了什么是函数式接口,函数式接口就是那些只有一个抽象方法的接口,Java8中内置了四种函数式接口:


Consumer<T> : voidaccept(Tt);
Supplier<T> : Tget();
Function<T,R> : Rapply(Tt);
Predicate<T> : booleantest(Tt)

这四种接口和我们平常写的没有什么区别,可以在Java8中直接调用:


3.1 Consumer


消费型接口,提供了一个参数、无返回值的接口方法,就和消费一样,花出去就没有了。


publicstaticvoidmain(String[] args) {
consume(100,money-> {
System.out.println("消费了"+money+"元");
    });
}
publicstaticvoidconsume(doublemoney, Consumer<Double>consumer){
consumer.accept(money);
}

3.2 Supplier


供给型接口,提供了无参数,有返回值的接口方法,主要起到供给数据的作用,比如实现一个生成随机数的功能:


publicstaticvoidmain(String[] args) {
System.out.println(getRandomNum(()->(int)(Math.random()*100)));
}
publicstaticintgetRandomNum(Supplier<Integer>supplier){
returnsupplier.get();
}

3.3 Function


函数型接口,提供带参数和返回值的接口方法,可用来对数据进行处理后再返回,比如实现一个替换字符串给功能:


publicstaticvoidmain(String[] args) {
//去掉前后空格System.out.println(handlerString("\t\tJava鱼仔\t\t",(str)->str.trim()));
}
publicstaticStringhandlerString(Stringstring, Function<String,String>function){
returnfunction.apply(string);
}

3.4 Predicate


断言型接口,提供带参数和返回值的接口方法,只不过返回值是boolean类型,可用于进行判断,比如实现一个判断某个字符串是否是整数的需求


publicstaticvoidmain(String[] args) {
Patternpattern=Pattern.compile("^[-\\+]?[\\d]*$");
if (isDigit("111",s-> {
returnpattern.matcher(s).matches();
     })){
System.out.println("is Digit");
     }
}
publicstaticStringhandlerString(Stringstring, Function<String,String>function){
returnfunction.apply(string);
}

(四)Stream API


Java8中两个最重大的改变,一个是Lambda表达式,另外一个就是Stream API


Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。


使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。也可以使用Stream API来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。


Stream的执行过程分为三步


1、创建stream


2、操作stream(查找、筛选、过滤等等)


3、执行stream


stream的操作属于惰性求值,即所有的操作是在执行stream时一次性执行。


4.1 创建stream


创建流的方式有四种,这里直接把创建方式的注释写进代码里


publicstaticvoidmain(String[] args) {
//创建Stream//1、通过Collection系列集合提供的stream()或parallelStream()List<String>list=newArrayList<>();
Stream<String>stream=list.stream();
//2、通过Arrays中的静态方法stream()获取Integer[] integers=newInteger[10];
Stream<Integer>stream1=Arrays.stream(integers);
//3、通过Stream类中的静态方法of()Stream<Integer>stream2=Stream.of(integers);
//4、迭代创建Stream<Integer>stream3=Stream.iterate(0, (x) ->x+2);
}

4.2 操作stream


stream有多种操作集合的方法,下面一一进行讲解:


为了更方便的演示,新建一个实体类User:


publicclassUser {
privateStringname;
privateintage;
privateStringsex;
//这里省略构造方法、get、set、toString方法}

filter过滤--通过某种条件过滤元素:


filter通过Predicate接口过滤元素,下面这段代码将年龄超过30岁的过滤出来


publicstaticvoidmain(String[] args) {
List<User>list=Arrays.asList(
newUser("javayz",23,"male"),
newUser("张三",25,"male"),
newUser("李四",30,"female"),
newUser("王五",33,"female")
newUser("王五",33,"female")
    );
//过滤出年龄大于30岁的人Stream<User>userStream=list.stream().filter((e) ->e.getAge() >=30);
userStream.forEach((e)->System.out.println(e));
}

limit截断--使元素不超过给定的数量


//对取出来的数据只展示一条Stream<User>userStream=list.stream()
        .filter((e) ->e.getAge() >=30)
        .limit(1);
userStream.forEach((e)->System.out.println(e));

skip--跳过集合中的前n个数


可以和limit联合使用取出指定的范围的数


Stream<User>userStream=list.stream().skip(2);

distinct--去重,通过元素的hashcode()和equals()去除重复元素


去重是根据hashcode()和equals()方法判断重复元素的,因此实体类了需要重写hashcode()和equals()方法


Stream<User>userStream=list.stream().distinct();


map--通过Function接口对stream中的每个数据处理后返回新的数据


比如我想把所有的英文改为大写,就可以这样


List<String>list1=Arrays.asList("aa","bb","cc");
Stream<String>stringStream=list1.stream().map((str) ->str.toUpperCase());
stringStream.forEach((e)->System.out.println(e));


flatmap--通过Function接口把stream的每一个值都换成另外个stream,最后再把所有stream连接成一个stream


这个方法的使用可能会比较难懂,通过一个例子,把包含三个字符串的集合中的每个字符串都分成一个个字符提取出来。比如把一个集合{"aa","bb","cc"}变成{'a','a','b','b','c','c'},使用map就需要这样:


List<String>list1=Arrays.asList("aa","bb","cc");
Stream<Stream<Character>>streamStream=list1.stream().map((str) -> {
List<Character>characters=newArrayList<>();
for (Characterch : str.toCharArray()) {
characters.add(ch);
    }
returncharacters.stream();
});
streamStream.forEach((stream)->{
stream.forEach((character->System.out.println(character)));
});


它第一个stream的返回值是stream中套一个字符流,输出的时候也需要先遍历最外层的stream再遍历内层的stream,比较麻烦,于是就可以使用flatmap,他会把多个stream合并为一个。


Stream<Character>characterStream=list1.stream().flatMap((str) -> {
List<Character>characters=newArrayList<>();
for (Characterch : str.toCharArray()) {
characters.add(ch);
    }
returncharacters.stream();
});
characterStream.forEach((e)->System.out.println(e));

sorted--自然排序,按照Comparable方式排序


Stream<String>stringStream=list.stream().sorted();

sorted(Comparator comparator)--定制排序,自己写一个Comparator 实现排序


List<User>list=Arrays.asList(
newUser("javayz",23,"male"),
newUser("张三",25,"male"),
newUser("李四",30,"female"),
newUser("王五",33,"female")
);
Stream<User>sorted=list.stream().sorted((e1, e2) -> {
returne1.getAge() ==e2.getAge() ?0 : e1.getAge() >e2.getAge() ?1 : -1;
});
sorted.forEach((e)->System.out.println(e));

4.3 执行stream


如果只是操作stream,流的数据是不会变化的,接下来介绍执行stream的一系列方法,首先把接下来会用的数据创建进来:


List<User>list=Arrays.asList(
newUser("javayz",23,"male"),
newUser("张三",25,"male"),
newUser("李四",30,"female"),
newUser("王五",33,"female")
);

allMatch--检查是否匹配所有元素


//判断所有的元素的sex是否都是male,这里返回falsebooleanmale=list.stream().allMatch((e) ->e.getSex().equals("male"));
System.out.println(male);

anyMatch--检查是否至少匹配一个元素


booleanmale=list.stream().anyMatch((e) ->e.getSex().equals("male"));
System.out.println(male);//这里返回true

noneMatch--检查是不是没有元素能够匹配指定的规则


booleanmale=list.stream().noneMatch((e) ->e.getSex().equals("male"));
System.out.println(male);//这里返回false

findFirst--返回第一个元素


Optional<User>first=list.stream().findFirst();
System.out.println(first.get());

count--返回当前流中的元素总个数


longcount=list.stream().count();
System.out.println(count);

max--返回当前流中的最大值


返回最大值和最小值依旧需要实现comparator接口方法


Optional<User>max=list.stream().max((e1, e2) -> {
returnInteger.compare(e1.getAge(), e2.getAge());
});
System.out.println(max.get());

min--返回当前流中的最小值


Optional<User>max=list.stream().min((e1, e2) -> {
returnInteger.compare(e1.getAge(), e2.getAge());
});
System.out.println(max.get());

reduce--规约,将流中的元素反复结合起来,得到一个值


List<Integer>list=Arrays.asList(1,2,3,4,5,6,7,8,9);
//从第0个元素开始,对list求和Integerreduce=list.stream().reduce(0, (x, y) ->x+y);
System.out.println(reduce);

collection--收集,将流中的数据接收成其他的形式


比如我们把上面User数据的名字收集到List数组中:


List<String>collect=list.stream().map((e) ->e.getName()).collect(Collectors.toList());
System.out.println(collect);

Collectors提供了大量的转化为其他方式的实现,这里不做过多介绍。


(五)接口中的默认方法和静态方法


在1.8之前,接口中的方法只能声明无法实现,在Java8中,接口中可以添加默认方法和静态方法了。


首先介绍默认方法,通过default修饰的方法可以在接口中增加实现。



publicinterfaceMyInterface {
defaultvoiddefaultMethod(){
System.out.println("hello");
    }
}

另外是接口中的静态方法:


publicinterfaceMyInterface {
publicstaticvoidstaticMethod(){
System.out.println("hello");
    }
}

(六)新时间日期API


JAVA8中增加了新的时间日期API,通过代码来混个眼熟:


6.1 LocalDate、LocalTime、LocalDateTime


@Testpublicvoidtest1(){
//获取当前时间LocalDateTimelocalDateTime=LocalDateTime.now();
System.out.println(localDateTime);
//增加两年System.out.println(localDateTime.plusYears(2));
//减少两年System.out.println(localDateTime.minusYears(2));
//获取年、月、日、小时、分钟、秒System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getHour());
System.out.println(localDateTime.getMinute());
System.out.println(localDateTime.getSecond());
}

6.2 Instant :时间戳


@Testpublicvoidtest2(){
Instantinstant=Instant.now();
//获取当前时间戳System.out.println(instant.toEpochMilli());
}

6.3 Duration :计算两个时间间隔


@Testpublicvoidtest3(){
Instantinstant1=Instant.now();
try {
Thread.sleep(1000);
    } catch (InterruptedExceptione) {
e.printStackTrace();
    }
Instantinstant2=Instant.now();
Durationbetween=Duration.between(instant1, instant2);
//计算出两个日期相差的毫秒、分钟、小时等数据System.out.println(between.toMillis());
System.out.println(between.toMinutes());
System.out.println(between.toHours());
}

6.4 Period:计算两个日期间隔


@Testpublicvoidtest4(){
LocalDatelocalDate1=LocalDate.of(2020,11,1);
LocalDatelocalDate2=LocalDate.now();
Periodbetween=Period.between(localDate1, localDate2);
//计算相差几年几个月零几天System.out.println(between.getYears());
System.out.println(between.getMonths());
System.out.println(between.getDays());
}

6.5 TemporalAdjuster:时间矫正器


TemporalAdjuster用于对时间进行操作,我们可以通过TemporalAdjusters这个类调用大量对时间操作的方法,比如下个周日等等。


@Testpublicvoidtest5(){
LocalDateTimelocalDateTime=LocalDateTime.now();
LocalDateTimewith=localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(with);
}

6.6 格式化时间


时间格式化类在JAVA8之前用的最多的就是SimpleDateFormat,现在多了一个叫做DateTimeFormatter的格式化类:


@Testpublicvoidtest6(){
DateTimeFormatterdtf=DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDateTimelocalDateTime=LocalDateTime.now();
System.out.println(localDateTime.format(dtf));
}

(七)总结


总的来讲,Java8的新东西还是有很多的,虽然现在很多程序员都不习惯使用新的语法,但对这些新语法也不要抗拒,毕竟现在最新的Java版本已经到16了呢!

相关文章
|
5月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
64 3
|
5月前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
109 2
|
5月前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
59 2
|
17天前
|
人工智能 Java 程序员
【AI程序员】通义灵码 AI 程序员全面上线JAVA使用体验
通过 AI 程序编写一个JAVA后台项目登陆页面
328 17
|
3月前
|
存储 Java 开发者
什么是java的Compact Strings特性,什么情况下使用
Java 9引入了紧凑字符串特性,优化了字符串的内存使用。它通过将字符串从UTF-16字符数组改为字节数组存储,根据内容选择更节省内存的编码方式,通常能节省10%至15%的内存。
|
3月前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
112 6
|
4月前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
52 4
|
5月前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
179 3
|
5月前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
45 2
|
5月前
|
Java 开发者
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素
在Java集合世界中,Set以其独特的特性脱颖而出,专门应对重复元素。通过哈希表和红黑树两种模式,Set能够高效地识别并拒绝重复元素的入侵,确保集合的纯净。无论是HashSet还是TreeSet,都能在不同的场景下发挥出色的表现,成为开发者手中的利器。
44 2

热门文章

最新文章