JAVA1.8新特性Stream API的簡單使用
list.stream()和list.parallelStream()的區別:stream(),單線程操作,雖然Stream API支持多線程操作集合,但是普通的stream()並沒有提供多線程操作,實質上還是串行運行,對於遍歷集合來說,它和迭代器,for循環相同,效率沒有太大的區別。而parallelStream()則是多線程操作list,它會把list拆分成幾部分,使用多線程並行操作,而至於會產生多少個線程來處理,則和cpu個數有關,一般線程個數和cpu個數相同,但是可以通過參數設置。下面就列舉一些常見的Stream操作集合的例子。
目錄
前提條件:
測試用Person類:
public class Person
{
private String name;
private Integer age;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
測試用Man類,該類是Person類子類,擁有自己特別的屬性target。
public class Man extends Person {
private String target;
public String getTarget() {
return target;
}
public void setTarget(String target) {
this.target = target;
}
}
Main函數代碼:
List<Person> persons = new LinkedList();
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
Person person4 = new Person();
person1.setName("張三");
person1.setAge(24);
person1.setGender("男");
person2.setName("李四");
person2.setAge(44);
person2.setGender("男");
person3.setName("王五");
person3.setAge(34);
person3.setGender("女");
person4.setName("小二");
person4.setAge(14);
person4.setGender("男");
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person4);
一、forEach()
該函數和for循環相同,主要作用就是遍歷集合裏面的所有元素,沒有返回值。
persons.parallelStream().forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
運行結果:
二、map()
該函數用於轉換集合裏面的元素,比如,將Person類里名字提取出來組成一個List<String>類型,這個時候就做了一個轉換:List<Person>→List<String>,代碼如下:
List<String> personNames = persons.parallelStream().map(person -> person.getName()).collect(Collectors.toList());
personNames.parallelStream().forEach(System.out::println);
運行結果:
map()函數裏面的lambda表達式需要有一個返回值,返回值的類型就是你最後想要轉換成的類型。如果你想轉換成Integer的List,那麼你就只需要返回person.getAge()。
當lambda表示足夠簡單,就不需要寫return關鍵字來返回自己需要的類型,如果邏輯比較複雜,需要2條以上的語句才能返回想要的結果,那麼就需要寫return語句,比如,現在我把person類集合轉換爲其子類man類的集合:
List<Man> mans = persons.parallelStream().map(person -> {
Man oneMan = new Man();
oneMan.setName(person.getName());
oneMan.setTarget("我是子類Man,我的名字是" + person.getName());
return oneMan;
}).collect(Collectors.toList());
mans.parallelStream().forEach(man -> System.out.println(man.getName() + "--" + man.getTarget()));
運行結果:
另外說一句,Collectors類可以轉換如下集中集合:List、Set、Map,不僅僅只有toList()方法,其中還有很多其他方法,比如分組groupingBy,統計counting等,非常實用,下面就舉一個通過grouping函數,將list轉換爲map的例子。
三、Collectors.groupingBy()
現在將persons集合轉換成,以person名字爲鍵,person類的集合爲值的map<String,List<Person>>,代碼如下:
Map<String, List<Person>> nameToPersons = persons.parallelStream().collect(Collectors.groupingBy(Person::getName));
for (Map.Entry<String, List<Person>> nameToPerson : nameToPersons.entrySet()) {
System.out.println("鍵:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().get(0).getName() + "--" + nameToPerson.getValue().get(0).getAge());
}
運行結果:
這裏解釋一下爲什麼值是List類型,因爲該方法不能確定你的鍵是否唯一,對應的,有另外的方法應對鍵唯一的情況,下面我用person的名字和年齡作爲鍵,person作爲值。(用什麼作爲鍵,和值都是隨意改變的)
Map<String, Person> nameToPersons = persons.parallelStream().collect(Collectors.toMap(person -> person.getName() + person.getAge(), person -> person));
for (Map.Entry<String, Person> nameToPerson : nameToPersons.entrySet()) {
System.out.println("鍵:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().getName() + "--" + nameToPerson.getValue().getAge());
}
運行結果:
四、filter()
該函數用作過濾,過濾掉集合中不滿足條件的值,保留需要的值。該函數接收一個boolean類型的表達式,如果集合中的值使這個表達式爲true,那麼就保留,否則移出,當然,如果你沒用使用集合中的值參與表達式,那麼這個集合最終保留的值取決於表達式。現在我過濾掉persons裏面年齡小於40的值,最後結果應該只會留下李四,44歲這個值,代碼如下:
List<Person> ageGt40s = persons.parallelStream().filter(person -> person.getAge() > 40).collect(Collectors.toList());
ageGt40s.forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
運行結果如下:
最後再說一下,關於使用parallelStream操作集合,必須考慮多線程的影響,因爲其實質是使用多線程同時操作集合的,如果在操作中,對外部變量進行了修改操作,那麼需要考慮是否線程安全問題。這裏貼上全部main函數測試代碼:
public class TestUnitl
{
public static void main(String[] args)
{
List<Person> persons = new LinkedList();
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
Person person4 = new Person();
person1.setName("張三");
person1.setAge(24);
person1.setGender("男");
person2.setName("李四");
person2.setAge(44);
person2.setGender("男");
person3.setName("王五");
person3.setAge(34);
person3.setGender("女");
person4.setName("小二");
person4.setAge(14);
person4.setGender("男");
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person4);
//persons.parallelStream().forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
//List<String> personNames = persons.parallelStream().map(person -> person.getName()).collect(Collectors.toList());
//personNames.parallelStream().forEach(System.out::println);
//List<Man> mans = persons.parallelStream().map(person -> {
// Man oneMan = new Man();
// oneMan.setName(person.getName());
// oneMan.setTarget("我是子類Man,我的名字是" + person.getName());
// return oneMan;
//}).collect(Collectors.toList());
//mans.parallelStream().forEach(man -> System.out.println(man.getName() + "--" + man.getTarget()));
//Map<String, List<Person>> nameToPersons = persons.parallelStream().collect(Collectors.groupingBy(Person::getName));
//
//for (Map.Entry<String, List<Person>> nameToPerson : nameToPersons.entrySet()) {
// System.out.println("鍵:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().get(0).getName() + "--" + nameToPerson.getValue().get(0).getAge());
//}
//Map<String, Person> nameToPersons = persons.parallelStream().collect(Collectors.toMap(person -> person.getName() + person.getAge(), person -> person));
//
//for (Map.Entry<String, Person> nameToPerson : nameToPersons.entrySet()) {
// System.out.println("鍵:" + nameToPerson.getKey() + "--值:" + nameToPerson.getValue().getName() + "--" + nameToPerson.getValue().getAge());
//}
List<Person> ageGt40s = persons.parallelStream().filter(person -> person.getAge() > 40).collect(Collectors.toList());
ageGt40s.forEach(person -> System.out.println(person.getName() + "--" + person.getAge() + "--" + person.getGender()));
}
}
目前筆者比較常用的就這四個函數,上面也總結了淺顯的使用方式,爲了更加深入瞭解stream api,筆者也會繼續學習瞭解該技術。