Java8 - 流

1. 流的兩個(gè)重要特點(diǎn):流水線榴捡、內(nèi)部迭代

<1> 流水線:

很多流操作本身會(huì)返回一個(gè)流,多個(gè)這樣的操作鏈接起來,形成一個(gè)大的流水線仰楚。

<2> 內(nèi)部迭代:

與使用迭代器顯式迭代的集合不同岔霸,流使用內(nèi)部迭代薛躬,即stream庫內(nèi)部幫你把迭代實(shí)現(xiàn)了。

2. 流與集合的兩個(gè)重要區(qū)別:結(jié)構(gòu)呆细、迭代

<1> 結(jié)構(gòu):

流是概念上固定的數(shù)據(jù)結(jié)構(gòu)型宝,其元素是需計(jì)算,即只有在需要的時(shí)候才計(jì)算值。
集合是一個(gè)內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)趴酣,它包含數(shù)據(jù)結(jié)構(gòu)中目前所有的值梨树,即集合中的每個(gè)元素都得先算出來才能添加到集合中。

舉列:
集合就像DVD里的電影岖寞,它完整的保存了整個(gè)電影抡四,是在之前已經(jīng)處理完成,再放到DVD里仗谆。
流就像網(wǎng)上在線看電影床嫌,不是非得把整個(gè)電影都下載完成后再來看,而是根據(jù)需要計(jì)算下載胸私。

<2> 迭代:

流使用內(nèi)部迭代厌处,即stream庫內(nèi)部幫你把迭代做了。
集合使用外部迭代岁疼,即需要自己使用Collection接口做外部顯示迭代阔涉。

內(nèi)部迭代的好處:可以自動(dòng)選擇一種適合硬件的數(shù)據(jù)表示和并行實(shí)現(xiàn),即以更優(yōu)化的順序進(jìn)行處理捷绒。

流-內(nèi)部迭代.png
集合-外部迭代.png

注意:
流只能遍歷一次瑰排,遍歷完之后,這個(gè)流已經(jīng)被消費(fèi)掉了暖侨。你可以從原始數(shù)據(jù)源那里再獲取一個(gè)新的流來重新遍歷一遍椭住。

如下代碼多次遍歷流,導(dǎo)致拋出異常:

Stream<String> stream = Arrays.asList("a", "b", "c").stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println);

多次遍歷流字逗,拋出異常:
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at com.fan.demo.DemoTest.main(DemoTest.java:115)

3. 流的兩類操作:中間操作京郑、終端操作

流的中間與終端操作.png

<1> 中間操作:

流的中間操作不執(zhí)行任何處理,它們會(huì)返回一個(gè)流葫掉,多個(gè)中間操作一般都可以合并起來些举,在終端操作時(shí)一次性全部處理。

<2> 終端操作:

終端操作會(huì)從流的流水線生成結(jié)果俭厚,其結(jié)果不是流户魏,而是如List、Integer挪挤、void的值叼丑。

4. 流的使用

構(gòu)建流:


Stream.of -- 通過顯式值創(chuàng)建一個(gè)流(接受任意類型數(shù)量的參數(shù))

Stream<String> stream = Stream.of("Hello World", "James", "Ok");
stream.map(String::toUpperCase).forEach(System.out::println);

輸出:
HELLO WORLD
JAMES
OK

創(chuàng)建一個(gè)空流:
Stream<String> emptyStream = Stream.empty();

Arrays.stream -- 通過數(shù)組創(chuàng)建一個(gè)流(接受一個(gè)數(shù)組作為參數(shù))

int[] numbers = {3, 2, 5, 11, 13, 7};
int sum = Arrays.stream(numbers).sum();   --- 總和41

Files.lines -- 由文件生成流(返回一個(gè)由指定文件中的各行構(gòu)成的字符串流)

Stream.iterate、Stream.generate -- 由函數(shù)生成無限流(應(yīng)該使用limit(n)來加以限制)

Stream.iterate方法接受一個(gè)初始值扛门,實(shí)際應(yīng)用在需要依次生成一系列值的時(shí)候鸠信,比如一些列日期:1月31日,2月1日
注意:Stream.iterate方法是純粹不變的:它沒有修改現(xiàn)有狀態(tài)尖飞,在每次迭代時(shí)會(huì)創(chuàng)建新的元組症副。

Stream.iterate(0, n -> n + 2).limit(10).forEach(System.out::println);
輸出:
0
2
4
6
8

