Java8 Add some useful methods to the container , Some of these methods are to improve the original function , Some are for the introduction of functional programming (Lambda expression ), Learning and using these methods will help us write more concise and effective code . This article uses ArrayList and HashMap For example , Explain Java8 Collections framework (Java Collections Framework) The use of the new addition method in .
Define the object :
public class Apple {
private Integer id;
private String name;
private BigDecimal money;
private Integer num;
public Apple(Integer id, String name, BigDecimal money, Integer num) {
this.id = id;
this.name = name;
this.money = money;
this.num = num;
}
}
Test data
List<Apple> appleList = new ArrayList<>();// Deposit apple A collection of objects
Apple apple1 = new Apple(1," Apple 1",new BigDecimal("3.25"),10);
Apple apple12 = new Apple(1," Apple 2",new BigDecimal("1.35"),20);
Apple apple2 = new Apple(2," Banana ",new BigDecimal("2.89"),30);
Apple apple3 = new Apple(3," litchi ",new BigDecimal("9.99"),40);
appleList.add(apple1);
appleList.add(apple12);
appleList.add(apple2);
appleList.add(apple3);
1、 grouping
List The object element inside , To group by an attribute , for example , With id grouping , take id Put the same together :
//List With ID grouping Map<Integer,List<Apple>>
Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId));
System.err.println("groupBy:"+groupBy);
{1=[Apple{id=1, name=' Apple 1', money=3.25, num=10}, Apple{id=1, name=' Apple 2', money=1.35, num=20}], 2=[Apple{id=2, name=' Banana ', money=2.89, num=30}], 3=[Apple{id=3, name=' litchi ', money=9.99, num=40}]}
2、List turn Map
id by key,apple The object is value
/**
* List -> Map
* It should be noted that :
* toMap If the collection object has duplicate key, Will report a mistake Duplicate key ....
* apple1,apple12 Of id All for 1.
* It can be used (k1,k2)->k1 To set up , If there are duplicates key, The retention key1, Abandon key2
*/
Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));
Print :
{1=Apple{id=1, name=' Apple 1', money=3.25, num=10}, 2=Apple{id=2, name=' Banana ', money=2.89, num=30}, 3=Apple{id=3, name=' litchi ', money=9.99, num=40}}
List turn Map Press key duplicate removal repeat key Value processing
Map<String, ObjectBasicBO> result =
Optional.ofNullable(list).get().stream().collect(
Collectors.toMap(ObjectBasicBO::getValue, Function.identity(), (old, key2) -> key2));
List duplicate removal
data :
BookBo bookBo1 = new BookBo("1", " Chinese language and literature ");
BookBo bookBo2 = new BookBo("2", " mathematics ");
BookBo bookBo3 = new BookBo("3", " English ");
BookBo bookBo4 = new BookBo("4", " Geography ");
BookBo bookBo5 = new BookBo("5", " biological ");
BookBo bookBo6 = new BookBo("1", " Chinese language and literature ");
List<BookBo> bookBoList = Arrays.asList(bookBo1, bookBo2, bookBo3, bookBo4, bookBo5, bookBo6);
List<BookBo> distinctList = bookBoList
//collectingAndThen Collect and then in
.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(o-> o.getName()))), ArrayList::new))
.stream().sorted(Comparator.comparing(BookBo::getName)).collect(Collectors.toList());
3、 Filter Filter
Filter out the qualified elements from the collection :
// Filter out qualified data
List<Apple> filterList = appleList.stream().filter(a -> a.getName().equals(" Banana ")).collect(Collectors.toList());
System.err.println("filterList:"+filterList);
[Apple{id=2, name=' Banana ', money=2.89, num=30}]
4. Sum up
Sum the data in the set according to a certain attribute :
// Calculation Total sum
BigDecimal totalMoney = appleList.stream().map(Apple::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
System.err.println("totalMoney:"+totalMoney); //totalMoney:17.48
5. Find the largest… In the stream minimum value
Collectors.maxBy and Collectors.minBy To calculate the maximum or minimum value in the flow .
Optional<Dish> maxDish = Dish.menu.stream().
collect(Collectors.maxBy(Comparator.comparing(Dish::getCalories)));
maxDish.ifPresent(System.out::println);
Optional<Dish> minDish = Dish.menu.stream().
collect(Collectors.minBy(Comparator.comparing(Dish::getCalories)));
minDish.ifPresent(System.out::println);
6. duplicate removal
import static java.util.Comparator.comparingLong;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;
// according to id duplicate removal
List<Person> unique = appleList.stream().collect(
collectingAndThen(
toCollection(() -> new TreeSet<>(comparingLong(Apple::getId))), ArrayList::new)
);
Multi field splicing and de duplication
List<ClassEntity> distinctClass = classEntities.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getProfessionId() + ";" + o.getGrade()))), ArrayList::new));
=============================== The concept is as follows ==========================================
Preface
Let’s start with the most familiar Java Collections framework (Java Collections Framework, JCF) Start talking about .
For introduction Lambda expression ,Java8 Added java.util.funcion
package , It contains commonly used The function interface , This is a Lambda The basis of expression ,Java The collection framework also adds some interfaces , So as to meet with Lambda Expression docking .
First, let’s review Java The interface inheritance structure of the collection framework :
The interface class marked in green in the figure above , It means that Java8 A new interface method has been added , Of course, because of inheritance , Their corresponding subclasses will also inherit these new methods . The following table details these methods .
The interface name | Java8 New ways to join |
---|---|
Collection | removeIf() spliterator() stream() parallelStream() forEach() |
List | replaceAll() sort() |
Map | getOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge() |
Most of these new methods will use java.util.function
The interface under the package , This means that most of these methods follow Lambda Expression related . We will learn these methods one by one .
Collection The new method in
As shown above , Interface Collection
and List
Some new methods have been added , We are List
Subclasses of ArrayList
For example . understand Java7ArrayList
Realization principle , It will help to understand .
forEach()
The method is signed as void forEach(Consumer<? super E> action)
, The purpose is to execute… On each element in the container action
The designated action , among Consumer
It’s a function interface , There is only one method to be implemented void accept(T t)
( We’ll see that later , It doesn’t matter what this method is called , You don’t even need to remember its name ).
demand : Suppose you have a list of strings , You need to print out all of them that are longer than 3 String .
Java7 And before we could use enhanced for Cycle to achieve :
// Use Zeng Qiang for Loop iteration
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
for(String str : list){
if(str.length()>3)
System.out.println(str);
}
Now use forEach()
Method combined with anonymous inner class , It can be realized in this way :
// Use forEach() Combined with anonymous inner class iteration
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.forEach(new Consumer<String>(){
@Override
public void accept(String str){
if(str.length()>3)
System.out.println(str);
}
});
The above code calls forEach()
Method , And use anonymous inner class to implement Comsumer
Interface . So far we haven’t seen the benefits of this design , But don’t forget Lambda expression , Use Lambda The expression is implemented as follows :
// Use forEach() combination Lambda Expression iteration
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.forEach( str -> {
if(str.length()>3)
System.out.println(str);
});
The above code is for forEach()
Method passes in a Lambda expression , We don’t need to know accept()
Method , I don’t need to know Consumer
Interface , Type derivation helps us do everything .
removeIf()
The signature of this method is boolean removeIf(Predicate<? super E> filter)
, Role is Delete all satisfied… In the container filter
The element that specifies the condition , among Predicate
It’s a function interface , There is only one method to be implemented boolean test(T t)
, The name of the same method doesn’t matter at all , Because you don’t need to write the name .
demand : Suppose you have a list of strings , You need to delete all of them that are longer than 3 String .
We know that if we need to delete the container in the iterative process, we must use the iterator , Otherwise it will throw ConcurrentModificationException
, So the traditional way to write these tasks is :
// Use iterators to delete list elements
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
Iterator<String> it = list.iterator();
while(it.hasNext()){
if(it.next().length()>3) // Delete length greater than 3 The elements of
it.remove();
}
Now use removeIf()
Method combined with anonymous inner class , This is how we achieve :
// Use removeIf() Combined with anonymous name inner class implementation
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.removeIf(new Predicate<String>(){ // Delete length greater than 3 The elements of
@Override
public boolean test(String str){
return str.length()>3;
}
});
The above code uses removeIf()
Method , And use anonymous inner class to implement Precicate
Interface . I believe you have thought of using Lambda How should expressions be written :
// Use removeIf() combination Lambda Expression implementation
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.removeIf(str -> str.length()>3); // Delete length greater than 3 The elements of
Use Lambda Expressions don’t need to be memorized Predicate
The interface name , There is no need to remember test()
Method name , Just know that there needs to be a return Boolean type Lambda Just expressions .
replaceAll()
The signature of this method is void replaceAll(UnaryOperator<E> operator)
, Role is Execution of each element operator
Specified operation , And replace the original element with the result of the operation . among UnaryOperator
It’s a function interface , There is only one function to be implemented T apply(T t)
.
demand : Suppose you have a list of strings , Make all of them longer than 3 The elements of are converted to uppercase , The rest of the elements remain the same .
Java7 Before that, there seems to be no elegant way :
// Use subscripts to implement element substitution
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
for(int i=0; i<list.size(); i++){
String str = list.get(i);
if(str.length()>3)
list.set(i, str.toUpperCase());
}
Use replaceAll()
Methods combined with anonymous inner classes can be implemented as follows :
// Use anonymous inner class to implement
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.replaceAll(new UnaryOperator<String>(){
@Override
public String apply(String str){
if(str.length()>3)
return str.toUpperCase();
return str;
}
});
The above code calls replaceAll()
Method , And use anonymous inner class to implement UnaryOperator
Interface . We know that we can use a simpler Lambda Expression implementation :
// Use Lambda Expression implementation
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.replaceAll(str -> {
if(str.length()>3)
return str.toUpperCase();
return str;
});
sort()
The method is defined in List
Interface , Method signature is void sort(Comparator<? super E> c)
, The method according to c
The specified comparison rules sort the container elements .Comparator
We are not new to interface , There’s a way int compare(T o1, T o2)
Need to achieve , Obviously this interface is a function interface .
demand : Suppose you have a list of strings , Sort elements by increasing string length .
because Java7 And before sort()
Method in Collections
In the tool class , So the code should be written like this :
// Collections.sort() Method
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
Collections.sort(list, new Comparator<String>(){
@Override
public int compare(String str1, String str2){
return str1.length()-str2.length();
}
});
Now it can be used directly List.sort() Method
, combination Lambda expression , It can be written like this :
// List.sort() Method combination Lambda expression
ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
list.sort((str1, str2) -> str1.length()-str2.length());
spliterator()
Method signature is Spliterator<E> spliterator()
, This method returns the… Of the container Separable iterators . From the point of view of name, this method follows iterator()
It’s a little like that , We know Iterator
It’s used to iterate over containers ,Spliterator
It has a similar effect , But they are different :
Spliterator
It can be likeIterator
So iterate one by one , You can also iterate in batches . Batch iteration can reduce the cost of iteration .Spliterator
It’s separable , OneSpliterator
You can callSpliterator<T> trySplit()
Try to divide it into two . One isthis
, The other is the newly returned one , The two iterators represent elements that do not overlap .
It can be done by ( many times ) call Spliterator.trySplit()
Method to break down the load , For multithreading .
stream() and parallelStream()
stream()
and parallelStream()
, respectively, Return… Of the container Stream
View representation , The difference is parallelStream()
Return to parallel Stream
.Stream
yes Java The core class of functional programming , We’ll learn about .
Map The new method in
comparison Collection
,Map
There are more ways , We use HashMap
For example, to explore one by one . understand Java7HashMap
Realization principle , It will help to understand .
forEach()
The signature of this method is void forEach(BiConsumer<? super K,? super V> action)
, Role is Yes Map
Execution of each map in action
Specified operation , among BiConsumer
It’s a function interface , There’s a way to do it void accept(T t, U u)
.BinConsumer
Interface name and accept()
Method names don’t matter , Please don’t remember them .
demand : Let’s say that there is a number to Map, Please export Map All mapping relationships in .
Java7 And the previous classic code is as follows :
// Java7 And previous iterations Map
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
for(Map.Entry<Integer, String> entry : map.entrySet()){
System.out.println(entry.getKey() + "=" + entry.getValue());
}
Use Map.forEach()
Method , Combine anonymous inner classes , The code is as follows :
// Use forEach() Combined with anonymous inner class iteration Map
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.forEach(new BiConsumer<Integer, String>(){
@Override
public void accept(Integer k, String v){
System.out.println(k + "=" + v);
}
});
The above code calls forEach()
Method , And use anonymous inner class to implement BiConsumer
Interface . Of course , In the actual scenario, no one uses anonymous inner class writing , Because there is Lambda expression :
// Use forEach() combination Lambda Expression iteration Map
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.forEach((k, v) -> System.out.println(k + "=" + v));
}
getOrDefault()
This method follows Lambda Expressions don’t matter , But it’s useful . Method signature is V getOrDefault(Object key, V defaultValue)
, Role is According to the given key
Inquire about Map
Corresponding value
, Return if not found defaultValue
. Using this method, the programmer can save the trouble of querying whether the specified key value exists .
demand ; Let’s say that there is a number to Map, Output 4 Corresponding English words , If not, output NoValue
// Inquire about Map The value specified in , Use the default when it doesn't exist
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
// Java7 And what we did before
if(map.containsKey(4)){ // 1
System.out.println(map.get(4));
}else{
System.out.println("NoValue");
}
// Java8 Use Map.getOrDefault()
System.out.println(map.getOrDefault(4, "NoValue")); // 2
putIfAbsent()
This method follows Lambda Expressions don’t matter , But it’s useful . Method signature is V putIfAbsent(K key, V value)
, The function is only in non-existent key
The mapping or mapping value of a value is null
when , Only then value
The specified value is put into Map
in , Otherwise it’s not right Map
Make changes . This method combines condition judgment with assignment , More convenient to use .
remove()
We all know Map
There is one of them. remove(Object key)
Method , According to the designation key
Value delete Map
Mapping relationship in ;Java8 Added remove(Object key, Object value)
Method , Only in the present Map
in key
It just maps to value
when Delete the map , Otherwise, do nothing .
replace()
stay Java7 And before , If you want to replace Map
The mapping relationship in can be obtained by put(K key, V value)
Method realization , This method always replaces the original value with a new value . In order to control the replacement behavior more precisely ,Java8 stay Map
Two of them replace()
Method , They are as follows :
replace(K key, V value)
, Only in the presentMap
inkey
When the mapping of exists Only usevalue
To replace the original value , Otherwise, do nothing .replace(K key, V oldValue, V newValue)
, Only in the presentMap
inkey
The mapping of exists and is equal tooldValue
when Only usenewValue
To replace the original value , Otherwise, do nothing .
replaceAll()
The signature of this method is replaceAll(BiFunction<? super K,? super V,? extends V> function)
, The effect is right. Map
Execution of each map in function
Specified operation , And use function
Replace the original value
, among BiFunction
It’s a function interface , There’s a way to do it R apply(T t, U u)
. Don’t be intimidated by so many function interfaces , Because we don’t need to know their names when we use them .
demand : Let’s say that there is a number to Map, Please convert the words in the original mapping relationship to uppercase .
Java7 And the previous classic code is as follows :
// Java7 And replace all of Map All mapping relationships in
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
for(Map.Entry<Integer, String> entry : map.entrySet()){
entry.setValue(entry.getValue().toUpperCase());
}
Use replaceAll()
Method combined with anonymous inner class , The implementation is as follows :
// Use replaceAll() Combined with anonymous inner class
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.replaceAll(new BiFunction<Integer, String, String>(){
@Override
public String apply(Integer k, String v){
return v.toUpperCase();
}
});
The above code calls replaceAll()
Method , And use anonymous inner class to implement BiFunction
Interface . further , Use Lambda The expression is implemented as follows :
// Use replaceAll() combination Lambda Expression implementation
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.replaceAll((k, v) -> v.toUpperCase());
It’s incredibly simple .
merge()
The signature of this method is merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
, Role is :
- If
Map
inkey
The mapping does not exist or isnull
, Willvalue
( It can’t benull
) Related tokey
On ; - Otherwise execution
remappingFunction
, If the execution result is notnull
Then use the result withkey
relation , Otherwise, in theMap
Delete inkey
Mapping .
Parameters in BiFunction
The function interface has been introduced before , There’s a way to do it R apply(T t, U u)
.
merge()
Although the semantics of methods are somewhat complicated , But the way it’s used is clear , A common scenario is to splice new error information onto the original information , such as :
map.merge(key, newMsg, (v1, v2) -> v1+v2);
compute()
The signature of this method is compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
, The effect is to turn remappingFunction
The results of the calculation are related to key
On , If the result is null
, It’s in Map
Delete in key
Mapping .
To achieve the above merge()
An example of error information splicing in the method , Use compute()
The code is as follows :
map.compute(key, (k,v) -> v==null ? newMsg : v.concat(newMsg));
computeIfAbsent()
The signature of this method is V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
, Role is : Only in the present Map
in non-existent key
The mapping or mapping value of a value is null
when , Only called mappingFunction
, And in mappingFunction
The execution result is not null
when , Follow the result with key
relation .
Function
It’s a function interface , There’s a way to do it R apply(T t)
.
computeIfAbsent()
Often used to Map
One of the key
Value to create an initialization map . For example, we need to implement a multivalued mapping ,Map
The definition of may be Map<K,Set<V>>
, Want to Map
Put the new value , It can be realized by the following code :
Map<Integer, Set<String>> map = new HashMap<>();
// Java7 And previous implementations
if(map.containsKey(1)){
map.get(1).add("one");
}else{
Set<String> valueSet = new HashSet<String>();
valueSet.add("one");
map.put(1, valueSet);
}
// Java8 How to implement
map.computeIfAbsent(1, v -> new HashSet<String>()).add("yi");
Use computeIfAbsent()
Combine condition judgment with addition operation , Make the code more concise .
computeIfPresent()
The signature of this method is V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
, Action follows computeIfAbsent()
contrary , namely , Only in the present Map
in There is key
The mapping of values is not null
when , Only called remappingFunction
, If remappingFunction
The execution result is null
, Delete key
Mapping , Otherwise use this result to replace key
The original mapping .
The function of this function is equivalent to the following code :
// Java7 And before computeIfPresent() Equivalent code
if (map.get(key) != null) {
V oldValue = map.get(key);
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null)
map.put(key, newValue);
else
map.remove(key);
return newValue;
}
return null;
summary
- Java8 Add some useful methods to the container , Some of these methods are for Perfect the original function , Some are for Introduce functional programming , Learning and using these methods will help us write more concise and effective code .
- The function interface Though many , But most of the time we don’t need to know their names at all , Writing Lambda Expression time type inference helps us do everything .
this paper github Address
https://github.com/CarpenterLee
https://github.com/CarpenterLee/JavaLambdaInternals
Reference resources :
https://blog.csdn.net/lu930124/article/details/77595585