jdk8新特性四: jdk8Stream流操作

jdk8新特性五: jdk8Stream流操作

jdk8之流Stream

  1. Stream,中文稱爲流,通過將集合轉換爲這麼一種叫做流的元素隊列,通過聲明性方式,能夠對集合中的每個元素進行一系列並行和串行的流水線操作。
  2. 元素是特定類型的對象,所以元素集合看作一種流,流在管道中傳輸,且可以在管道的節點上進行處理。比如排序,聚合,過濾等操作。

stream流的執行順序

  1. 操作詳情:

1、數據元素便是原始集合,如list,set,map集合。

2、生成流,可以是串行流,stream()或者是並行流parallelStream()

3、中間操作:可以是排序,聚合,過濾,轉換。

4、終端操作:很多流操作本身就會返回一個流,所以多個操作可以直接連接起來,最後統一進行收集。

  1. 例子

stream().map()是將一個元素映射成另一個元素。stream是生成流,map是中間操作。

collect()是終端操作。

List<String> list=Arrays.asList("spring","abc","bcd","amd","efo");
List<String> resultList = list.stream().map(obj -> "在小d課堂學習" + obj).collect(Collectors.toList());
System.out.println(resultList);

stream中的函數

  1. map函數

1、將流中每個元素T映射爲R(類似類型轉換)

2、使用場景:在javaweb中將do對象轉成dto對象。

public static void main(String[] args) throws IOException, InterruptedException {


    List<User> list=Arrays.asList(new User(1,"小的","123"),new User(21,"小c","1234"),new User(31,"小d","1233"),
                                  new User(4,"小的m","1d23"),new User(21,"小d的","12d3"));
    List<UserDto> resultDto = list.stream().map(obj -> {
        UserDto userDto = new UserDto();
        userDto.setUserId(obj.getId());
        userDto.setUsername(obj.getName());
        return userDto;
    }).collect(Collectors.toList());

    System.out.println(resultDto);


}
  1. filter函數

1、用於通過設置的條件過濾出元素

2、例如:過濾出字符串長度大於5的字符串

List<String> list2 = Arrays.asList("springboot", "springcloud",
                                   "redis", "git", "netty", "java", "html", "docker");
List<String> resultList = list2.stream().filter(obj -> obj.length() >
                                                5).collect(Collectors.toList());
System.out.println(resultList);
  1. limit函數和sorted函數
List<String> resultList = list2.stream().sorted().collect(Collectors.toList());
List<String> resultList = list2.stream().sorted(Comparator.comparing(obj->obj.length())).collect(Collectors.toList());
List<String> resultList = list2.stream().sorted(Comparator.comparing(obj->obj.length(),Comparator.reverseOrder())).collect(Collectors.toList());
List<String> resultList = list2.stream().sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
List<String> resultList = list2.stream().sorted(Comparator.comparing(String::length)).limit(3).collect(Collectors.toList());
System.out.println(resultList);
  1. allMatch函數

檢查是否匹配所有元素,只有全部符合才返回true

List<String> list = Arrays.asList("springboot", "springcloud", "redis",
                                  "git", "netty", "java", "html", "docker");
boolean flag = list.stream().allMatch(obj->obj.length()>1);
System.out.println(flag);
  1. anyMatch函數

檢查是否至少匹配一個元素。

List<String> list = Arrays.asList("springboot", "springcloud", "redis",
                                  "git", "netty", "java", "html", "docker");
boolean flag = list.stream().anyMatch(obj->obj.length()>18);
System.out.println(flag);
  1. Max函數和Min函數,比較出最大值和最小值。

Optional是新增的類型,可以進行判空操作。

if(xxx.isPresent()){}

public static void main(String[] args) throws IOException, InterruptedException {



    List<Student> list = Arrays.asList(new Student(32),new
                                       Student(33),new Student(21),new Student(29),new Student(18));
    //list.stream().max(Comparator.comparingInt(Student::getAge));
    //最⼤
    Optional<Student> optional2 = list.stream().max((s1, s2)->
                                                    Integer.compare(s1.getAge(),s2.getAge()));
    //最⼩
    Optional<Student> optional = list.stream().min((s1, s2)->
                                                   Integer.compare(s1.getAge(),s2.getAge()));
    System.out.println(optional2.get().getAge());
    System.out.println(optional.get().getAge());

}

jdk8裏面的並行流parallelStream

  1. 集合做重複操作,如果使用串行執行,會相當耗時,因此一般會採用多線程加快,java8的paralleStream用forkjoin框架提供併發執行能力。
  2. 底層原理

線程池ForkjoinPool維護一個線程隊列

可以分割任務,將父任務拆分成子任務,完全貼合分治思想。

  1. 問題:

