Aggregation operation of java collection
Step 1: traverse data in the traditional way and aggregate operation way
The traditional way of traversing data is to use the for loop, then judge the conditions, and finally print out the data that meets the conditions
for (Hero h : heros) { if (h.hp > 100 && h.damage < 50) System.out.println(h.name); }
With aggregation, the style of painting changes:
heros .stream() .filter(h -> h.hp > 100 && h.damage < 50) .forEach(h -> System.out.println(h.name));
package lambda; import java.util.ArrayList; import java.util.List; import java.util.Random; import charactor.Hero; public class TestAggregate { public static void main(String[] args) { Random r = new Random(); List<Hero> heros = new ArrayList<Hero>(); for (int i = 0; i < 5; i++) { heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100))); } System.out.println("Initialized collection:"); System.out.println(heros); System.out.println("Query criteria: hp>100 && damage<50"); System.out.println("Find the data that meets the conditions through traditional operation mode:"); for (Hero h : heros) { if (h.hp > 100 && h.damage < 50) System.out.println(h.name); } System.out.println("Find the data that meets the conditions through aggregation operation:"); heros .stream() .filter(h -> h.hp > 100 && h.damage < 50) .forEach(h -> System.out.println(h.name)); } }
Step 2: the concept of stream and pipeline
heros .stream() .filter(h -> h.hp > 100 && h.damage < 50) .forEach(h -> System.out.println(h.name));
To understand aggregation operations, first establish the concept of Stream and pipeline
Stream is different from the structured data of Collection. Stream is a series of elements, just like a can on a production line, coming out in series.
Pipeline refers to a series of aggregation operations.
The pipeline is divided into three parts
Pipe source: in this case, the source is a List
Intermediate operation: each intermediate operation will return another Stream, for example. filter() will return another Stream. The intermediate operation is lazy and will not be traversed.
End operation: when this operation is executed, the Stream will be used with "light" and can no longer be operated. So this must be the last operation of the flow. The end operation will not return Stream, but it will return int, float, String, Collection or anything like forEach. Only when the end operation is finished can the real traversal be carried out, and only when the traversal is carried out can the related judgment of the intermediate operation be carried out
Note: this Stream is different from the InputStream and OutputStream in the I/O chapter.
Step 3: pipe source
It's easy to switch the Collection to a pipe source, just call stream().
heros.stream()
However, there is no stream() method for arrays, so you need to use
Arrays.stream(hs)
perhaps
Stream.of(hs)
.
package lambda; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Random; import charactor.Hero; public class TestAggregate { public static void main(String[] args) { Random r = new Random(); List<Hero> heros = new ArrayList<Hero>(); for (int i = 0; i < 5; i++) { heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100))); } //The source is the assembly heros .stream() .forEach(h->System.out.println(h.name)); //The source is an array Hero hs[] = heros.toArray(new Hero[heros.size()]); Arrays.stream(hs) .forEach(h->System.out.println(h.name)); } }
Step 4: intermediate operation
Each intermediate operation will return another Stream, for example. filter() will return another Stream. The intermediate operation is "lazy" and will not be traversed.
There are many intermediate operations, mainly divided into two categories:
Filtering and converting elements to other forms of flow
Filter elements:
filter matching
distinct to remove duplicates (based on equals)
sorted natural sorting
sorted(Comparator) specifies sorting
limit reservation
skip ignores
Convert to other forms of flow:
mapToDouble to double flow
map to any type of stream
package charactor; public class Hero implements Comparable<Hero>{ public String name; public float hp; public int damage; public Hero(){ } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getHp() { return hp; } public void setHp(float hp) { this.hp = hp; } public int getDamage() { return damage; } public void setDamage(int damage) { this.damage = damage; } public Hero(String name) { this.name =name; } //The construction method of initializing name,hp,damage public Hero(String name,float hp, int damage) { this.name =name; this.hp = hp; this.damage = damage; } @Override public int compareTo(Hero anotherHero) { if(damage<anotherHero.damage) return 1; else return -1; } @Override public String toString() { return "Hero [name=" + name + ", hp=" + hp + ", damage=" + damage + "]\r\n"; } } package lambda; import java.util.ArrayList; import java.util.List; import java.util.Random; import charactor.Hero; public class TestAggregate { public static void main(String[] args) { Random r = new Random(); List<Hero> heros = new ArrayList<Hero>(); for (int i = 0; i < 5; i++) { heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100))); } //Create a duplicate data heros.add(heros.get(0)); System.out.println("Data after collection initialization (Last data repeat): "); System.out.println(heros); System.out.println("Meeting conditions hp>100&&damage<50 Data"); heros .stream() .filter(h->h.hp>100&&h.damage<50) .forEach(h->System.out.print(h)); System.out.println("To remove duplicate data, the standard is to equals"); heros .stream() .distinct() .forEach(h->System.out.print(h)); System.out.println("Sort by blood volume"); heros .stream() .sorted((h1,h2)->h1.hp>=h2.hp?1:-1) .forEach(h->System.out.print(h)); System.out.println("Keep 3."); heros .stream() .limit(3) .forEach(h->System.out.print(h)); System.out.println("Ignore the first three"); heros .stream() .skip(3) .forEach(h->System.out.print(h)); System.out.println("Convert to double Of Stream"); heros .stream() .mapToDouble(Hero::getHp) .forEach(h->System.out.println(h)); System.out.println("Convert any type of Stream"); heros .stream() .map((h)-> h.name + " - " + h.hp + " - " + h.damage) .forEach(h->System.out.println(h)); } }
Step 5: end the operation
When the end operation is performed, the Stream is "light" and cannot be operated any more. So this must be the last operation of the flow. The end operation will not return Stream, but it will return int, float, String, Collection or anything like forEach,.
Only when the end operation is finished can the traversal behavior be carried out. The previous intermediate operation is also carried out at this time.
Common ending operations are as follows:
forEach() traverses each element
toArray() to array
min(Comparator) takes the smallest element
max(Comparator) takes the largest element
count() total
findFirst() first element
package lambda; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import org.omg.Messaging.SYNC_WITH_TRANSPORT; import charactor.Hero; public class TestAggregate { public static void main(String[] args) { Random r = new Random(); List<Hero> heros = new ArrayList<Hero>(); for (int i = 0; i < 5; i++) { heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100))); } System.out.println("Traverse each data in the collection"); heros .stream() .forEach(h->System.out.print(h)); System.out.println("Returns an array"); Object[] hs= heros .stream() .toArray(); System.out.println(Arrays.toString(hs)); System.out.println("Return to the hero with the lowest damage"); Hero minDamageHero = heros .stream() .min((h1,h2)->h1.damage-h2.damage) .get(); System.out.print(minDamageHero); System.out.println("Return to the hero with the highest damage"); Hero mxnDamageHero = heros .stream() .max((h1,h2)->h1.damage-h2.damage) .get(); System.out.print(mxnDamageHero); System.out.println("Total number of data in the stream"); long count = heros .stream() .count(); System.out.println(count); System.out.println("First hero"); Hero firstHero = heros .stream() .findFirst() .get(); System.out.println(firstHero); } }
Practice: Aggregation operation
The first choice is to prepare 10 Hero objects, hp and damage are random numbers.
Print out hp's third highest hero name in the traditional way and in the aggregate way
Answer:
package lambda; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Random; import charactor.Hero; public class TestAggregate { public static void main(String[] args) { Random r = new Random(); List<Hero> heros = new ArrayList<Hero>(); for (int i = 0; i < 10; i++) { heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100))); } System.out.println("Data after collection initialization (Last data repeat): "); System.out.println(heros); //Traditional way Collections.sort(heros,new Comparator<Hero>() { @Override public int compare(Hero o1, Hero o2) { return (int) (o2.hp-o1.hp); } }); Hero hero = heros.get(2); System.out.println("It's found in the traditional way hp The third highest hero name is:" + hero.name); //Polymerization mode String name =heros .stream() .sorted((h1,h2)->h1.hp>h2.hp?-1:1) .skip(2) .map(h->h.getName()) .findFirst() .get(); System.out.println("Found by aggregation hp The third highest hero name is:" + name); } }