当前位置: 首页 > 科技观察

JAVA8新特性实用总结JAVA8新特性实用总结

时间:2023-03-16 14:42:49 科技观察

JAVA8新特性实用总结从两年前到现在已有的JDK版本的迭代,迅速发展到JDK15,我真的感觉有点不动,更新速度也太快了,不过比起现有的系统和国内的趋势。大多数公司仍然使用最基本的1.8作为在线环境。没有问题,但是我们真的会用JAVA8吗?https://www.oracle.com/java/technologies/java-se-glance.html新特性概述本总结主要从Lambda表达式入手,由浅入深,按实用性排序,逐步讲解带来的新特性为了开发人的幸福,如何更好的简化代码,优化可读性。这是我们研究的目的,也是本节的总结。你会使用遍历循环吗?从最基本的循环说起,循环无非就是我们刚开始学习的时候需要接触到的for最基本的循环结构,也是后面工作中会大量用到的结构。如何更好地简化它?//创建测试集合Listlist=Arrays.asList(1,2,2,3,4,5,5,6);//基本循环System.out.println("---------------------------1基本循环");for(inti=0;iSystem.out.println(item));//使用lambda方法引用System.out.println("---------------------------4lambda");list.forEach(System.out::println);//下面是编译语法糖代码Iteratorvar4=list.iterator();while(var4.hasNext()){Integeri=(Integer)var4.next();System.out.println(i);}从上面的代码我们可以看出,随着lambda方法的引入,代码变得越来越精简,更容易阅读和理解,要写的东西也越来越少。第一种方法是我们常规的操作方法,一般适用于需要下标逻辑的。在业务。二是迭代器语法糖,方便开发者编写,但是对于代码编译来说,编译出来的代码仍然是迭代器,只是语法简单。Lambda是一个函数表达式。该项目用作我们循环的参数,我们需要执行的代码块在箭头后面。一句代码不需要使用{}lambda方法引用是一种全新的方式。引用二个词是我们经常用到的,一般在对象引用中都有表达意义。简而言之,一个值可以从一个地方引用和使用,但是现在,一个方法可以看作是一个值,也可以随意取用。在使用~forEach的时候,小伙伴们可能会有疑惑。为什么lambda表达式可以用在forEach中,为什么不能用在其他地方呢?我们看一下源码defaultvoidforEach(Consumeraction){Objects.requireNonNull(action);for(Tt:this){action.accept(t);}}我们发现Consumer是一个接口,而for语法在Sugar内部仍然使用形式来执行集合,调用accept方法。Consumer消费者接口,适用于入参处理,无返回值@FunctionalInterfacepublicinterfaceConsumer{voidaccept(Tt);发现这个接口和其他接口唯一的区别就是@FunctionalInterface,其实这个注解就是告诉编译器,这个接口下的accept方法可以用函数式的写法来描述。有了这个注解的定义,我们就可以愉快的使用函数式lambda表达式了。消费者接口作为JDK自带的函数式接口,在java.util.function包下,支持链式操作。它接受指定的通用类型。内部处理后,没有返回值//没有返回处理Consumercustom=(str)->System.out.println("first"+str);消费者desc=custom.andThen((str)->System.out.println("second"+str));desc.accept("hello");--------------------------firsthellosecondhello简单总结一下lambda的基本语法:(parameter)->Onelineofexecutioncode(parameter)->{Multiplelinesofexecutioncode}单个参数可以完全省略参数的括号。default默认实现,子类不需要重写接口定义的关键字。在上面Consumer的使用中,我们发现有一个默认实现的接口。顺便解释一下defaultConsumerandThen(Consumerafter){Objects.requireNonNull(after);return(Tt)->{accept(t);after.accept(t);};}default提供了一个默认的实现方法,实现类不需要重写这个方法的定义,但是可以直接使用。方法引用使用方法作为引用作为值。//使用lambda方法引用System.out.println("------------------------4lambda");list.forEach(System.输出::println);博主这里的理解是,被引用的方法需要和定义要求的lambda表达式有相同的入参个数和返回类型:defaultvoidforEach(Consumeraction),才可以被引用。例如:Consumer接口接受的lambda形式是:item->System.out.println(item)而我们引用的System.out::println就是这个形式。publicvoidprintln(Objectx){Strings=String.valueOf(x);synchronized(this){print(s);newLine();}}void的优雅判断我们都知道JAVA中最讨厌的异常就是NPE=NullPointerExceptionnull指针异常,为了避免空指针异常,我们经常使用if作为判断,如果这样的判断过多,很容易让人看的烦。例如下面的代码:Personperson=newPerson("test",1);if(person!=null){if(person.getName()!=null){System.out.println("123"+person.getName());}else{//dosomething}}else{//dosomething}假设我们有一个person对象,首先判断它是否为空,如果不为空,则获取值,然后获取namemember变量,如果不为空,则拼接打印。这种二级判断的逻辑在代码中经常看到。学习了Optional之后,我们上面的逻辑可以修改为://最佳实践Optional.ofNullable(person).map(p->p.getName()).map(string->string.concat("123")).ifPresent(System.out::println);函数输入参数,返回指定类型,可以理解为转换。首先发现map接受一个Functionmapper,如何使用Function@FunctionalInterfacepublicinterfaceFunction{Rapply(Tt);//链式转换FunctionstringToInteger=Integer::valueOf;//然后使用前面处理的返回值作为下一步处理的输入参数FunctionintegerToString=stringToInteger.andThen(Integer::toHexString);Stringhex=integerToString.apply("123");System.out.println(hex);//7bOptional优雅判断为空,并执行相应的操作。Optional对NPE有很好的解决方案,可以解决我们对多个if的优化。它不仅美丽,而且非常优雅。//如果person为null,则触发异常Optional.of(person);//如果person1为null,则返回emptyOptional.ofNullable(person1);以上是创建实例的两种方式,一般使用第二种,第一种如果为null的情况下,会触发NPE。最后还是没有处理这个异常,所以不推荐使用。privateOptional(){this.value=null;}isPresent():如果不为空则返回真。get():获取当前包含的值,如果value=null则抛出NPE,然后执行消费者,否则返回EMPTYStreamstream作为JAVA8的核心内容,全面掌握其精髓,对于开发者来说,无非就是打开新世界大门的钥匙。从宏观上看,一门语言处理最多的就是数据的集合,比如Listfilter过滤器,就是过滤出你想要的集合元素。Listlist=Arrays.asList(1,2,3,3,4,5,5,6);//过滤偶数longnum=list.stream().filter(item->item%2==0).count();//3通过简单筛选,筛选条件为偶数,最后统计其个数。这里的filter接受一个filter(Predicatepredicate)count,简而言之,就是统计前面的表达式生成的新集合的个数。谓词断言也是一个可以使用lambda表达式的函数式接口。@FunctionalInterfacepublicinterfacePredicate{booleantest(Tt);Predicate主要实现了它的测试接口,通过逻辑执行返回一个boolean来判断当前元素是否可用。//断言字符串长度大于0PredicatestringEmpty=(str)->str.length()>0;PredicatestartHello=(str)->str.startsWith("hello");系统输出。println("testemptycharacter="+stringEmpty.test(""));System.out.println("testhello="+stringEmpty.test("hello"));//合并两个测试界面,满足你可以或者只要有一个满足即可(startHello).test("world"));--------------------testnullcharacter=falsetesthello=truetestandhelloworld=truetestorworld=truemapmap可以理解为映射,处理每个元素,并返回任何类型。支持链式映射,将上层映射的返回值作为下层映射的参数值。Listpeople=Arrays.asList(newPerson("hello",1),newPerson("world",2));//将每个元素的名字组装成一个新的集合。Listnames=people.stream().map(item->item.getName()).collect(Collectors.toList());System.out.println(names);//多图处理Listconcat=people.stream().map(item->item.getName()).map(name->name.concat("-concat")).collect(Collectors.toList());System.out.println(concat);--------------------[hello,world][hello-concat,world-concat]map接受一个map(Functionmapper)我们已经在上面讨论过了。sorted对元素进行排序,可以使用默认的或者自定义的排序规则。ListsortedList=Arrays.asList("acc","dee","zdd","wee","abb","ccd");//默认排序,字典顺序,首字母相同,然后比较第二个Listsorted=sortedList.stream().sorted().collect(Collectors.toList());System.out.println(sorted);//自定义实现,只比较第一个字符Listsorted2=sortedList.stream().sorted((str1,str2)->str1.charAt(1)-str2.charAt(1)).collect(Collectors.toList());System.out.println(sorted2);-------------------------[abb,acc,ccd,dee,wee,zdd]//可以找到自定义的排序吗不比较第二个字母[acc,abb,ccd,dee,wee,zdd]我们发现sorted接受一个ComparatorcomparatorComparator比较器也是一个函数式接口,不用多说了,自然可以用lambda@FunctionalInterfacepublicinterfaceComparator{intcompare(To1,To2);Comparatorcomparator=(str1,str2)->str1.charAt(0)-str2.charAt(0);//自定义比较首字母inta=comparator.compare("abb","acc");System.out.println(a);//再比较,如果第一个返回0,直接返回结果,否则进行二次比较intb=comparator.thenComparing((str1,str2)->str1.charAt(1)-str2.charAt(1)).compare("abb","acc");System.out.println(b);------------------------------0-1比较器返回一个int值,这个int表示两个元素的排列顺序,根据ASCII表表示的值,如果两个元素如果a-b之差>0,则a在前,b在后。allMatch/anyMatch同理,Match用于处理当前序列的全部或部分,返回一个布尔值ListsortedList=Arrays.asList("acc","dee","zdd","wee","abb","ccd");//所有元素都通过断言,返回true,否则返回falsebooleanstartWithA=sortedList.stream().allMatch(str->str.startsWith("a"));System.out.println(startWithA);//只要满足一个就返回truebooleanhasA=sortedList.stream().anyMatch(str->str.startsWith("a"));System.out.println(hasA);------------------------falsetrue以上是流常用的一些总结,总结了一些很常用的,暂未总结的内容将在下一期补充。在这里,我会提到局部变量的最终语义。自定义功能接口模仿上述任何功能接口。我们可以写这样一个转换接口,将指定类型转换为指定类型@FunctionalInterfacepublicinterfaceFunctionInterface{Rcover(At);}通过自定义函数接口,我们可以写如下代码来进行转换,但是涉及到一些参数变化。//如果在lambda中使用num局部变量,它隐式包含最终语义finalintnum=1;FunctionInterfacefunction4=(val)->Integer.valueOf(val+num);Integerresult4=function4.cover("12");//num=2;//这个不能改,修改不能编译