並行流,不一定比串行流塊,當數據量小的時候,並行流還沒把任務分出去,說不一定串行流已經執行完了。

可能會出現線程安全問題。

  1. 線程安全問題例子

ArrayList()是不安全的,會報異常。

CopyOnwriteArrayList():是安全的。上了鎖。

for(int i=0;i<10;i++) {
    List list2 = new ArrayList();
    //List list = new CopyOnWriteArrayList();
    IntStream.range(0, 100).parallel().forEach(list2::add);
    System.out.println(list2.size());
}

jdk8裏面的聚合操作reduce

  1. reduce,聚合,就是根據一定的規則將Stream中的元素進行計算後返回一個唯一的值。
int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1
                                            + item2).get();
  1. 如果不用lambda,就要使用匿名函數。
int result = Stream.of(1,2,3,4,5).reduce(new
                                         BinaryOperator<Integer>() {
                                             @Override
                                             public Integer apply(Integer item1, Integer item2) {
                                                 return item1 + item2;
                                             }
                                         }).get();
  1. 可以設置一個初始值
int value = Stream.of(1, 2, 3, 4,5).reduce(100, (sum, item) -> sum +
                                           item);
  1. 利用聚合reduce求最大值
int value = Stream.of(1645, 234345, 32,
44434,564534,435,34343542,212).reduce( (item1, item2) -> item1 >
item2 ? item1 : item2 ).get();
System.out.println(value);

jdk8的forEach集合

  1. forEach就是遍歷每一個元素,在forEach裏面進行對每一個元素進行操作。map也有這種功能。
  2. 注意點:

1、不能修改包含外部的變量的值。

2、不能用break或者return或者continue等關鍵字結束或者循環。

jdk8收集器和集合統計

  1. Collectors.collect()方法 的使用

一個終端操作,用於對流中的數據進行歸集操作,collect方法接收的參數是一個Collector

//源代碼
public static <T> Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>)
ArrayList::new, List::add,(left, right) -> {
left.addAll(right); return left; }, CH_ID);
}

ArrayList::new,創建⼀個ArrayList作爲累加器

List::add,對流中元素的操作就是直接添加到累加器中

reduce操作, 對⼦任務歸集結果addAll,後⼀個⼦任務的結果直接全部添加到

前⼀個⼦任務結果中

CH_ID 是⼀個unmodififiableSet集合

Collectors.toMap()

Collectors.toSet()

Collectors.toCollection() :⽤⾃定義的實現Collection的數據結構收集

Collectors.toCollection(LinkedList::new)

Collectors.toCollection(CopyOnWriteArrayList::new)

Collectors.toCollection(TreeSet::new)

  1. 拼接函數Collectors.joining
  • 共有三個重載方法

//3種重載⽅法

Collectors.joining()

Collectors.joining(“param”)

Collectors.joining(“param1”, “param2”, “param3”)

該⽅法可以將Stream得到⼀個字符串, joining函數接受三個參數,分別表示 元素之間的連

接符、前綴和後綴。

List<String> list=Arrays.asList("abc","bcd","cmd");
String result = list.stream().collect(Collectors.joining(","));
System.out.println(result);
  • 添加前綴和後綴
String result = Stream.of("springboot", "mysql", "html5",
                          "css3").collect(Collectors.joining(",", "[", "]"));
  1. jdk8裏面partitioningBy分組
  • Collectors.partitioningBy分組,key是boolean類型
//源碼====predicate是斷言
public static <T>
    Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super
                                                          T> predicate) {
    return partitioningBy(predicate, toList());
}
  • 需求:根據list進行分組,字符串長度大於4的爲一組,其他爲一組。
List<String> list = Arrays.asList("java", "springboot","HTML5","nodejs","CSS3");
Map<Boolean, List<String>> result =list.stream().collect(partitioningBy(obj -> obj.length() > 4));
  1. group By分組
  • Collectors.groupingBy()

  • 需求:根據學生所在的省份,進行分組

