compute
V compute(K key, BiFunction < ? super K, ? super V, ? extends V> remappingFunction)
指定的key在map中的值進行操作,不管存不存在,操作完成後儲存到map中
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("1",1);
map.put("2",2);
map.compute("1", (k,v)-> {
System.out.println("key = " + k + ", value = " + v);
if (v != null) {
return v+1;
} else {
return 0;
}
});
map.compute("3", (k,v)->{
System.out.println("key = " + k + ", value = " + v);
if (v != null) {
return v+1;
} else {
return 0;
}
});
System.out.println(map.toString());
}
控制檯列印
key = 1, value = 1
key = 3, value = null
{1=2, 2=2, 3=0}
computeIfAbsent
V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
computeIfAbsent的方法有兩個引數 第一個是所選map的key,第二個是需要做的操作。這個方法當key值不存在時才起作用。
當key存在返回當前value值,不存在執行函式並儲存到map中。
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("1",1);
map.put("2",2);
// key存在返回value
Integer integer1 = map.computeIfAbsent("2", key -> new Integer(10));
// key不存在執行函式存入
Integer integer2 = map.computeIfAbsent("3", key -> new Integer(20));
System.out.println("integer1 = " + integer1);
System.out.println("integer2 = " + integer2);
System.out.println(map.toString());
}
控制檯列印
integer1 = 2
integer2 = 20
{1=1, 2=2, 3=20}
computeIfPresent
V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
對指定的 在map中已經存在的key的value進行操作。只對已經存在key的進行操作,其他不操作
public static void main(String[] args) {
HashMap<String,Integer> map = new HashMap<>();
map.put("1",1);
map.put("2",2);
map.put("3",3);
// 只對 map 中存在的key對應的value進行操作
Integer integer1 = map.computeIfPresent("3", (k,v) -> {
System.out.println("key = " + k + ", value = " + v);
return v+1;
});
Integer integer2 = map.computeIfPresent("4", (k,v) -> {
System.out.println("key = " + k + ", value = " + v);
return v+1;
} );
System.out.println("integer1 = " + integer1);
System.out.println("integer2 = " + integer2);
System.out.println(map.toString());
}
控制檯列印
key = 3, value = 3
integer1 = 4
integer2 = null
{1=1, 2=2, 3=4}
of(T value)
Student student = new Student();
// 如果 student 為 null,則會丟擲NullPointerException
// 適用於 student 不為空的情況
Optional<Student> opt = Optional.of(student);
ofNullable(T value)
Student student = new Student();
// student 為 null 時不會報錯
Optional<User> opt = Optional.ofNullable(user);
// 若 student 不為空,則返回true,否則返回false
System.out.println(opt.isPresent());
獲取物件值
Student student = new Student();
// student 為 null 時不會報錯
Optional<User> opt = Optional.ofNullable(user);
// 若 student 不為空,則返回true,否則返回false
System.out.println(opt.isPresent());
// 若 student 為 null, opt.get() 會報錯
// 若 student 不為null,則返回物件值
System.out.println(opt.get());
檢查是否有值的另一個選擇是 ifPresent() 方法。該方法除了執行檢查,還接受一個Consumer(消費者) 引數,如果物件不是空的,就對執行傳入的 Lambda 表示式。
Student student = new Student();
Optional<Student> opt = Optional.ofNullable(student);
// 只有當 student 不為空時才會執行 ifPresent 方法裡面的表示式
opt.ifPresent(u -> {
System.out.println("username = " + u.getUsername());
});
返回預設值
orElse(T other)
Student student1 = null;
Student student2 = new Student();
student2.setUsername("lizhencheng");
Student optStudent = Optional.ofNullable(student1).orElse(student2);
System.out.println(optStudent.getUsername());
這裡 student1物件是空的,所以返回了作為預設值的 student2。
如果物件的初始值不是 null,那麼預設值會被忽略:
Student student1 = new Student();
student1.setUsername("lzc");
Student student2 = new Student();
student2.setUsername("lizhencheng");
Student optStudent = Optional.ofNullable(student1).orElse(student2);
System.out.println(optStudent.getUsername());
orElseGet(Supplier<? extends T> other)
這個方法會在有值的時候返回值,如果沒有值,它會執行作為引數傳入的 Supplier(供應者) 函式式介面,並將返回其執行結果:
Student student1 = new Student();
student1.setUsername("lzc");
Student optStudent = Optional.ofNullable(student1).orElseGet(()->{
Student student2 = new Student();
student2.setUsername("lizhencheng");
return student2;
});
// 如果 student1 為 null,控制檯則列印 "lzc" ,否則列印 "lizhencheng"
System.out.println(optStudent.getUsername());
orElse() 和 orElseGet() 的不同之處
public class Main {
public static void main(String[] args) {
Student student1 = new Student();
student1.setUsername("lzc");
System.out.println("orElse......");
Student optStudent1 = Optional.ofNullable(student1).orElse(createNewStudent());
System.out.println("orElseGet......");
Student optStudent2 = Optional.ofNullable(student1).orElseGet(()-> createNewStudent());
System.out.println(optStudent1.getUsername());
System.out.println(optStudent2.getUsername());
}
public static Student createNewStudent() {
System.out.println("createNewStudent......");
Student student = new Student();
student.setUsername("lizhencheng");
return student;
}
}
控制檯列印結果
orElse......
createNewStudent......
orElseGet......
lzc
lzc
這個示例中,兩個 Optional 物件都包含非空值,兩個方法都會返回對應的非空值。不過,orElse() 方法仍然建立了 User 物件。與之相反,orElseGet() 方法不建立 User 物件。在執行較密集的呼叫時,比如呼叫 Web 服務或資料查詢,這個差異會對效能產生重大影響。
返回異常
Student student = null;
Student optStudent = Optional.ofNullable(student).orElseThrow(() -> new IllegalArgumentException("引數不能為空"));
如果 student值為 null,會丟擲 IllegalArgumentException。
這個方法讓我們有更豐富的語義,可以決定丟擲什麼樣的異常,而不總是丟擲 NullPointerException。
轉換值
Student student = new Student("lzc","1班");
String str = Optional
.ofNullable(student)
.map(s -> s.getUsername())
.orElse("lizhencheng");
System.out.println(str);
過濾值
Student student = new Student("lzc","1班");
Optional<Student> temp = Optional
.ofNullable(student)
.filter(s -> s.getUsername() != null && s.getUsername().length() >= 3);
System.out.println(temp.isPresent());
forEach
default void forEach(Consumer<? super T> action)
遍歷列表元素
List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
list.forEach(s -> System.out.println(s));
filter
Stream<T> filter(Predicate<? super T> predicate)
List<String> list = new ArrayList<>();
list.add("123");
list.add("456789");
List<String> resultList = list
.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s));
Collectors.toList()可以把流轉換為 List 型別或者是Set型別
distinct
Stream<T> distinct()
去除重複元素,這個方法是透過類的 equals 方法來判斷兩個元素是否相等的
List<String> list = new ArrayList<>();
list.add("123");
list.add("123");
list.add("456789");
List<String> resultList = list
.stream()
.distinct()
.collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s));
sorted
Stream<T> sorted()
Stream<T> sorted(Comparator<? super T> comparator)
如果流中的元素的類實現了 Comparable 介面,即有自己的排序規則,那麼可以直接呼叫 sorted() 方法對元素進行排序。
方法一
List<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",16));
list.add(new Student("lisi",20));
list.add(new Student("wangwu",18));
List<Student> resultList = list
.stream()
.sorted((s1,s2) -> s1.getAge() - s2.getAge())
.collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s.toString()));
方法二
List<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",16));
list.add(new Student("lisi",20));
list.add(new Student("wangwu",18));
List<Student> resultList = list
.stream()
//.sorted(Comparator.comparing(Student::getAge)) // 升序
.sorted(Comparator.comparing(Student::getAge).reversed()) // 降序
.collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s.toString()));
limit
Stream<T> limit(long maxSize)
返回前 n 個元素
List<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",16));
list.add(new Student("lisi",20));
list.add(new Student("wangwu",18));
List<Student> resultList = list
.stream()
.limit(2)
.collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s.toString()));
skip
Stream<T> skip(long n)
去除前 n 個元素
List<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",16));
list.add(new Student("lisi",20));
list.add(new Student("wangwu",18));
List<Student> resultList = list
.stream()
.skip(2)
.collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s.toString()));
map
<R> Stream<R> map(Function<? super T, ? extends R> mapper)
將流中的每一個元素 T 對映為 R(類似型別轉換)
List<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",16));
list.add(new Student("lisi",20));
list.add(new Student("wangwu",18));
List<String> resultList = list
.stream()
.map(s -> {
String username = s.getUsername();
return username;
}).collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s.toString()));
flatMap
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
將流中的每一個元素 T 對映為一個流,再把每一個流連線成為一個流
List<String> list = new ArrayList<>();
list.add("aaa bbb ccc");
list.add("ddd eee fff");
list.add("ggg hhh iii");
List<String> resultList = list
.stream()
.map(s -> s.split(" "))
.flatMap(Arrays::stream).collect(Collectors.toList());
resultList.stream().forEach(s -> System.out.println(s));
上面例子中,我們的目的是把 List 中每個字串元素以” “分割開,變成一個新的 List。
首先 map 方法分割每個字串元素,但此時流的型別為 Stream<String[ ]>,因為 split 方法返回的是 String[ ] 型別;所以我們需要使用 flatMap 方法,先使用Arrays::stream將每個 String[ ] 元素變成一個 Stream 流,然後 flatMap 會將每一個流連線成為一個流,最終返回我們需要的 Stream。
anyMatch
boolean anyMatch(Predicate<? super T> predicate)
流中是否有一個元素匹配給定的 T -> boolean
條件
List<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",16));
list.add(new Student("lisi",20));
list.add(new Student("wangwu",18));
// 是否存在一個 Student 物件的 age >= 20
boolean b = list.stream().anyMatch(s -> s.getAge() >= 20);
System.out.println(b);
allMatch
boolean allMatch(Predicate<? super T> predicate)
流中是否所有元素都匹配給定的 T -> boolean
條件
collect
<R, A> R collect(Collector<? super T, A, R> collector)
joining
joining 連線字串
對流裡面的字串元素進行連線
List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
list.add("789");
String collect = list.stream().collect(Collectors.joining(","));
System.out.println(collect);
toList/toSet
toList或者toSet,將資料流轉換成List型別或者是Set型別
List<String> list = new ArrayList<>();
list.add("123");
list.add("456789");
List<String> resultList = list
.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
resultList.forEach(s -> System.out.println(s));
groupingBy
groupingBy 用於將資料分組,最終返回一個 Map 型別
List<Student> list = new ArrayList<>();
list.add(new Student("zhangsan",16));
list.add(new Student("lisi",2));
list.add(new Student("lzc",18));
list.add(new Student("xiaohong",1));
list.add(new Student("xiaoming",18));
list.add(new Student("lili",2));
Map<Integer, List<Student>> collect =
list.stream()
// .collect(Collectors.groupingBy(Student::getAge)); // 這樣是無序的
// .collect(Collectors.groupingBy(Student::getAge, TreeMap::new,Collectors.toList())); // 升序
.collect(Collectors.groupingBy(Student::getAge, (() -> new TreeMap().descendingMap()),Collectors.toList())); // 降序
for (Integer key : collect.keySet()) {
List<Student> students = collect.get(key);
System.out.println("age = " + key);
students.forEach(s -> System.out.println(s.toString()));
}
groupingBy 可以接受一個第二引數實現多級分組:
Map<Integer, Map<String, List<Student>>> collect =
list.stream()
.collect(
Collectors.groupingBy(
Student::getAge,
Collectors.groupingBy(Student::getUsername)
)
);
收集資料
list.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.summingInt(Student::getAge)));
partitioningBy
Map<Boolean, List<Student>> collect = list.stream().collect(Collectors.partitioningBy(s -> s.getAge() > 1));
partitioningBy 也可以新增一個收集器作為第二引數,進行類似 groupBy 的多重分割槽等等操作。
本作品採用《CC 協議》,轉載必須註明作者和本文連結