使用Stream.iterate構(gòu)建一個(gè)斐波那契數(shù)列:(斐波那契數(shù)列中前兩個(gè)數(shù)字是0,1政基,后續(xù)的每個(gè)數(shù)字 = 前兩個(gè)數(shù)字之和)
先構(gòu)建一個(gè)斐波那契元組贞铣,格式為:(數(shù)列中數(shù)字,后續(xù)數(shù)字)沮明,如下:
Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]}).limit(10).forEach(t -> System.out.println("(" + t[0] + "," + t[1] + ")"));
輸出:
(0,1)
(1,1)
(1,2)
(2,3)
(3,5)
(5,8)
(8,13)
(13,21)
(21,34)
(34,55)

使用map提取每個(gè)元組中的第一個(gè)元素辕坝,則構(gòu)建的斐波那契數(shù)列為:
Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]}).limit(10).map(t -> t[0]).forEach(System.out::println);
輸出:
0
1
1
2
3
5
8
13
21
34

Stream.generate方法接受一個(gè)Supplier<T>類型的Lambda提供新的值

Stream.generate(Math::random).limit(5).forEach(System.out::println);
輸出:
0.7017580650263067
0.5551699003184056
0.17273970322460497
0.5153472880449076
0.8041474317735003

篩選:


filter(謂詞) -- 用謂詞篩選(謂詞:一個(gè)返回boolean的函數(shù))

找出所有偶數(shù),并返回列表
List<Integer> numbers = Arrays.asList(8, 9, 100, 200, 8, 18, 23, 100);
List<Integer> evenNumList = numbers.stream().filter(i -> i % 2 == 0).collect(Collectors.toList());   --- [8, 100, 200, 8, 18, 100]

distinct -- 去重(根據(jù)流所生成元素的hashCode和equals方法實(shí)現(xiàn)篩選各異元素)

List<Integer> numbers = Arrays.asList(8, 9, 100, 200, 8, 18, 23, 100);
numbers.stream().filter(i -> i % 2 == 0).distinct().forEach(System.out::println);

輸出:
8
100
200
18

limit(n) -- 截短流(截取前n個(gè)元素)

找出所有偶數(shù)荐健,并截取走前2兩個(gè)
Stream.of(8, 9, 100, 200, 8, 18, 23, 100).filter(i -> i % 2 == 0).limit(2).forEach(System.out::println);

輸出:
8
100

skip(n) -- 跳過元素(扔掉前n個(gè)元素酱畅,流中元素不足n個(gè),返回空流)

找出所有偶數(shù)江场,并扔掉前兩個(gè)
Stream.of(8, 9, 100, 200, 8, 18, 23, 100).filter(i -> i % 2 == 0).skip(2).forEach(System.out::println);

輸出:
200
8
18
100

映射


map(函數(shù)) -- 對(duì)流中每一個(gè)元素應(yīng)用函數(shù)纺酸,將其映射為一個(gè)新元素(不去修改,創(chuàng)建新版本)

對(duì)每個(gè)單詞求其長(zhǎng)度并返回列表
List<String> words = Arrays.asList("Hello", "Are", "You", "Ok");
List<Integer> wordLengths = words.stream().map(String::length).collect(Collectors.toList());   --- [5, 3, 3, 2]

flatMap -- 對(duì)流中每個(gè)元素都轉(zhuǎn)換成另一個(gè)流址否,并把所有的流連接起來成為一個(gè)流餐蔬,即流的扁平化

