Java8常用的新特性詳解
一、Java 8 新特性的簡(jiǎn)介
- 速度更快
- 代碼更少(增加了新的語(yǔ)法:Lambda表達(dá)式)強(qiáng)大的Stream API
- 便于并行
- 最大化減少空指針異常:Optional
- Nashorn引擎,允許在JVM上運(yùn)行JS應(yīng)用
二、Lambda表達(dá)式
Lambda表達(dá)式:特殊的匿名內(nèi)部類,語(yǔ)法更簡(jiǎn)潔。
Lanbda表達(dá)式允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為方法參數(shù)傳遞),將代碼像數(shù)據(jù)一樣傳遞。
基本語(yǔ)法:
<函數(shù)式接口> <變量名> = (參數(shù)1,參數(shù)2...) ->{ //方法體 }
Lambda引入了新的操作符:->(箭頭操作符),->將表達(dá)式分成兩部分
- 左側(cè):(參數(shù)1,參數(shù)2…)表示參數(shù)列表。
- 右側(cè):{}內(nèi)部是方法體
Lambda需要注意的事項(xiàng):
- 形參列表的數(shù)據(jù)類型會(huì)自動(dòng)推斷
- 如果形參列表為空,只需保留()
- 如果形參只有1個(gè),()可以省略,只需要參數(shù)的名稱即可
- 如果執(zhí)行語(yǔ)句只有一句,且無(wú)返回值,{}可以省略,若有返回值,則若想省去{},則必須同時(shí)省略return,且執(zhí)行語(yǔ)句也保證只有一句
- Lambda不會(huì)生成一個(gè)單獨(dú)的內(nèi)部類文件
2.1 lambda代碼說(shuō)明
語(yǔ)法格式一:
lambda 無(wú)參,無(wú)返回值
//如何使用lambda表達(dá)式 public class Demo1 { public static void main(String[] args) { //線程//匿名實(shí)現(xiàn)類對(duì)象---以前的寫法 // Runnable runnable=new Runnable() { // @Override // public void run() { // System.out.println("hello world!"); // } // }; //lambda表達(dá)式寫法 Runnable runnable1= ()->System.out.println("hello world!"); new Thread(runnable1).start(); //更簡(jiǎn)單的寫法 new Thread(()->System.out.println("hello world!")).start(); } }
語(yǔ)法格式二:
lambda 有一個(gè)參,無(wú)返回值
@Test public void test02(){ Consumer<String> con = new Consumer<String>() { @Override public void accept(String s){ System.out.println(s); } }; con.accept("hello world!"); System.out.println("*********************"); //Lambda表達(dá)式 Consumer<String> con1 = (String str)-> System.out.println(str); con1.accept("hello world"); }
語(yǔ)法格式三:
數(shù)據(jù)類型可以省略,因?yàn)榭捎删幾g器推斷得出,稱為“類型推斷”
@Test public void test03(){ Consumer<String> con1 = (str) -> System.out.println(str); con1.accept("hello world"); }
三、函數(shù)式接口
如果一個(gè)接口只有一個(gè)抽象方法,則該接口稱之為函數(shù)式接口,函數(shù)式接口可以使用Lambda表達(dá)式,Lambda表達(dá)式會(huì)被匹配到這個(gè)抽象方法上。
@FunctionalInterface注解檢測(cè)接口是否符合函數(shù)式接口
public class Demo1 { public static void main(String[] args) { USB usb = new USB() { @Override public void show() { System.out.println("我是函數(shù)式接口"); } }; USB usb1=()-> System.out.println("你好"); info(()-> System.out.println("你好嘿嘿嘿")); } public static void info(USB usb){ usb.show(); } } //函數(shù)式接口 interface USB{ public void show(); }
lambda新增了四個(gè)重要的函數(shù)式接口:
- 函數(shù)形接口
- 供給形接口
- 消費(fèi)型接口
- 判斷型接口
函數(shù)式接口說(shuō)明
public class Demo2 { public static void main(String[] args) { // Consumer<Double> consumer=t-> System.out.println("吃飯消費(fèi)掉:"+t); // Consumer<Double> consumer=new Consumer<Double>() { // @Override // public void accept(Double aDouble) { // System.out.println("你消費(fèi)得金額:"+aDouble); // } // }; Consumer<Double> consumer1=t ->System.out.println("吃飯消費(fèi)掉:"+t); Consumer<Double> consumer2=t ->System.out.println("唱歌消費(fèi)掉:"+t); Consumer<Double> consumer3=t ->System.out.println("洗腳消費(fèi)掉:"+t); hobby(consumer1,1000); hobby(consumer2,2000); hobby(consumer3,4000); Supplier<Integer> supplier=new Supplier<Integer>() { @Override public Integer get() { return new Random().nextInt(10); } }; Supplier<Integer> supplier1=()->new Random().nextInt(10); int[] arr = getArr(supplier1, 5); System.out.println(Arrays.toString(arr)); System.out.println("~~~~~~~~~~~~~~~function~~~~~~~~~~~~~~~~~~~~~~~"); // Function<String,String> function1=new Function<String, String>() { // @Override // public String apply(String s) { // return s.toUpperCase(); // } // }; // Function<String,String> function=s->s.toUpperCase(); // System.out.println(toUpper(function, "hello")); List<String> list=new ArrayList<>(); list.add("zhangsan"); list.add("lisi"); list.add("wangwu"); list.add("zhaoliu"); list.add("tianqi"); // Predicate<String> predicate=new Predicate<String>() { // @Override // public boolean test(String s) { // return s.length()>5; // } // }; Predicate<String> predicate1=s->s.length()>5; List<String> list1 = predicate(predicate1, list); System.out.println(list1); } //斷言型接口 返回true/false經(jīng)常用于判斷 public static List<String> predicate(Predicate<String> predicate,List<String> list){ List<String> newList=new ArrayList<>(); for(int i=0;i<list.size();i++){ if(predicate.test(list.get(i))){ newList.add(list.get(i)); } } return newList; } //函數(shù)型接口 有參數(shù),且需要返回值 public static String toUpper(Function<String,String> function,String str){ return function.apply(str); } //消費(fèi)性函數(shù)式接口 不需要返回值,有參數(shù),經(jīng)常用于迭代 public static void hobby(Consumer<Double> consumer,double money){ consumer.accept(money); } //供給型函數(shù)式接口 無(wú)參數(shù),指定返回值類型,經(jīng)常用于只注重過(guò)程的代碼 public static int[] getArr(Supplier<Integer> supplier,int count){ int [] arr=new int[count]; for(int i=0;i<count;i++){ arr[i]=supplier.get(); } return arr; } }
四、方法引用
方法引用式Lambda表達(dá)式的一種簡(jiǎn)寫形式。如果Lambda表達(dá)式方法體中只是調(diào)用一個(gè)特定的已經(jīng)存在的方法,則可以使用方法引用。
常見(jiàn)的方法引用:
(1)構(gòu)造器引用
**格式:**類名::new
@Test public void test04(){ //普通寫法 Supplier<Emp> supplier=new Supplier<Emp>() { @Override public Emp get() { return new Emp("劉德華"); } }; //類名::new 方法引用 Supplier<Emp> supplier=Emp::new; //必須該類中存在無(wú)參構(gòu)造函數(shù)。 System.out.println(supplier.get()); } @Data @AllArgsConstructor @NoArgsConstructor class Emp{ private String name; }
(2)靜態(tài)方法引用
**格式:**類名::靜態(tài)方法名
//類::靜態(tài)方法 int compare(T o1, T o2); //Lambda表達(dá)式方法引用 Comparator<Integer> comparator=(o1,o2)->Integer.compare(o1,o2); //靜態(tài)方法引用Demo Comparator<Integer> comparator=Integer::compare; int compare = comparator.compare(18, 18); System.out.println(compare);
(3)類的方法引用
**格式:**類名::實(shí)例方法名
//lambda匿名方法引用 Function<Emp,String> function=e->{ return e.getName(); }; //類名::實(shí)例方法 R apply(T t); Function<Emp,String> function=Emp::getName; System.out.println(function.apply(new Emp("劉德華")));
(4)實(shí)例對(duì)象的方法引用
**格式:**對(duì)象::實(shí)例方法名
//對(duì)象::實(shí)例方法 //這里System.out就是一個(gè)對(duì)象 Consumer<String> consumer2=System.out::println; consumer2.accept("你是劉德華嗎?");
五、Stream API
流(Stream)中保存對(duì)集合或數(shù)組數(shù)據(jù)的操作。和集合類似,但集合中保存的是數(shù)據(jù)。
特點(diǎn):
- Stream自己不會(huì)存儲(chǔ)元素。
- Stream不會(huì)改變?cè)磳?duì)象。相反,他們會(huì)返回一個(gè)持有結(jié)果的新Stream。
- Stream操作是延遲執(zhí)行的。這意味著他們會(huì)等到需要結(jié)果的時(shí)候才執(zhí)行。
步驟:
創(chuàng)建一個(gè)流。
在一個(gè)或多個(gè)步驟中,將初始化Stream轉(zhuǎn)化到另一個(gè)Stream的中間操作。
使用一個(gè)終止操作來(lái)產(chǎn)生一個(gè)結(jié)果。該操作會(huì)強(qiáng)制它之前的延遲操作立即執(zhí)行。在這之后,該Stream就不能使用了。
要注意的是,對(duì)流的操作完成后需要進(jìn)行關(guān)閉操作(或者用JAVA7的try-with-resources)。
獲取Stream對(duì)象的方式
- 通過(guò)Collection對(duì)象的stream()或parallelStream()方法
- 通過(guò)Arrays類的stream()方法
- 通過(guò)Stream接口的of()、iterate()、generate()方法
- 通過(guò)IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法
public class Demo1 { public static void main(String[] args) { //1.通過(guò)Collection得對(duì)象中stream方法或parallelStream List<String> list=new ArrayList<>(); list.add("apple"); list.add("huawei"); list.add("xiaomi"); list.add("vivo"); Stream<String> stream = list.stream();//串行流 //遍歷集合(T t)-{}; 方法引用 stream.forEach(e->{ System.out.println(e); }); //方法引用 stream.forEach(System.out::println); Stream<String> stringStream = list.parallelStream(); //并行流 //2.通過(guò)Arrays轉(zhuǎn)化為流 int[] arr={2,34,5,6,7,2}; IntStream stream = Arrays.stream(arr); stream.forEach(System.out::println); //3.通過(guò)Stream中of,iterator,generator(); Stream<String> list = Stream.of("java01", "java02", "java03"); static <T> UnaryOperator<T> identity() { return t -> t; } UnaryOperator<Integer> unaryOperator=new UnaryOperator<Integer>() { @Override public Integer apply(Integer x) { return x+5; } }; UnaryOperator<Integer> unaryOperator=x->x+5; Stream<Integer> list = Stream.iterate(0,unaryOperator);//0,5,10,15,20,25,30 list.limit(10).forEach(System.out::println); Supplier<T> s Supplier<Integer> s=new Supplier() { @Override public Integer get() { return new Random().nextInt(50); } }; Supplier<Integer> s=()->new Random().nextInt(50); Stream<Integer> stream = Stream.generate(s); Stream<Integer> stream = Stream.generate(()->new Random().nextInt(50)); stream.limit(10).forEach(System.out::println); //IntStream LongStream DoubleStream IntStream stream = IntStream.rangeClosed(0, 90); stream.forEach(System.out::println); } }
5.1 中間操作
中間操作.
filter、limit、skip、distinct、sorted map parallel
- filter:接收Lambda,從流中排除某些操作;
- limit:截?cái)嗔?,使其元素不超過(guò)給定對(duì)象
- skip(n):跳過(guò)元素,返回一個(gè)扔掉了前n個(gè)元素的流,若流中元素不足n個(gè),則返回一個(gè)空流,與limit(n)互補(bǔ)
- distinct:篩選,通過(guò)流所生成元素的hashCode()和equals()去除重復(fù)元素。
代碼操作
public class test02 { public static void main(String[] args) { //personList.stream()是創(chuàng)建流,filter()屬于中間操作,forEach、count()是終止操作。 List<Person> personList = new ArrayList<>(); personList.add(new Person("歐陽(yáng)雪",18,"中國(guó)",'F')); personList.add(new Person("Tom",24,"美國(guó)",'M')); personList.add(new Person("Tom",24,"美國(guó)",'M')); personList.add(new Person("Harley",22,"英國(guó)",'F')); personList.add(new Person("向天笑",20,"中國(guó)",'M')); personList.add(new Person("李康",22,"中國(guó)",'M')); personList.add(new Person("小梅",20,"中國(guó)",'F')); personList.add(new Person("何雪",21,"中國(guó)",'F')); personList.add(new Person("李康",22,"中國(guó)",'M')); //找出大于21歲的人 personList.stream().filter((person) -> person.getAge()>21).forEach(System.out::println); System.out.println("----------------------"); //查詢中國(guó)人有幾個(gè) long num = personList.stream().filter(p ->p.getCountry().equals("中國(guó)")).count(); System.out.println("中國(guó)人有:"+num+"個(gè)"); System.out.println("---------------------------"); //從Person列表中取出兩個(gè)女性。 personList.stream().filter((p) -> p.getSex() == 'F').limit(2).forEach(System.out::println); System.out.println("----------------------------"); //從Person列表中從第2個(gè)女性開始,取出所有的女性。 personList.stream().filter((p) -> p.getSex() == 'F').skip(1).forEach(System.out::println); System.out.println("-------------------------------"); //去除掉了一個(gè)重復(fù)的數(shù)據(jù) personList.stream().filter((p) -> p.getSex() == 'M').distinct().forEach(System.out::println); }
測(cè)試結(jié)果
在這個(gè)例子中,personList.stream()是創(chuàng)建流,filter()、limit()、skip()、distinct()屬于中間操作,forEach、count()是終止操作。
5.2 Stream中間操作–映射
- map–接收Lambda,將元素轉(zhuǎn)換成其他形式或提取信息。接收一個(gè)函數(shù)作為參數(shù),該函數(shù)會(huì)被應(yīng)用到每個(gè)元素上,并將其映射成一個(gè)新的元素。
- flatMap–接收一個(gè)函數(shù)作為參數(shù),將流中的每個(gè)值都換成另一個(gè)流,然后把所有流連接成一個(gè)流
map舉例
例:比如,我們用一個(gè)PersonCountry類來(lái)接收所有的國(guó)家信息:
System.out.println("**************************"); personList.stream().map((p) -> { Person personName = new Person(); personName.setCountry(p.getCountry()); return personName; }).distinct().forEach(System.out::println);
測(cè)試結(jié)果
5.3 Stream中間操作–排序
- sorted()–自然排序(Comparable)
- sorted(Comparator com)–定制排序(Comparator)
自然排序比較好理解,這里只講一下定制排序,對(duì)前面的personList按年齡從小到大排序,年齡相同,則再按姓名排序:
final Stream<Person> sorted = personList.stream().sorted((p1, p2) -> { if (p1.getAge().equals(p2.getAge())) { return p1.getName().compareTo(p2.getName()); } else { return p1.getAge().compareTo(p2.getAge()); } }); sorted.forEach(System.out::println);
運(yùn)行結(jié)果
5.4 終止操作
forEach、min、max、count reduce、collect
- allMatch–檢查是否匹配所有元素
- anyMatch–檢查是否至少匹配一個(gè)元素
- noneMatch–檢查是否沒(méi)有匹配所有元素
- findFirst–返回第一個(gè)元素
- findAny–返回當(dāng)前流中的任意元素
- count–返回流中元素的總個(gè)數(shù)
- max–返回流中最大值
- min–返回流中最小值
allMatch
判斷personList中的人是否都是成年人:
final boolean adult = personList.stream().allMatch(p -> p.getAge() >= 18); System.out.println("是否都是成年人:" + adult); final boolean chinaese = personList.stream().allMatch(p -> p.getCountry().equals("中國(guó)")); System.out.println("是否都是中國(guó)人:" + chinaese);
運(yùn)行結(jié)果
max min
判斷最大、最小的人信息
final Optional<Person> maxAge = personList.stream().max((p1, p2) -> p1.getAge().compareTo(p2.getAge())); System.out.println("年齡最大的人信息:" + maxAge.get()); final Optional<Person> minAge = personList.stream().min((p1, p2) -> p1.getAge().compareTo(p2.getAge())); System.out.println("年齡最小的人信息:" + minAge.get());
運(yùn)行結(jié)果
求一個(gè)1到100的和
List<Integer> integerList = new ArrayList<>(100); for(int i = 1;i <= 100;i++) { integerList.add(i); } final Integer reduce = integerList.stream().reduce(0, (x, y) -> x + y); System.out.println("結(jié)果為:" + reduce);
運(yùn)行結(jié)果
求所有人的年齡之和
final Optional<Integer> reduce = personList.stream().map(Person::getAge).reduce(Integer::sum); System.out.println("年齡總和:" + reduce);
年齡總和:193
改寫map舉例中的的例子,將國(guó)家收集起來(lái)轉(zhuǎn)換成List
final List<String> collect = personList.stream().map(p -> p.getCountry()).distinct().collect(Collectors.toList()); System.out.println(collect);
輸出結(jié)果:[中國(guó), 美國(guó), 英國(guó)]
計(jì)算出平均年齡
final Double collect1 = personList.stream().collect(Collectors.averagingInt(p -> p.getAge())); System.out.println("平均年齡為:" + collect1);
平均年齡為:21.444444444444443
注意流的關(guān)閉
try(final Stream<Integer> integerStream = personList.stream().map(Person::getAge)) { final Optional<Integer> minAge = integerStream.collect(Collectors.minBy(Integer::compareTo)); System.out.println(minAge.get()); }
到此這篇關(guān)于Java8常用的新特性詳解的文章就介紹到這了,更多相關(guān)Java8常用的新特性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用application.property讀取文件里面的值
本文通過(guò)實(shí)例代碼給大家介紹了Java使用application.property讀取文件里面的值,需要的朋友可以參考下2018-10-10Jenkins如何實(shí)現(xiàn)自動(dòng)打包部署linux
這篇文章主要介紹了Jenkins如何實(shí)現(xiàn)自動(dòng)打包部署linux,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11MyBatis使用注解開發(fā)實(shí)現(xiàn)步驟解析
這篇文章主要介紹了MyBatis使用注解開發(fā)實(shí)現(xiàn)步驟解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Spring與Shiro整合及加載權(quán)限表達(dá)式問(wèn)題
這篇文章主要介紹了Spring與Shiro整合及加載權(quán)限表達(dá)式問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12Spring Boot部署到Tomcat過(guò)程中遇到的問(wèn)題匯總
這篇文章主要給大家分享了關(guān)于Spring Boot部署到Tomcat過(guò)程中遇到的一些問(wèn)題,文中將解決的方法介紹非常詳細(xì),對(duì)同樣遇到這個(gè)問(wèn)題的朋友具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03SpringBoot Actuator監(jiān)控的項(xiàng)目實(shí)踐
本文主要結(jié)合 Spring Boot Actuator,跟大家一起分享微服務(wù)Spring Boot Actuator 的常見(jiàn)用法,方便我們?cè)谌粘V袑?duì)我們的微服務(wù)進(jìn)行監(jiān)控治理,感興趣的可以了解一下2024-01-01