List<Student> students = Arrays.asList(new Student("⼴東", 23), new Student("⼴東", 24), new Student("⼴東", 23),new Student("北京", 22), new Student("北京", 20), new Student("北京", 20),new Student("海南", 25));
Map<String, List<Student>> listMap =students.stream().collect(Collectors.groupingBy(obj ->obj.getProvince()));
listMap.forEach((key, value) -> {
    System.out.println("========");
    System.out.println(key);
    value.forEach(obj -> {
        System.out.println(obj.getAge());
    });
});
class Student {
    private String province;
    private int age;
    public String getProvince() {
        return province;
    }
    public void setProvince(String province) {
        this.province = province;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Student(String province, int age) {
        this.age = age;
        this.province = province;
    }
}
  1. Collectors.counting()統計
  • 需求:統計各個省份的人數
List<Student> students = Arrays.asList(new Student("⼴東", 23), new Student("⼴東", 24), new Student("⼴東", 23),new Student("北京", 22), new Student("北京", 20), new Student("北京", 20),new Student("海南", 25));
Map<String, Long> listMap =students.stream().collect(Collectors.groupingBy(Student::getProvince,Collectors.counting()));
listMap.forEach((key, value) -> {System.out.println(key+"省⼈數有
                                                    "+value);});
  1. 統計平均值,最大值,最小值等。
  • Collectors.summarizing()
public static <T> Collector<T, ?, IntSummaryStatistics>
    summarizingInt(ToIntFunction<? super T> mapper) { return new
    CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
    IntSummaryStatistics::new,
    (r, t) -> r.accept(mapper.applyAsInt(t)),
    (l, r) -> { l.combine(r); return l; }, CH_ID);
                                                    }
  • 分類

summarizingInt

summarizingLong

summarizingDouble

 List<Student> students = Arrays.asList(new Student("⼴東", 23), new
Student("⼴東", 24), new Student("⼴東", 23),new Student("北京", 22), new
Student("北京", 20), new Student("北京", 20),new Student("海南", 25));
IntSummaryStatistics summaryStatistics =
students.stream().collect(Collectors.summarizingInt(Student::getAge));
System.out.println("平均值:" + summaryStatistics.getAverage());
System.out.println("⼈數:" + summaryStatistics.getCount());
System.out.println("最⼤值:" + summaryStatistics.getMax());
System.out.println("最⼩值:" + summaryStatistics.getMin());
System.out.println("總和:" + summaryStatistics.getSum());
class Student {
 private String province;
 private int age;
 public String getProvince() {
 return province;
 }
 public void setProvince(String province) {
 this.province = province;
 }
 public int getAge() {
 return age;
 }
 public void setAge(int age) {
 this.age = age;
 }
 public Student(String province, int age) {
 this.age = age;
 this.province = province;
 }
}

jdk8新內存空間Metaspace

  1. HostSpot虛擬機新增了內存空間Metaspace

  2. jdk8中的永久代被取消了。

JVM內存知識 在JDK8之前的HotSpot JVM,有個區域叫做“永久代(permanent generation), 通過
在命令⾏設置參數-XX:MaxPermSize來設定永久代最⼤可分配的內存空間
如果JDK8⾥⾯設置了PermSize 和 MaxPermSize 會被忽略並給出警告

  1. 永久代的作用

該塊內存主要是被JVM⽤來存放 class 和 mate 信息的,當 class 被加載 loader 的時候就會

被存儲到該內存區中,如⽅法的編譯信息及字節碼、常量池和符號解析、類的層級信息,字段,名

字等

永久代空間不夠,類信息太多,會報oom

  1. jdk8的處理

jdk8的修改 JDK8 HotSpot JVM 使⽤本地內存來存儲類元數據信息,叫做 元空間(Metaspace)

在默認情況下Metaspace的⼤⼩只與本地內存⼤⼩有關

常⽤的兩個參數 -XX:MetaspaceSize=N 指Metaspace擴容時觸發FullGC的初始化閾值

-XX:MaxMetaspaceSize=N 指⽤於限制Metaspace增⻓的上限,防⽌因爲某些情況導致

Metaspace⽆限的使⽤本地內存

不管兩個參數如何設置,都會從20.8M開始,然後隨着類加載越來越多不斷擴容調整直到最⼤

  1. 查看Metaspace大小命令

jstat -gc pid MC: current metaspace capacity MU: mateaspace utilization

MC:Metaspace的容量空間

MU:Metaspace的已經使用空間。

jdk7裏面的新特性try-with-resources

  1. 在try( …)⾥聲明的資源,會在try-catch代碼塊結束後⾃動關閉掉
  2. 舊的寫法
public static void main(String[] args) throws IOException {
    String path = "/Users/jack/Desktop/t.txt";
    test(path);
}
private static void test(String filepath) throws FileNotFoundException {
    OutputStream out = new FileOutputStream(filepath);
    try {
        out.write((filepath+"可以學習java架構課程").getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  1. 新的寫法
private static void test(String filepath){
    try(OutputStream out = new FileOutputStream(filepath);) {
        out.write((filepath+"可以學習java架構課程").getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  1. 注意點

1、實現了AutoCloseable接⼝的類,在try()⾥聲明該類實例的時候,try結束後⾃動調⽤的
close⽅法,這個動作會早於finally⾥調⽤的⽅法
2、不管是否出現異常,try()⾥的實例都會被調⽤close⽅法

3、try⾥⾯可以聲明多個⾃動關閉的對象,越早聲明的對象,會越晚被close掉

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章