菜鳥的java8新特性探索
說明
更新時間:2020/5/29 11:11,更新了基本功能
關於java8新特性,很久之前就聽說過了,現在將java8新特性中的Stream api的使用記錄在這裏,以便日後查看,本文會持續更新,不斷地擴充
本文僅爲記錄學習軌跡,如有侵權,聯繫刪除
一、關於java8新特性
Java 8 (又稱爲 jdk 1.8) 是 Java 語言開發的一個主要版本。 Oracle 公司於 2014 年 3 月 18 日發佈 Java 8 ,它支持函數式編程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
其中個人u覺得最重要的新特性Stream API,個人使用的也比較頻繁,雖然當時不知道這是java8的新特性,Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。
二、Stream
Stream流使用流程:開始---->中間操作---->終止操作
開始包括流的創建,中間操作包括對創建的流進行篩選、聚合等操作,終止操作則將得到的結果轉爲某種形式輸出
/**
* Java從8開始,不但引入了Lambda表達式,還引入了一個全新的流式API:Stream API。它位於java.util.stream包中。
*
* 劃重點:這個Stream不同於java.io的InputStream和OutputStream,它代表的是任意Java對象的序列。
*
* Stream API的基本用法就是:創建一個Stream,然後做若干次轉換,最後調用一個求值方法獲取真正計算的結果:
*
* 注意:把數組變成Stream使用Arrays.stream()方法。對於Collection(List、Set、Queue等),直接調用stream()方法就可以獲得Stream。
*/
stream的創建
主要分兩類,數組和集合(List、Map、Set)
//數組變成Stream使用Arrays.stream()方法
int[] nums = {1,2,3,4,5,6,7,8,9,10};
Arrays.stream(nums).forEach(n->{
//用forEach()遍歷數組無法獲取下標
System.out.println("n = "+n);
});
//對於Collection(List、Set、Queue等),直接調用stream()方法就可以獲得Stream
List<String> list = new ArrayList<>();
list.add("灰太狼");
list.add("喜羊羊");
list.add("小灰灰");
list.add("懶羊羊");
list.stream().forEach(l->{
System.out.println("index = "+list.indexOf(l)+" value = "+l);
});
Stream的中間操作
下面整理很多常用的一些中間操作,包括求和,過濾、平均值、排序等,具體如下
可能用到的兩個實體類
class User{
private Integer id;
private String name;
private Date birthday;
private Integer age;
private String sex;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", birthday=" + birthday +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public User(Integer id, String name, Date birthday, Integer age, String sex) {
this.id = id;
this.name = name;
this.birthday = birthday;
this.age = age;
this.sex = sex;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public Date getBirthday() {
return birthday;
}
}
class Account {
private Integer id;
private String name;
public Account() {
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public Account(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(1)forEach()
/**
* Stream中間操作 1.forEach()
* 循環每一個元素
*/
public static void StreamForEcach(){
/**
* 數組
*/
System.out.println("--------------------數組的forEach()--------------------");
int[] nums = {1,2,3,4,5,6,7,8,9,10};
Arrays.stream(nums).forEach(n->{
//用forEach()遍歷數組無法獲取下標
System.out.println("n = "+n);
});
/**
* List
*/
System.out.println("--------------------List的forEach()--------------------");
List<String> list = new ArrayList<>();
list.add("灰太狼");
list.add("喜羊羊");
list.add("小灰灰");
list.add("懶羊羊");
list.stream().forEach(l->{
System.out.println("index = "+list.indexOf(l)+" value = "+l);
});
/**
* map
*/
System.out.println("-------------------Map的forEach()--------------------");
Map<String,String> map = new HashMap<>();
map.put("狼1","灰太狼");
map.put("狼2","小灰灰");
map.put("羊1","喜羊羊");
map.put("羊2","懶羊羊");
//map遍歷方式1
System.out.println("map遍歷方式1:");
map.keySet().forEach(key -> {
System.out.println("key : "+key+" value : "+map.get(key));
});
//map遍歷方式2
System.out.println("map遍歷方式2:");
map.entrySet().forEach(entry -> {
System.out.println("key : " + entry.getKey() + " value : " + entry.getValue());
});
//map遍歷方式3
System.out.println("map遍歷方式3:");
map.forEach((key,value)->{
System.out.println("key : "+key+" value : "+value);
});
/**
* set
*/
System.out.println("--------------------set的forEach()--------------------");
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.forEach(s->{
System.out.println(s);
});
}
(2)filter()
/**
* Stream中間操作 2.filter()
* 過濾篩選出符合某些條件的項,filter(條件 && 條件)
*/
public static void StreamFilter(){
/**
* 數組
*/
System.out.println("--------------------數組的filter()--------------------");
int[] nums = {1,2,3,4,5,6,7,8,9,10};
//篩選出除了10的所有偶數
int[] newNums = Arrays.stream(nums).filter(n -> (n % 2 == 0 && n != 10)).toArray();
Arrays.stream(newNums).forEach(System.out::println);
/**
* List
*/
System.out.println("--------------------List的filter()--------------------");
List<String> list = new ArrayList<>();
list.add("灰太狼");
list.add("喜羊羊");
list.add("小灰灰");
list.add("懶羊羊");
//篩選出以"羊"結尾的項
List<String> newList = list.stream().filter(l -> l.endsWith("羊")).collect(Collectors.toList());
newList.forEach(System.out::println);
/**
* map
*/
System.out.println("--------------------Map的filter()--------------------");
Map<String,String> map = new HashMap<>();
map.put("狼1","灰太狼");
map.put("狼2","小灰灰");
map.put("羊1","喜羊羊");
map.put("羊2","懶羊羊");
//通過以狼結尾的項篩選出灰太狼
Map<String, String> newMap = map.entrySet().stream().filter(m -> {
if (m.getKey().startsWith("狼") && m.getValue().equals("灰太狼")) {
return true;
} else {
return false;
}
}).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));
newMap.forEach((k,v)->{
System.out.println("key = "+k+" value = "+v);
});
/**
* set
*/
System.out.println("--------------------Set的filter()--------------------");
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
//篩選出偶數
Set<Integer> newSet = set.stream().filter(s -> s % 2 == 0).collect(Collectors.toSet());
newSet.forEach(System.out::println);
}
(3)limit()
/**
* Stream中間操作 3.limit()
* 它是用於限制流中元素的個數,即取前n個元素,返回新的流
*/
public static void StreamLimit(){
/**
* 數組
*/
System.out.println("--------------------數組的limit()--------------------");
int[] nums = {1,2,3,4,5,6,7,8,9,10};
//取出前10個數
int[] newNums = Arrays.stream(nums).limit(5).toArray();
Arrays.stream(newNums).forEach(System.out::println);
/**
* List
*/
System.out.println("--------------------List的limit()--------------------");
List<String> list = new ArrayList<>();
list.add("灰太狼");
list.add("喜羊羊");
list.add("小灰灰");
list.add("懶羊羊");
//取出前兩項
List<String> newList = list.stream().limit(2).collect(Collectors.toList());
newList.forEach(System.out::println);
/**
* map
*/
System.out.println("--------------------Map的limit()--------------------");
Map<String,String> map = new HashMap<>();
map.put("狼1","灰太狼");
map.put("狼2","小灰灰");
map.put("羊1","喜羊羊");
map.put("羊2","懶羊羊");
//取出前兩項
Map<String, String> newMap = map.entrySet().stream().limit(2).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));
newMap.forEach((k,v)->{
System.out.println("key = "+k+" value = "+v);
});
/**
* set
*/
System.out.println("--------------------Set的limit()--------------------");
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
//取出前兩項
Set<Integer> newSet = set.stream().limit(2).collect(Collectors.toSet());
newSet.forEach(System.out::println);
}
(4)skip()
/**
* Stream中間操作 4.skip()
* 該方法與limit()方法互補
* skip()方法用於跳過前面n個元素,然後再返回新的流
*/
public static void StreamSkip(){
/**
* 方法skip(n)的參數n的四種情況:
*
* (1)當n<0時,拋IllegalArgumentException異常;
*
* (2)當n=0時,相當沒有跳過任何元素,原封不動、完璧歸趙;
*
* (3)當0<n<length時,跳過n個元素後,返回含有剩下的元素的流;
*
* (4)當n>=length時,跳過所有元素,返回空流。
*/
/**
* 數組
*/
System.out.println("--------------------數組的skip()--------------------");
int[] nums = {1,2,3,4,5,6,7,8,9,10};
//跳過前5項返回其餘的項
int[] newNums = Arrays.stream(nums).skip(5).toArray();
Arrays.stream(newNums).forEach(System.out::println);
/**
* List
*/
System.out.println("--------------------List的skip()--------------------");
List<String> list = new ArrayList<>();
list.add("灰太狼");
list.add("喜羊羊");
list.add("小灰灰");
list.add("懶羊羊");
////跳過前2項返回其餘的項
List<String> newList = list.stream().skip(2).collect(Collectors.toList());
newList.forEach(System.out::println);
/**
* map
*/
System.out.println("--------------------Map的skip()--------------------");
Map<String,String> map = new HashMap<>();
map.put("狼1","灰太狼");
map.put("狼2","小灰灰");
map.put("羊1","喜羊羊");
map.put("羊2","懶羊羊");
//跳過前2項返回其餘的項
Map<String, String> newMap = map.entrySet().stream().skip(2).collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue()));
newMap.forEach((k,v)->{
System.out.println("key = "+k+" value = "+v);
});
/**
* set
*/
System.out.println("--------------------Set的skip()--------------------");
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
//跳過前2項返回其餘的項
Set<Integer> newSet = set.stream().skip(2).collect(Collectors.toSet());
newSet.forEach(System.out::println);
}
(5)distinct()
/**
* Stream中間操作 5.distinct()
* 去除重複項
*/
public static void StreamDistinct(){
/**
* 數組
*/
System.out.println("--------------------數組的distinct()--------------------");
int[] nums = {1,2,3,1,2,34,4,5,5,8,4};
//去除重複項
int[] newNums = Arrays.stream(nums).distinct().toArray();
Arrays.stream(newNums).forEach(System.out::println);
/**
* List
*/
System.out.println("--------------------List的distinct()--------------------");
List<String> list = new ArrayList<>();
list.add("灰太狼");
list.add("灰太狼");
list.add("喜羊羊");
list.add("喜羊羊");
list.add("懶羊羊");
//去除重複項
List<String> newList = list.stream().distinct().collect(Collectors.toList());
newList.forEach(System.out::println);
/**
* map和set因爲不可重複性所以沒必要用到distinct()
*/
}
(6)map()
/**
* Stream中間操作 6.map()
* 可以將對象轉換爲其他對象
* Stream.map()是Stream最常用的一個轉換方法,它把一個Stream轉換爲另一個Stream
* 所謂map操作,就是把一種操作運算,映射到一個序列的每一個元素上。
* 例如,對x計算它的平方,可以使用函數f(x) = x * x。我們把這個函數映射到一個序列1,2,3,4,5上,就得到了另一個序列1,4,9,16,25:
*/
public static void StreamMap(){
//將數組先轉爲Stream,再平方後再轉爲數組
int[] nums = {1, 2, 3, 4, 5};
int[] result1 = Arrays.stream(nums)
.map(n -> n * n)
.toArray();
//將Strings列表轉換爲大寫
List<String> list1 = Arrays.asList("a","b","c","d","e");
List<String> newList1 = list1.stream().map(String::toUpperCase).collect(Collectors.toList());
newList1.forEach(System.out::println);
//對象列表 - >字符串列表
List<User> users = Arrays.asList(
new User(1,"灰太狼",new Date(),11,"男"),
new User(2,"喜羊羊",new Date(),10,"男"),
new User(3,"小灰灰",new Date(),15,"男")
);
List<String> newUsers = users.stream().map(u -> u.getName()).collect(Collectors.toList());
newUsers.forEach(System.out::println);
//對象列表 - >其他對象列表(User -> Account)
List<Account> accounts = users.stream().map(u -> {
Account account = new Account();
account.setId(u.getId());
account.setName(u.getName());
return account;
}).collect(Collectors.toList());
accounts.forEach(System.out::println);
}
(7)sorted()
/**
* Stream中間操作 7.sorted()
* 排序
*/
public static void StreamSorted(){
//將數組先轉爲Stream,再平方後再轉爲數組
int[] nums = {11, 2, 32, 14, 5};
int[] newNums = Arrays.stream(nums).sorted().toArray();
Arrays.stream(newNums).forEach(System.out::println);
//按對象的年齡排序
List<User> users = Arrays.asList(
new User(1,"灰太狼",new Date(),11,"男"),
new User(2,"喜羊羊",new Date(),10,"男"),
new User(3,"小灰灰",new Date(),15,"男")
);
List<User> newUsers = users.stream().sorted((p1, p2) -> {
return p1.getAge().compareTo(p2.getAge());
}).collect(Collectors.toList());
newUsers.forEach(System.out::println);
}
除此之外還有其他的中間操作,以後遇到接着補充…
最終操作
最終操作將結果轉換成某種形式輸出
(1)allMatch()
/**
* Stream終止操作 1.allMatch()
* 檢查是否匹配所有元素
*/
public static void StreamAllMatch(){
//判斷數組的元素是否都是在0-20之間
int[] nums = {11, 2, 32, 14, 5};
boolean isBetweenZeroTwenty = Arrays.stream(nums).allMatch(n -> (n >= 0) && (n <= 20));
System.out.println("數組的元素是否都是在0-20之間:"+isBetweenZeroTwenty);
//判斷user列表的元素的年紀是否都是大於等於18歲
List<User> users = Arrays.asList(
new User(1,"灰太狼",new Date(),11,"男"),
new User(2,"喜羊羊",new Date(),10,"男"),
new User(3,"小灰灰",new Date(),15,"男")
);
boolean isAdult = users.stream().allMatch(u -> u.getAge() >= 18);
System.out.println("user列表的元素的年紀是否都是大於等於18歲:"+isAdult);
}
(2)max()和 min()
/**
* Stream終止操作 2.max()和 min()
* 查找最大值
*/
public static void StreamMaxMin(){
//返回數組最大值
int[] nums = {11, 2, 32, 14, 5};
int numMax = Arrays.stream(nums).max().getAsInt();
int numMin = Arrays.stream(nums).min().getAsInt();
System.out.println("數組最大值:"+numMax);
System.out.println("數組最小值:"+numMin);
//返回年紀最大值
List<User> users = Arrays.asList(
new User(1,"灰太狼",new Date(),11,"男"),
new User(2,"喜羊羊",new Date(),10,"男"),
new User(3,"小灰灰",new Date(),15,"男")
);
Optional<User> userMax = users.stream().max((p, q) -> {
return p.getAge().compareTo(q.getAge());
});
Optional<User> userMin = users.stream().min((p, q) -> {
return p.getAge().compareTo(q.getAge());
});
System.out.println("年紀最大的是 : "+userMax.get());
System.out.println("年紀最小的是 : "+userMin.get());
}
(3)sum()和 average()
/**
* Stream終止操作 3.sum()和 average()
* 查找最大值
*/
public static void StreamSumAve(){
//求和與平均值
int[] nums = {11, 2, 32, 14, 5};
int numSum = Arrays.stream(nums).sum();//求和
double numAve = Arrays.stream(nums).average().getAsDouble();//求平均值
System.out.println("求和 :"+numSum);
System.out.println("平均值:"+numAve);
//對象的求和與平均值
List<User> users = Arrays.asList(
new User(1,"灰太狼",new Date(),11,"男"),
new User(2,"喜羊羊",new Date(),10,"男"),
new User(3,"小灰灰",new Date(),15,"男")
);
Integer userAgeSum = users.stream().map(u -> u.getAge()).reduce(Integer::sum).get();
Double userAgeAve = users.stream().collect(Collectors.averagingInt(p -> p.getAge()));
System.out.println("用戶年紀求和 : "+userAgeSum);
System.out.println("用戶年紀平均值 : "+userAgeAve);
}
Stream高級應用
下面是Stream的一些高級應用,個人覺得這個十分重要,像統計數據方面,真的是方便。
(1)排序並分組
/**
* Stream高級應用 1.排序並分組
*
*/
public static void StreamGroupingOrderBy(){
try {
SimpleDateFormat simFormat = new SimpleDateFormat("yyyy/MM/dd");
//對象的求和與平均值
List<User> users = Arrays.asList(
new User(1,"灰太狼",simFormat.parse("2018/01/23"),11,"男"),
new User(2,"紅太狼",simFormat.parse("2018/01/23"),10,"女"),
new User(2,"美羊羊",simFormat.parse("2001/12/03"),10,"女"),
new User(3,"小灰灰",simFormat.parse("2022/02/13"),15,"男"),
new User(3,"懶羊羊",simFormat.parse("2020/02/13"),15,"男")
);
//按性別分組
Map<String, List<User>> collectSex = users.stream()
.sorted(Comparator.comparing(User::getBirthday))
.collect(Collectors.groupingBy(User::getSex));
//輸出
collectSex.forEach((k,v)->{
System.out.println("key : "+k+" value : "+v);
});
//按出生日期的day分組
Map<Date, List<User>> collectBirthday= users.stream()
.sorted(Comparator.comparing(User::getBirthday))
.collect(Collectors.groupingBy(u->u.getBirthday()));
//輸出
collectBirthday.forEach((k,v)->{
System.out.println("key : "+simFormat.format(k)+" value : "+v);
});
} catch (ParseException e) {
e.printStackTrace();
}
}
(2)集合之間轉換
/**
* Stream高級應用 2.集合之間轉換
*
*/
public static void StreamConvert(){
try {
/**
* List ----> Map
*/
SimpleDateFormat simFormat = new SimpleDateFormat("yyyy/MM/dd");
List<User> users = Arrays.asList(
new User(1,"灰太狼",simFormat.parse("2018/01/23"),11,"男"),
new User(2,"紅太狼",simFormat.parse("2018/01/23"),10,"女"),
new User(2,"美羊羊",simFormat.parse("2001/12/03"),10,"女"),
new User(3,"小灰灰",simFormat.parse("2022/02/13"),15,"男"),
new User(3,"懶羊羊",simFormat.parse("2020/02/13"),15,"男")
);
//以name爲key,age爲value,將list<User>轉爲Map
Map<String, Integer> map = users.stream().collect(Collectors.toMap(User::getName, User::getAge));
map.forEach((key,value)->{
System.out.println("key:"+key+" value:"+value);
});
/**
* List -----> Set
*/
Set<User> collect1 = users.stream().collect(Collectors.toSet());
collect1.forEach(System.out::println);
/**
* Map -----> List
*/
List<String> stringList = map.entrySet().stream().map(m -> m.getKey()).collect(Collectors.toList());
stringList.forEach(System.out::println);
/**
* Map ----> Set
*/
Set<String> stringSet = map.entrySet().stream().map(m -> m.getKey()).collect(Collectors.toSet());
stringSet.forEach(System.out::println);
/**
* Set ----> List
*/
List<String> list = stringSet.stream().collect(Collectors.toList());
list.forEach(System.out::println);
} catch (ParseException e) {
e.printStackTrace();
}
}