對(duì)給定的單詞,得到不同字符的列表:
List<String> words = Arrays.asList("Hello", "Are", "You", "Ok");
List<String> uniqueCharacters = words.stream().map(w -> w.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
--- [H, e, l, o, A, r, Y, u, O, k]

查找和匹配


anyMatch(謂詞) -- 流中是否至少有一個(gè)元素能匹配謂詞

是否至少有一個(gè)元素大于100
boolean flag = Stream.of(8, 9, 100, 200, 8, 18, 23, 100).anyMatch(i -> i > 100);   --- true

allMatch(謂詞) -- 流中是否所有的元素都匹配謂詞

是否所有都為偶數(shù)
boolean flag = Stream.of(8, 9, 100, 200, 8, 18, 23, 100).allMatch(i -> i % 2 == 0);   --- false

noneMatch(謂詞) -- 是否流中沒有元素與謂詞匹配

是否沒有元素大于200
boolean flag = Stream.of(8, 9, 100, 200, 8, 18, 23, 100).noneMatch(i -> i > 200);   --- true

findAny() -- 返回當(dāng)前流中的任意元素

返回當(dāng)前流中長(zhǎng)度大于2的任意元素
Optional<String> word = Stream.of("Hello World", "James", "Ok").filter(e -> e.length() > 2).findAny();   --- Hello World

如果流中沒有滿足條件的元素佑附,則findAny()返回空(Optional.empty)

找出流中長(zhǎng)度大于2的任意元素樊诺,如果存在,按如下格式輸出(結(jié)合Optional對(duì)象的ifPresent(函數(shù)) ):
Stream.of("Hello World", "James", "Ok").filter(e -> e.length() > 2).findAny().ifPresent(s -> System.out.println("[" + s + "]'s length = "+ s.length()));   
--- [Hello World]'s length = 11

findFirst() -- 查找第一個(gè)元素

對(duì)流中元素求平方音同,找出第一個(gè)能被3整除的元素
Optional<Integer> firstElement = Stream.of(1, 2, 3, 4, 5, 6).map(x -> x * x).filter(x -> x % 3 == 0).findFirst();   --- 9

歸約


reduce -- 歸約(將流中元素反復(fù)結(jié)合起來词爬,得到一個(gè)值)

元素求和:
int sum = Stream.of(5, 6, 7, 8).reduce(0, (a, b) -> a + b);   --- 26
int sum = Stream.of(5, 6, 7, 8).reduce(0, Integer::sum);   --- 26
無初始值,返回Optional對(duì)象
Optional<Integer> sumOpt = Stream.of(5, 6, 7, 8).reduce((a, b) -> (a + b));   --- 26

求最大值:
int max = Stream.of(10, 20, 0, 11, 100, 250).reduce(0, Integer::max);   --- 250
Optional<Integer> maxOpt = Stream.of(10, 20, 0, 11, 100, 250).reduce(Integer::max);   --- 250

求最小值:
int min = Stream.of(10, 20, 0, 11, 100, 250).reduce(0, Integer::min);   --- 0
Optional<Integer> minOpt = Stream.of(10, 20, 0, 11, 100, 250).reduce(Integer::min);   --- 0

map-reduce模式:(map和reduce的連接)
計(jì)算單詞的個(gè)數(shù):
int count = Stream.of("Hello", "James", "Ok").map(e -> 1).reduce(0, Integer::sum);   --- 3 (將流中每個(gè)元素映射成數(shù)字1)
long count = Stream.of("Hello", "James", "Ok").count();   --- 3

特化流 IntStream权均、DoubleStream顿膨、LongStream

特化流IntStream、DoubleStream叽赊、LongStream分別將流中的元素特化為int虽惭、long和double,從而避免了暗含的裝箱操作蛇尚。

mapToInt芽唇、mapToDouble、mapToLong -- 將流轉(zhuǎn)化成特化流

計(jì)算每個(gè)字符串的長(zhǎng)度取劫,并返回一個(gè)IntStream特化流(不是一個(gè)Stream<Integer>)匆笤,然后調(diào)用IntStream接口中的sum方法求和:
如果流為空,則sum默認(rèn)返回0
int sum = Stream.of("Hello World", "James", "Ok").mapToInt(String::length).sum();   --- 18

數(shù)值范圍:
rangeClosed(參數(shù)1, 參數(shù)2) -- 生成兩個(gè)參數(shù)之間的所有數(shù)字谱邪,包含第二個(gè)參數(shù) 

IntStream evenNum = IntStream.rangeClosed(1, 100).filter(n -> n % 2 == 0);
System.out.println(evenNum.count());   --- 50

range(參數(shù)1, 參數(shù)2) -- 生成兩個(gè)參數(shù)之間的所有數(shù)字炮捧,不包含第二個(gè)參數(shù)

IntStream evenNum = IntStream.range(1, 100).filter(n -> n % 2 == 0);
System.out.println(evenNum.count());   --- 49

boxed方法 -- 將特化流轉(zhuǎn)回一般的對(duì)象流

IntStream intStream = Stream.of("Hello World", "James", "Ok").mapToInt(String::length);
Stream<Integer> stream = intStream.boxed();

Optional原始類型特化版本:OptionalInt、OptionalDouble惦银、OptionalLong

計(jì)算每個(gè)字符串的長(zhǎng)度咆课,并返回一個(gè)IntStream特化流末誓,調(diào)用其max方法,返回一個(gè)OptionalInt特化對(duì)象:
OptionalInt maxLength = Stream.of("Hello World", "James", "Ok").mapToInt(String::length).max();   --- 11

收集器:


為了便于舉例书蚪,定義一個(gè)Person類喇澡,如下:

public class Person {
    private final String name;
    private final String sex;
    private final int age;
    private final Job job;
    private final boolean partyMember;

    public Person(String name, String sex, int age, Job job, boolean partyMember) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.job = job;
        this.partyMember = partyMember;
    }
    public enum Job { TEACHER, WORKER, DOCTOR, DRIVER, COOK}
    ...省略get,set方法
}

