1. 程式人生 > 實用技巧 >Java 8中Stream API

Java 8中Stream API

Stream簡介

  1. Java 8引入了全新的Stream API。這裡的Stream和I/O流不同,它更像具有Iterable的集合類,但行為和集合類又有所不同。
  2. stream是對集合物件功能的增強,它專注於對集合物件進行各種非常便利、高效的聚合操作,或者大批量資料操作。
  3. 只要給出需要對其包含的元素執行什麼操作,比如 “過濾掉長度大於 10 的字串”、“獲取每個字串的首字母”等,Stream 會隱式地在內部進行遍歷,做出相應的資料轉換。

為什麼要使用Stream

  1. 函數語言程式設計帶來的好處尤為明顯。這種程式碼更多地表達了業務邏輯的意圖,而不是它的實現機制。易讀的程式碼也易於維護、更可靠、更不容易出錯。
  2. 高階
例項資料來源
public class Data {
private static List<PersonModel> list = null;
static {
PersonModel wu = new PersonModel("wu qi",18, "男");
PersonModel zhang = new PersonModel(" zhang san" , 19, "男");
PersonModel wang = new PersonModel( "wang si", 20, "女");
PersonModel zhao = new PersonModel(" zhao wu", 20,“男");
PersonModel chen = new PersonModel("chen liu" ,21, "男");
list = Arrays.asList(wu, zhang, wang, zhao, chen);
public static List<PersonModel> getData() {
return list;
}
Filter
  1. 遍歷資料並檢查其中的元素時使用。
  2. filter接受一個函式作為引數,該函式用Lambda表示式表示。
過濾所有的男性
public static void fiterSex(){
List<PersonModel> data = Data . getData();
//old
List<PersonModel> temp=new ArrayList<>();
for (PersonModel person:data) {
if ("男".equals(person.getSex))){
temp. add(person);
}
System. out. println(temp);
//new
List<PersonModel> collect = data
.stream() 
.filter(person ->“男". equals(person. getSex()))
.collect(toList());
System. out. println(collect);
}
/**
過濾所有的男性並且小於20歲
**/
public static void fiterSexAndAge(){
List<PersonModel> data - Data. getData();
//old
List<PersonModel> temp=new ArrayList<>();
for (PersonModel person:data) {
if ("男".equals(person.getSex() )&&person.getAge()<20){
temp . add(person);
}
//new 1
List<PersonModel> collect = data
.stream()
.filter(person -> {
if ("男" .equals(person. getSex()8&person. getAge()<28){
return true;
}
return false;
})
.collect(toList());
//new
List<PersonModel> collect1 = data
. stream()
.filter(person -> (“男" .equals(person.getSex()&person. getAge()<20))
.collect(toList());
}


Map
  1. map生成的是個一對一對映,for的作用
  2. 比較常用
  3. 而且很簡單
/**取出所有的使用者名稱字**/
public static void getUserNameList(){
List<PersonMdel> data = Data. getData();
//old
List<String> list=new ArrayList<>(); 
for (PersonModel pers ion :data) {
list. add(persion. getName());
System. . out .println(list);
//new 1
List<String> collect = data.stream() . map(person -> person .getName()).collect(toList());
System. out . printIn(collect);
//new 2
List<String> collect1 = data.stream().map(PersonModel::getName).collect(toList()); 
System.out.printIn(collect1);
//new 3
List<string> collect2 = data . stream() .map(person -> {
System. out . printIn(person . getName());
return person. getName();
}).collect(toList());

FlatMap
  1. 顧名思義,跟map差不多,更深層次的操作

  2. 但還是有區別的

  3. map和flat返回值不同

  4. Map 每個輸入元素,都按照規則轉換成為另外一個元素。
    還有一些場景,是一對多對映關係的,這時需要 flatMap。

  5. Map一對一

  6. Flatmap一對多

  7. map和flatMap的方法宣告是不一樣的

  8. (1) Stream map(Function mapper);

(2) Stream flatMap(Function> mapper);

(3) map和flatMap的區別:我個人認為,flatMap的可以處理更深層次的資料,入參為多個list,結果可以返回為一個list,而map是一對一的,入參是多個list,結果返回必須是多個list。通俗的說,如果入參都是物件,那麼flatMap可以操作物件裡面的物件,而map只能操作第一層。

public static void flatMapString() {
List<PersonModel> data = Data . getData();
//返回型別不一樣
List<String> collect - data.stream()
.flatMap(person -> Arrays . stream(person. getName().split(" "))).collect(toList()); 
List<Stream<String>> collect1 = data.stream()
.map(person -> Arrays . stream(person. getName().split(" "))).collect(toList());
//用map實現
List<String> collect2 - data. stream()
.map(person -> person. getName().split(" "))
.flatMap (Arrays: :stream) . collect(toList()); 
//另- 種方式
List<string> collect3 = data. stream()
.map(person -> person. getName().split(" "))
.flatMap(str -> Arrays.asList(str). stream()).collect(toList());
}

Reduce
  1. 感覺類似遞迴
  2. 數字(字串)累加
public static void reduceTest(){
//累加,初始化值是10
Integer reduce = Stream.of(1, 2, 3, 4)
.reduce(10, (count, item) ->{
System . out . println(”count:"+count);
System . out . println(”item:" +item);
return count + item ;
} );
System. out . println(reduce);
Integer reduce1 = Stream.of(1, 2, 3, 4)
.reduce(0, (x, y) -> x + y);
System. out . println(reduce1);
String reduce2 = Stream.of ("1", "2", "3")
.reduce("e", (x, y) -> (x +",”+ y));
System. . out .println(reduce2);
}


Collect
  1. collect在流中生成列表,map,等常用的資料結構
  2. toList()
  3. toSet()
  4. toMap()
  5. 自定義
tolist
public static void tolistTest(){
List<PersonModel> data = Data. getData(); 
List<String> collect = data. stream()
.map(PersonModel: getName)
.collect(Collectors.toList());
}
/*
toSet
*/
public static void toSetTest(){
List<PersonModel> data = Data .getData();
Set<String> collect = data. stream()
. map(PersonModel: getName )
. collect(Collectors . toSet());
}
toMap
public static void toMapTest(){
List<PersonModel> data - Data . getData();
Map<String. Integery collect = data .stream()
.collect(
Collectors. toMap(PersonModel : :getName, PersonModel: getAge)
);
data. stream()
.collect(Collectors. toMap(per->per . getName(), value->{
return value+"1";
}));
}
/*
指定型別
**/
public static void toTreeSetTest(){
List<PersonModel> data = Data . getData();
TreeSet<PersonModel> collect = data.stream()
.collect (Collectors. toCollection(TreeSet: :new));
System. out . printIn(collect);
}
//分組
public static void toGroupTest(){
List<PersonModel> data = Data. getData();
Map<Boolean, ListcPersonModel>> collect = data. stream()
.col lect(Collectors.groupingBy(per ->“男" . equals(per . get<e)x))));
System. out . println(collect);
}
//分隔
public static void toJoiningTest(){
List<PersonModel> data = Data . getData();
String collect = data.stream()
.map(personModel -> personModel . getName())
.collect(Collectors .joining(",", "{", "}")); 
System.out.println(collect);
/* *
*自定義
*/
public static void reduce(){
List<String> collect - Stream.of("1", "2", "3").col1ect(
Collectors .reduc ing(new ArrayList<String>(), x -> Arrays.asList(x), (y, z) -> {
y . addAll(z); 
return y;
}));
System. out. println(collect);


Optional
  1. Optional 是為核心類庫新設計的一個數據型別,用來替換 null 值。
  2. 人們對原有的 null 值有很多抱怨,甚至連發明這一概念的Tony Hoare也是如此,他曾說這是自己的一個“價值連城的錯誤”
  3. 用處很廣,不光在lambda中,哪都能用
  4. Optional.of(T),T為非空,否則初始化報錯
  5. Optional.ofNullable(T),T為任意,可以為空
  6. isPresent(),相當於 !=null
  7. ifPresent(T), T可以是一段lambda表示式 ,或者其他程式碼,非空則執行
public static void main(String[] args) {
PersonModel personMode l=new PersonModel();
//物件為空則打出
Optional<object>。= Opt ional . of (personModel);
System. . out .println(o.ispresent()?o.get():"-"); 
//名稱為空則打出一
optional<String> name = optional . ofNullable(personModel . getName());
System.out .print In(name . isPresent()?name.get():"-");
//如果不為空,則打出xxx
Optional .ofNullable("test" ).ifPresent(na->{
System . out . println(na+" ifPresent );
});
//如果空, 則返回指定字串
System.out. println(Optional.ofNullable(nul1).orElse("-")); 
System . out . println(Optional .ofNullable("1" ).orElse("-"));
//如果空, 則返回指定方法, 或者程式碼
System .out . print ln(Optional .ofNullable(nul1) .orElseGet(()->{
return "hahah";
}));
System. . out .println(Opt ional.ofNullable("1" ).orElseGet(()->{ 
return "hahah";
}));
//如果空,則可以丟擲異常
System.out.println(Optional.ofNullable("1" ) .orElseThrow(()->{
throw new RuntimeException("ss");
})):

    
objects . requireNonNull(null,"is nul1");
//利用Optional進行多級判斷
EarthModel earthModel1 = new EarthModel(); 
//old
if (earthModel!=null){
if (earthModel1.getTea()!=nul1){
11...
}
}
/ /new
Opt ional .ofNullable(earthModel1)
.map(EarthModel::getTea)
.map(TeaModel::getType)
.isPresent();
//
Optional<EarthModel> earthModel = Optional.ofNullable(new EarthModel());
Optional<List<PersonModel>> personModels =
earthModel. map( EarthModel: :getPersonModels);
//
Optional<Stream<String>> stringStream = personModels .map(per ->
per stream( ). map(PersonModel:: getName));

    / /判斷物件 中的list
Optional .ofNullable(new EarthMode1())
. map(EarthModel: :getPersonModels)
.map(pers->pers
. stream()
. map(PersonModel: getName)
.collect(toList())) 
.ifPresent(per-> System . out .println(per));
List<PersonModel> models=Data . getData();
Opt ional .ofNullable(models)
.map(per -> per
. stream()
. map(PersonModel: :getName)
.collect(toList()))
. ifPresent(per-> System . out . println(per));
}

併發

  1. stream替換成parallelStream或 parallel
  2. 輸入流的大小並不是決定並行化是否會帶來速度提升的唯一因素,效能還會受到編寫程式碼的方式和核的數量的影響
  3. 影響效能的五要素是:資料大小、源資料結構、值是否裝箱、可用的CPU核數量,以及處理每個元素所花的時間