jdk8新特性五: jdk8Stream流操作
文章目錄
jdk8之流Stream
- Stream,中文稱爲流,通過將集合轉換爲這麼一種叫做流的元素隊列,通過聲明性方式,能夠對集合中的每個元素進行一系列並行和串行的流水線操作。
- 元素是特定類型的對象,所以元素集合看作一種流,流在管道中傳輸,且可以在管道的節點上進行處理。比如排序,聚合,過濾等操作。
- 操作詳情:
1、數據元素便是原始集合,如list,set,map集合。
2、生成流,可以是串行流,stream()或者是並行流parallelStream()
3、中間操作:可以是排序,聚合,過濾,轉換。
4、終端操作:很多流操作本身就會返回一個流,所以多個操作可以直接連接起來,最後統一進行收集。
- 例子
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中的函數
- 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);
}
- 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);
- 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);
- 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);
- 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);
- 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
- 集合做重複操作,如果使用串行執行,會相當耗時,因此一般會採用多線程加快,java8的paralleStream用forkjoin框架提供併發執行能力。
- 底層原理
線程池ForkjoinPool維護一個線程隊列
可以分割任務,將父任務拆分成子任務,完全貼合分治思想。
- 問題:
並行流,不一定比串行流塊,當數據量小的時候,並行流還沒把任務分出去,說不一定串行流已經執行完了。
可能會出現線程安全問題。
- 線程安全問題例子
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
- reduce,聚合,就是根據一定的規則將Stream中的元素進行計算後返回一個唯一的值。
int value = Stream.of(1, 2, 3, 4, 5).reduce((item1, item2) -> item1
+ item2).get();
- 如果不用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();
- 可以設置一個初始值
int value = Stream.of(1, 2, 3, 4,5).reduce(100, (sum, item) -> sum +
item);
- 利用聚合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集合
- forEach就是遍歷每一個元素,在forEach裏面進行對每一個元素進行操作。map也有這種功能。
- 注意點:
1、不能修改包含外部的變量的值。
2、不能用break或者return或者continue等關鍵字結束或者循環。
jdk8收集器和集合統計
- 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)
- 拼接函數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(",", "[", "]"));
- 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));
- 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;
}
}
- 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);});
- 統計平均值,最大值,最小值等。
- 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
-
HostSpot虛擬機新增了內存空間Metaspace
-
jdk8中的永久代被取消了。
JVM內存知識 在JDK8之前的HotSpot JVM,有個區域叫做“永久代(permanent generation), 通過
在命令⾏設置參數-XX:MaxPermSize來設定永久代最⼤可分配的內存空間
如果JDK8⾥⾯設置了PermSize 和 MaxPermSize 會被忽略並給出警告
- 永久代的作用
該塊內存主要是被JVM⽤來存放 class 和 mate 信息的,當 class 被加載 loader 的時候就會
被存儲到該內存區中,如⽅法的編譯信息及字節碼、常量池和符號解析、類的層級信息,字段,名
字等
永久代空間不夠,類信息太多,會報oom
- jdk8的處理
jdk8的修改 JDK8 HotSpot JVM 使⽤本地內存來存儲類元數據信息,叫做 元空間(Metaspace)
在默認情況下Metaspace的⼤⼩只與本地內存⼤⼩有關
常⽤的兩個參數 -XX:MetaspaceSize=N 指Metaspace擴容時觸發FullGC的初始化閾值
-XX:MaxMetaspaceSize=N 指⽤於限制Metaspace增⻓的上限,防⽌因爲某些情況導致
Metaspace⽆限的使⽤本地內存
不管兩個參數如何設置,都會從20.8M開始,然後隨着類加載越來越多不斷擴容調整直到最⼤
- 查看Metaspace大小命令
jstat -gc pid MC: current metaspace capacity MU: mateaspace utilization
MC:Metaspace的容量空間
MU:Metaspace的已經使用空間。
jdk7裏面的新特性try-with-resources
- 在try( …)⾥聲明的資源,會在try-catch代碼塊結束後⾃動關閉掉
- 舊的寫法
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();
}
}
}
- 新的寫法
private static void test(String filepath){
try(OutputStream out = new FileOutputStream(filepath);) {
out.write((filepath+"可以學習java架構課程").getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
- 注意點
1、實現了AutoCloseable接⼝的類,在try()⾥聲明該類實例的時候,try結束後⾃動調⽤的
close⽅法,這個動作會早於finally⾥調⽤的⽅法
2、不管是否出現異常,try()⾥的實例都會被調⽤close⽅法3、try⾥⾯可以聲明多個⾃動關閉的對象,越早聲明的對象,會越晚被close掉