構(gòu)建personList列表:
List<Person> personList = Arrays.asList(
    new Person("李鐵蛋", "男",31, Person.Job.WORKER, true),
    new Person("王翠花", "女", 22, Person.Job.TEACHER, false),
    new Person("牛建國(guó)", "男", 62, Person.Job.DRIVER, false),
    new Person("Lucy Rose", "女", 42, Person.Job.DOCTOR, true),
    new Person("尼古拉斯蛋蛋", "男", 51, Person.Job.COOK, false)
);

構(gòu)建流:
Stream<Person> personStream = personList.stream();

Collectors.toList() -- 把流中所有元素收集到一個(gè)List

List<Person> persons = personStream.collect(Collectors.toList());

Collectors.toSet() -- 把流中所有元素收集到一個(gè)Set殊校,刪除重復(fù)項(xiàng)

Set<Person> persons = personStream.collect(Collectors.toSet());

Collectors.toCollection -- 把流中所有元素收集到給定的供應(yīng)源創(chuàng)建的集合

Collection<Person> persons = personStream.collection(Collections.toCollection(ArrayList::new));

Collectors.counting() -- 計(jì)算流中元素個(gè)數(shù)

long count = personStream.collect(counting());
等價(jià)于
long count = personStream.count();

對(duì)流中元素相應(yīng)類型的屬性求和

Collectors.summingInt晴玖、Collectors.summingLong、Collectors.summingDouble:

對(duì)所有人的年齡求和
int ageSum = personStream.collect(Collectors.summingInt(Person::getAge));

計(jì)算流中元素的平均值

Collectors.averagingInt为流、Collectors.averagingLong呕屎、Collectors.averagingDouble(返回類型都為double):

求所有人年齡的平均值
double ageAver = personStream.collect(Collectors.averagingInt(Person::getAge));

計(jì)算流中元素對(duì)應(yīng)類型屬性的統(tǒng)計(jì)值(最大值,最小值敬察,總和秀睛,平均值,數(shù)量)

Collectors.summarizingInt莲祸、Collectors.summarizingLong琅催、Collectors.summarizingDouble:

對(duì)所有人的年齡求統(tǒng)計(jì)值
IntSummaryStatistics ageStatistics = personStream.collect(Collectors.summarizingInt(Person::getAge));
輸出:
IntSummaryStatistics{count=5, sum=208, min=22, average=41.600000, max=62}

Collectors.joining -- 連接字符串(內(nèi)部使用StringBuilder來連接)

String personName = personStream.map(Person::getName).collect(Collectors.joining(", "));

Collectors.maxBy -- 按照指定比較器選出最大元素(被Optional包裹)

選出年齡最大的人
Optional<Person> maxAgePerson = personStream.collect(Collectors.maxBy(Comparator.comparingInt(Person::getAge)));

Collectors.minBy -- 按照指定比較器選出最小元素(被Optional包裹)

選出年齡最小的人
Optional<Person> minAgePerson = personStream.collect(Collectors.minBy(Comparator.comparingInt(Person::getAge)));

Collectors.reducing -- 從一個(gè)作為累加器的初始值開始,利用BinaryOperator與流中的元素逐個(gè)結(jié)合虫给,從而將流歸約為單個(gè)值藤抡。

對(duì)所有人的年齡求和
int ageSum = personStream.collect(Collectors.reducing(0, Person::getAge, Integer::sum));

Collectors.groupingBy -- 對(duì)流中元素進(jìn)行分組,返回結(jié)果Map

根據(jù)元素的一個(gè)屬性的值對(duì)元素進(jìn)行分組抹估,分組結(jié)果是個(gè)Map缠黍,Map的key為屬性的值,Map的value為屬于這個(gè)屬性的元素列表药蜻。

按職業(yè)對(duì)人進(jìn)行分組
Map<Person.Job, List<Person>> personsByJob = personStream.collect(Collectors.groupingBy(Person::getJob));
輸出:
{
COOK=[Person{name='尼古拉斯蛋蛋', sex='男', age=51, job=COOK}], 
TEACHER=[Person{name='王翠花', sex='女', age=22, job=TEACHER}], 
DRIVER=[Person{name='牛建國(guó)', sex='男', age=62, job=DRIVER}], 
DOCTOR=[Person{name='Lucy Rose', sex='女', age=42, job=DOCTOR}], 
WORKER=[Person{name='李鐵蛋', sex='男', age=31, job=WORKER}]
}

按分的子組收集數(shù)據(jù):即傳遞收集器作為groupingBy的第二個(gè)參數(shù)瓷式。

例1:按性別分組,并計(jì)算每組的人數(shù):
Map<String, Long> sexCount = personStream.collect(Collectors.groupingBy(Person::getSex, Collectors.counting()));
輸出:
{女=2, 男=3}

例2:按性別分組语泽,并查找每組中年齡最大的人:
Map<String, Optional<Person>> maxAgeBySex = personStream.collect(Collectors.groupingBy(Person::getSex, Collectors.maxBy(Comparator.comparingInt(Person::getAge))));
輸出:
{
女=Optional[Person{name='Lucy Rose', sex='女', age=42, job=DOCTOR}], 
男=Optional[Person{name='牛建國(guó)', sex='男', age=62, job=DRIVER}]
}
說明:這個(gè)Map中的值是Optional贸典,是由于maxBy收集器返回的類型,實(shí)際上踱卵,如果不存在某個(gè)性別廊驼,就不會(huì)對(duì)應(yīng)一個(gè)Optional.empty()值,根本不會(huì)出現(xiàn)在Map的鍵中惋砂,所以這個(gè)Optional包裝器在這里不是很有用妒挎。

支持多級(jí)分組,即可以把一個(gè)內(nèi)層groupingBy傳遞給外層groupingBy西饵,并定義一個(gè)為流中元素分類的二級(jí)標(biāo)準(zhǔn)酝掩。

先按性別分組,然后再按職業(yè)分組:
Map<String, Map<Person.Job, List<Person>>> personBySexAndJob = personStream.collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getJob)));
輸出:
{
女={
    DOCTOR=[Person{name='Lucy Rose', sex='女', age=42, job=DOCTOR}], 
    TEACHER=[Person{name='王翠花', sex='女', age=22, job=TEACHER}]
   }, 
男={
    COOK=[Person{name='尼古拉斯蛋蛋', sex='男', age=51, job=COOK}], 
    DRIVER=[Person{name='牛建國(guó)', sex='男', age=62, job=DRIVER}], 
    WORKER=[Person{name='李鐵蛋', sex='男', age=31, job=WORKER}]
   }
}

Collectors.collectingAndThen -- 包裹另一個(gè)收集器眷柔,對(duì)其結(jié)果應(yīng)用轉(zhuǎn)換函數(shù)

這個(gè)工廠方法接受兩個(gè)參數(shù)期虾,即要轉(zhuǎn)換的收集器和轉(zhuǎn)換函數(shù)原朝。該方法相當(dāng)于對(duì)舊收集器的一個(gè)包裝,collect操作的最后一步將返回值用轉(zhuǎn)換函數(shù)做一個(gè)映射镶苞。

如下例子:collectingAndThen包裹起maxBy收集器喳坠,而轉(zhuǎn)換函數(shù)Optional::get則把返回的Optional中的值提取出來。

按性別進(jìn)行分組宾尚,并找出每組中年齡最大的人:
Map<String, Person> personMap = personStream.collect(Collectors.groupingBy(Person::getSex,
                Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Person::getAge)),Optional::get)));
輸出:
{
女=Person{name='Lucy Rose', sex='女', age=42, job=DOCTOR, partyMember=true}, 
男=Person{name='牛建國(guó)', sex='男', age=62, job=DRIVER, partyMember=false}
}

Collectors.partitioningBy(謂詞) -- 分區(qū)(分組的特殊情況),即謂詞(返回一個(gè)boolean值的函數(shù))作為分類函數(shù)谢澈,進(jìn)行分組煌贴。

根據(jù)是否為黨員對(duì)人進(jìn)行分組:
Map<Boolean, List<Person>> personMap = personStream.collect(Collectors.partitioningBy(Person::isPartyMember));
輸出:
{
false=[
Person{name='王翠花', sex='女', age=22, job=TEACHER, partyMember=false}, 
Person{name='牛建國(guó)', sex='男', age=62, job=DRIVER, partyMember=false}, 
Person{name='尼古拉斯蛋蛋', sex='男', age=51, job=COOK, partyMember=false}
], 
true=[
Person{name='李鐵蛋', sex='男', age=31, job=WORKER, partyMember=true}, 
Person{name='Lucy Rose', sex='女', age=42, job=DOCTOR, partyMember=true}
]
}

可以傳遞收集器作為partitioningBy的第二個(gè)參數(shù):

例1:統(tǒng)計(jì)黨員與非黨員的人數(shù):
Map<Boolean, Long> personCount = personStream.collect(Collectors.partitioningBy(Person::isPartyMember, Collectors.counting()));
輸出:{false=3, true=2}

例2:先按是否為黨員,然后再按性別進(jìn)行分組:
Map<Boolean, Map<String, List<Person>>> personMap = personStream.collect(Collectors.partitioningBy(Person::isPartyMember, Collectors.groupingBy(Person::getSex)));
輸出:
{
false={
    女=[Person{name='王翠花', sex='女', age=22, job=TEACHER, partyMember=false}], 
    男=[
        Person{name='牛建國(guó)', sex='男', age=62, job=DRIVER, partyMember=false}, 
        Person{name='尼古拉斯蛋蛋', sex='男', age=51, job=COOK, partyMember=false}
       ]
}, 
true={
    女=[Person{name='Lucy Rose', sex='女', age=42, job=DOCTOR, partyMember=true}], 
    男=[Person{name='李鐵蛋', sex='男', age=31, job=WORKER, partyMember=true}]
}
}

例3:先按是否為黨員分組锥忿,然后找出年齡最大的人:
Map<Boolean, Person> personMap = personStream.collect(Collectors.partitioningBy(Person::isPartyMember,
                Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Person::getAge)), Optional::get)));
輸出:
{
false=Person{name='牛建國(guó)', sex='男', age=62, job=DRIVER, partyMember=false}, 
true=Person{name='Lucy Rose', sex='女', age=42, job=DOCTOR, partyMember=true}
}

例4:寫一個(gè)方法牛郑,接受參數(shù)int n,并將前n個(gè)自然數(shù)分為質(zhì)數(shù)和非質(zhì)數(shù):

判斷一個(gè)數(shù)是否為質(zhì)數(shù)的方法:
public static boolean isPrime(int candidate) {
    int candidateRoot = (int) Math.sqrt(candidate);
    return IntStream.rangeClosed(2, candidateRoot).noneMatch(i -> candidate % i == 0);
}
創(chuàng)建一個(gè)包含n個(gè)自然數(shù)的流敬鬓,用isPrime方法作為謂詞進(jìn)行分區(qū):
public static Map<Boolean, List<Integer>> partitionPrimes(int n) {
    return IntStream.rangeClosed(1, n).boxed().collect(Collectors.partitioningBy(candidate -> isPrime(candidate)));
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末淹朋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钉答,更是在濱河造成了極大的恐慌础芍,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件数尿,死亡現(xiàn)場(chǎng)離奇詭異仑性,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)右蹦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門诊杆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人何陆,你說我怎么就攤上這事晨汹。” “怎么了贷盲?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵淘这,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我巩剖,道長(zhǎng)慨灭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任球及,我火速辦了婚禮氧骤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吃引。我一直安慰自己筹陵,他們只是感情好刽锤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著朦佩,像睡著了一般并思。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上语稠,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天宋彼,我揣著相機(jī)與錄音,去河邊找鬼仙畦。 笑死输涕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的慨畸。 我是一名探鬼主播莱坎,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼寸士!你這毒婦竟也來了檐什?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤弱卡,失蹤者是張志新(化名)和其女友劉穎乃正,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體婶博,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烫葬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凡蜻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搭综。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡区丑,死狀恐怖悍募,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饰剥,我是刑警寧澤忠荞,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布蒋歌,位于F島的核電站,受9級(jí)特大地震影響委煤,放射性物質(zhì)發(fā)生泄漏堂油。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一碧绞、第九天 我趴在偏房一處隱蔽的房頂上張望府框。 院中可真熱鬧,春花似錦讥邻、人聲如沸迫靖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽系宜。三九已至照激,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盹牧,已是汗流浹背俩垃。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汰寓,地道東北人口柳。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像踩寇,于是被迫代替她去往敵國(guó)和親啄清。 傳聞我的和親對(duì)象是個(gè)殘疾皇子六水,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345