title: Coding Qian
tag: 标签名
categories: 分类
comment: 是否允许评论(true or false)
description: 描述
top_img: https://z3.ax1x.com/2021/10/06/4xq2s1.png
cover:https://s4.ax1x.com/2022/02/11/HUIZbn.jpg
一 基础知识
为什么要关心Java8
Java在编程语言生态系统中的位置
Java式怎么进入编程市场的?
面向对象在20世纪90年代开始兴起的原因有两个:封装原则使得其软件工程问题比C少,作为一个思想模型,它轻松地反映了Windows95及之后的WIMP编程模式。Java的“一次编写,随处运行”模式,早期浏览器安全地执行Java小应用的能力让它占领了大学市场。
流处理
流是一系列数据项,一次只生成一项。程序可以从输入流中一个一个读取数据,然后以同样的方式将数据项写入输出流。一个程序的输出流很可能是另一个程序的输入流。
举一个例子:
在Unix中,命令(cat,tr,sort和tail)是同时执行的,这样sort就可以在cat和tr完成前先处理头几行。就像汽车组装流水线一样。汽车排队进入加工站,每个加工站会接收、修改汽车,然后将之传递给下一战做进一步的处理。尽管流水实际上是一个序列,但不同加工站的运行一般是并行的。
基于上述思想,Java 8在java.util.Stream中添加了一个Stream API:Stream就是一系列T类型的项目。
用行为参数化把代码传递给方法
Java8中增加的另外一个编程概念是通过API来传递代码的能力。
java8增加了把方法(你的代码)作为参数传递给另一个方法的能力。下图则是描述了这样的一种思想。我们把这一概念行为实现参数化的思想上。
java中的函数
编程语言中的函数一词通常是指方法,尤其是值静态方法;这是在数学函数,也就是没有副作用的函数之外的新含义。
Java8的一个新功能是方法引用。
File[] hiddenFiles = new File(".").listFiles(new FileFilter(){
public boolean accept(File file){
return file.isHidden();
}
})
在Java8中可以将代码进行重写:
File[] HiddenFiles = new File(".").listFiles(File::isHidden);
流初识
例子:你需要从一个列表中筛选金额较高的交易,然后按货币分组。
使用流:
通过行为参数化传递代码
应对不断变化的需求
筛选绿苹果
public static List<Apple> filterGreenApples(List<Apple> inventory){
// 创建一个集合存储苹果
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if("green".equals(apple.getColor())){
result.add(apple);
}
}
return result;
}
但是接下来又想筛选出多种颜色:比如浅绿色、暗红色、黄色等。
将颜色作为参数
public static List<Apple> filterApplesByColor(List<Apple> inventory, String color){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getColor().equals(color)){
result.add(apple);
}
}
return result;
}
对大于150克的苹果进行筛选
public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){
List<Apple> result = new ArrayList<>();
for(Apple apple: inventory){
if(apple.getWeight() > weight){
result.add(apple);
}
}
return result;
}
行为参数化
行为参数化就是帮助你处理频繁变更的需求的一种软件开发模式。它意味着拿出一个代码块,把它准备好却不去执行它。这个代码块以后可以被你程序的其他部分调用,着意味着你可以推迟着块代码块的执行。
面对上面的例子,一种可能的解决方案是对你的选择标准进行建模:你考虑得是苹果,需要根据Apple的某些属性来返回一个boolean值。我们把它们称为谓词。定义一个接口来对选择标准建模。
public interface ApplePredicate{
public boolean test(Apple a);
}
多个实现选择不同的标准:
static class AppleWeightPredicate implements ApplePredicate{
public boolean test(Apple apple){
return apple.getWeight() > 150;
}
public static class AppleColorPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "green".equals(apple.getColor());
}
}
怎么利用ApplePredicate的不同实现呢?需要filterApples方法接受ApplePredicate对象,对App做条件测试。这就是行为参数:让方法接受多种行为作为参数,并在内部使用,来完成不同的行为。
根据抽象条件筛选
public static List<Apple> filterApples(List<Apple> inventory,ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple apple:inventory){
if(p.test(apple)){
result.add(apple);
}
}
return result;
}
传递代码行为:
如果一个农民工让你找出所有重量超过150克的红苹果,你只需要创建一个实现类来实现ApplePredicate就行了。
public static class AppleRedAndHeavyPredicate implements ApplePredicate{
public boolean test(Apple apple){
return "red".equals(apple.getColor())
&& apple.getWeight() > 150;
}
}
List<Apple> redAndHeavyApples = filter(inventory, new AppleRedAndHeavyPredicate());
System.out.println(redAndHeavyApples);
上述中比较重要的点就是传递的是对象,通过实现test方法的对象来传递布尔表达式。
多种行为,一个参数
测试:
编写一个prettyPrintApple方法,它接受一个Apple的List,并可以对它参数化,以多种方式根据苹果生成一个String输出。
打印每个苹果的重量,并判断式重的还是轻的。
编写代码前的框架:
public static void prettyPrintApple(List<Apple> inventory,???){
for(Apple apple: inventory){
String output = ???.???(apple);
System.out.println(output);
}
}
步骤:
需要一种接受apple并且返回String 值得方法。
public interface AppleFormatter{
String accept(Apple a);
}
通过实现AppleFormatter方法,来表示多种格式行为了:
public class AppleFancyFormatter implements AppleFormatter{
public String accept(Apple apple){
String char = apple.getWeight() > 150 ? "heavy":"light";
return "A "+char + " "+apple.getColor()+ "apple";
}
}
public class AppleSimpleFormatter implements AppleFormatter{
public String accept(Apple a){
return "An apple of"+apple.getWeight()+"g";
}
}
最后,让上述得prettyPrintApple方法接受AppleForamtter对象,并在内部使用它们
public static void prettyPrintApple(List<Apple> inventory,AppleFormatter formatter){
for(Apple apple: inventory){
String output =formater.accept(apple);
System.out.println(output);
}
}
对于上述得代码进行分析,我们发现当我们把行为传递给filterApples方法的时候,还是不得不实现好几个ApplePredicate接口的类。
行为化参数,用谓词筛选苹果
面对上述的代码我们可以使用匿名类。
尝试使用Lambda表达式
List<Apple> result = filterApples(inventory,(Apple apple)->"red".equals(apple.getColor()));
尝试将List类型抽象化
上述的filterApples方法还只适用于Apple,你还可以将List类型进行抽象化,把办法运用在香蕉、桔子等。
public interface Predicate<T>{
boolean test(T t);
}
public static <T> List<T> filter(List<T> list, Predicate<T> p){
List<T> result = new ArrayList<>();
for(T e: list){
if(p.test(e)){
result.add(e);
}
}
return result;
}
接下来可以将对应的参数传入其中:
List<Apple> redApples =
filter(inventory, (Apple apple) -> "red".equals(apple.getColor()));
List<Integer> evenNumbers =
filter(numbers, (Integer i) -> i % 2 == 0);
真实的例子
==行为参数化==是一个很有用的模式,它能够轻松地适应不断变化的需求。这种模式可以把一个行为(一段代码)封装起来,并通过传递和使用创建的行为将方法的行为参数化。
用compatator来排序
public interface Comparator<T> {
public int compare(T o1, T o2);
}
inventory.sort(new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
});
// 使用lambda表达式
inventory.sort(
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
用Runnable执行代码块
线程是轻量级的进程:它们自己执行一个代码块。
public interface Runnable{
public void run();
}
创建接口执行不同行为的线程:
Thread t = new Thread(new Runnable() {
public void run(){
System.out.println("Hello world");
}
});
// 使用lambda表达式
Thread t = new Thread(() -> System.out.println("Hello world"));
小结
- 行为参数化,就是一个方法接受多个不同的行为作为参数,并在内部使用它们,完成不同行为的能力。
- 行为参数化可让代码更好地适应不断变化的要求,减轻未来的工作量。
Lambda表达式
Lambda管中窥豹
Lambda表达式可以理解为可传递的匿名函数的一种方式:它没有名称,但它有参数列表,函数主体、返回类型,可能还有一个可以抛出的异常列表。
未使用lambda表达式之前:
Comparator<Apple> byWeight = new Comparator<Apple>() {
public int compare(Apple a1, Apple a2){
return a1.getWeight().compareTo(a2.getWeight());
}
};
使用lambda表达式之后:
Comparator<Apple> byWeight =
(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
测试:
()->{} // 没有参数,并返回void
()->"QJS" // 没有参数,并返回String作为表达式
()-> {return "Mario";} // 没有参数,并返回String
(Integer i)->return "QJS"+i; //错误,return是一个控制流语句,要使得有效,需要添加(Integer i)->{return "QJS"+i;}
(String s)->{"QJS"} //错误,"QJS"是一个表达式,不是一个语句。修改:(String s)->"QJS"或者 (String s)->{return"QJS";}
在哪里以及如何使用Lambda
可以在函数式接口上使用lambda表达式
函数式接口
函数式接口就是只定义了一个抽象方法的接口。
JavaAPI常见的一些函数式接口:
测试:
// 下面哪些是函数式接口:
public interface Adder(
int add(int a ,int b);
) // 是函数式接口
public interface SmartAdder extends Adder{
int add(double a,double b);
}
// 不是函数式接口,因为它定义了两个叫做add的抽象方法
public interface Nothing{
}
// 不是函数式接口,因为它没有声明抽象方法
函数式接口可以干什么,Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例。
函数描述符
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作函数描述符。例如,Runnbale接口可以看作是一个什么也不接受什么也不返回(void)的函数的签名,因为它只有一个抽象方法,这个方法什么也不接受,什么也不返回。
测试:
把Lambda付诸实践:环绕执行模式
环绕执行模式
[](
[https://imgtu.com/i/HaRCWQ)
第1步:记得行为参数化
从BufferedReader种打印两行的写法:
String result = processFile((BufferedReader br) ->
br.readLine() + br.readLine());
第2步:使用函数式接口传递行为
Lambda仅用于上下文式函数式接口的情况。因此需要创建一个能匹配BufferedReader->String
@FunctionalInterface
public interface BufferedReaderProcessor {
String process(BufferedReader b) throws IOException;
}
第3步:执行一个行为
BufferedReader->String形式的Lambda满足BufferedReaderProcessor接口中定义的process方法的签名。
public static String processFile(BufferedReaderProcessor p) throws
IOException {
try (BufferedReader br =
new BufferedReader(new FileReader("data.txt"))) {
return p.process(br);
}
}
第4步:传递Lambda
处理一行:
String oneLine =
processFile((BufferedReader br) -> br.readLine());
处理两行:
String twoLines =
processFile((BufferedReader br) -> br.readLine() + br.readLine());
总结:
[](
使用函数式接口
Predicate
java.util.function.Predicate 定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean.
使用Predicate
@FunctionalInterface
public interface Predicate<T>{
boolean test(T t)
}
public static <T> List<T> filter(List<T> lsit,Predicate<T> p){
List<T> results = new ArrayList<>();
for(T s:list){
if(p.test(s)){
restults.add(s);
}
}
return results;
}
Predicate<String> nonEmpStringPredicate = (String s)->! s.isEmpty();
Consumer
java.util.function.Consumer定义了一个名叫accept的抽象方法,接受泛型T的对象,但是没有返回值(void)
如果需要访问类型T的对象,并对其进行某些操作,就可以使用这个接口。
// void accept(T t);消费型接口,一个参数,没有返回值
//只有參數,沒有返回值
Consumer<String> consumer = t->{
System.out.println(t);
};
consumer.accept("javaXXXX");
Function
java.util.function.Function<T,R>接口定义了一个叫做apply的方法,它接受一个泛型T的对象,并且返回一个R的对象。
//R apply(T t);函数型接口,一个参数,一个返回值
//供给型接口
Function<String,Integer> function = t ->{return t.length();};
System.out.println(function.apply("abcd"));
Supplier
Supplie供给型,没有参数,有一个返回值。包含的方法为t.get()
//T get(); 供给型接口,无参数,有返回值
//没有参数,但是有返回值
Supplier<String> supplier =()->{return UUID.randomUUID().toString();};
System.out.println(supplier.get());
方法引用
管中窥豹
根据已有的方法实现类创建Lambda表达式。当使用方法引用时,目标引用放在分隔符**::**前,方法的名称在后。如Apple::getWeight就是引用了Apple类中定义得到方法getWeight.
如何构建方法引用:
方法引用主要有三类:
(1)指向静态方法的方法引用。(如Integer::parseInt)Integer的parseInt方法
(2) 指向任意类型实例方法的方法引用(String类型的length方法,写作String::length)
(String a) -> s.toUpperCase()可以写作String::toUpperCase
(3) 指向现有对象的实例方法的方法引用,(假如你有一个局部变量expensiveTransaction用于存放Transaction类型的对象,它支持实例getValue,则可以写作expensiveTransaction::getValue)
构造函数引用
对于一个现有构造函数,可以利用它的名称和关键字new来创建它的一个引用: ClassName::new. 它的功能与指向静态方法的引用类似。假如一个构造函数没有签名,它适合Spplier的签名() ->Apple.则可以这样写
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qL57sXZT-1645079970545)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216114312618.png)]
引入流
流是什么
流是JavaAPI新成员,它允许你以声明性方式处理数据集合。可以把它看成遍历数据集的高级迭代器。
Java7和Java8的比较:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2R7Mwij-1645079970545)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216120005346.png)][
可以将几个基础操作连接起来。来表达复杂的数据处理流水线。filter结果被传递给了sorted,sorted的结果被传递给了map,最后传递给collect方法。
流简介
流的简单定义:从支持数据处理数据操作的源生成的元素序列。
- 元素序列:就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。
- 源:流会使用一个提供数据的源,如集合、数组或输出/输入资源。从有序集合生成流时会保留原有的顺序。列表也是一样。
- 数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等。
示例:
分析:首先对menu调用stream方法,由菜单得到一个流。数据源是菜单,它给流提供一个元素序列。接下来,对流应用一些列数据处理操作:filter、map、limit和Collect之外。这些操作之后会返回另一个流,这样他们就可以接成一条流水线。
下图显示了流的操作流程:
- 😂filter:接受Lambda,从流中排除某些元素。
- map:接受一个Lambda,将元素转换成其他形式或提取信息。
- limit:截断流,使其元素不超过指定数量。
- collect:将流转换为其他形式。
流与集合
-
集合是一个内存中的数据结构,它包含数据结构中目前所有的值-集合中的每个元素都得先算出来才能添加到集合中。(你可以往集合里加东西或者删除东西,但是不管什么时候,集合中得每个元素都是放在内存里的,元素都得先算出来才能成为集合的一部分)
-
流则是在概念上固定的数据结构(你不能添加或删除元素),其元素则是按需计算的。流就像是一个延迟创建的集合:只有在消费者要求的时候才会计算值。集合则是急切创建的。
-
流只能遍历一次。
-
外部迭代与内部迭代
使用Collection接口需要用户去做迭代(比如使用for-each),这个称为**外部迭代。**而Stream库使用了内部迭代–它帮你把迭代做了,还把得到的流值存储在某个地方,你只要给出一个函数说要干什么就可以了。下面的代码是这俩种的区别:
流操作
使用流
一个流的使用一般包括三件事:
- 一个**数据源(如集合)**来执行一个查询
- 一个中间操作链,形成一条流的流水线
- 一个**终端操作,**执行于流水线,并能生成结果
常用的Stream API操作
使用流
筛选和切片
用谓词筛选
筛选出各异的元素
流还支持一个叫作distinct的方法,它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)。如下面的代码会筛选出**列表中所有的偶数,并保证没有重复。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mqC025RR-1645079970550)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216140056544.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nZWSzkV9-1645079970550)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216140134117.png)]
截断流
流支持limit(n)方法,该方法会返回一个不超过给定长度的流。所需的长度作为参数传递给limit.如果流是有序的,则最多会返回前n个元素。
跳过元素
流支持skip(n)方法,返回一个扔掉了前n个元素的流。如果流中元素不足n个,则会返回一个空流。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kAUyibJF-1645079970551)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216141201113.png)]
映射
对流中的每一个元素应用函数
流支持map方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并讲其映射成一个新的元素。
下面的代码把方法引用Dish::getName传给map方法,用来提前流中菜肴的名称:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QitcKchK-1645079970551)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216142258190.png)]
给定一个单词列表,显示每个单词中有几个字母:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CdMDmenq-1645079970552)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216142503228.png)]
流的扁平化
对于一张单词表,如何返回一张列表,列出里面各不相同的字符呢?
使用flatMap
flatmap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
查找和匹配
检查谓词是否至少匹配一个元素
anyMatch方法可以回答“流中是否有一个元素能匹配给定的谓词”。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wanwk3Hu-1645079970553)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220216153241534.png)]
检查谓词是否匹配所有元素
allMatch和anyMatch类似,但它会看看流中的元素是否都能匹配给定的谓词。
比如,可以用来看看采品是否有利健康
boolean isHealthy = menu.stream()
.allMatch(d -> d.getCalories() < 1000);
noneMatch
和allMatch相对的是noneMatch。它可以确保流中没有任何元素与给定的谓词匹配。
boolean isHealthy = menu.stream()
.noneMatch(d ->d.getCalories() >= 1000);
查找元素
findAny方法将返回当前流中的任意元素。它可以与其他流操作结婚使用。
可以结合使用filter和findAny方法来实现这个查询:
Optional<Dish> dish =
menu.stream()
.filter(Dish::isVegetarian)
.findAny();
查找第一个元素
归约
元素求和
对流中的所有元素求和:
int sum = numbers.stream().reduce(0,(a,b) ->a +b );
reduce接受两个参数:
最大值和最小值
使用reduce来计算流中的最大值:
Optional<Integer> max = numbers.stream().reduce(Integer::max);
如果要计算最小值:
Optional<Integer> max = numbers.stream().reduce(Integer::min);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uv5sUvKl-1645079970555)(C:\Users\QJS\AppData\Roaming\Typora\typora-user-images\image-20220217131112004.png)]
例子:
package lambdasinaction.chap5;
public class Trader{
private String name;
private String city;
public Trader(String n, String c){
this.name = n;
this.city = c;
}
public String getName(){
return this.name;
}
public String getCity(){
return this.city;
}
public void setCity(String newCity){
this.city = newCity;
}
public String toString(){
return "Trader:"+this.name + " in " + this.city;
}
}
package lambdasinaction.chap5;
public class Transaction{
private Trader trader;
private int year;
private int value;
public Transaction(Trader trader, int year, int value)
{
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader(){
return this.trader;
}
public int getYear(){
return this.year;
}
public int getValue(){
return this.value;
}
public String toString(){
return "{" + this.trader + ", " +
"year: "+this.year+", " +
"value:" + this.value +"}";
}
}
package lambdasinaction.chap5;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static java.util.Comparator.comparing;
/**
* 文件描述
*
* @Author: QJS
* @CreateDate: 2022/2/17 13:19
**/
public class TrancsactionTest {
public static void main(String[] args) {
Trader raoul = new Trader("Raoul","Cambridge");
Trader mario = new Trader("Mario","Milan");
Trader alan = new Trader("Alan","Cambridge");
Trader brian = new Trader("Brian","Cambridge");
List<Transaction> transactions = Arrays.asList(
new Transaction(brian,2011,300),
new Transaction(raoul,2012,1000),
new Transaction(raoul,2011,400),
new Transaction(mario,2012,710),
new Transaction(mario,2012,700),
new Transaction(alan,2012,950)
);
// 1 找出2011年的所有交易并按交易额排序
List<Transaction> tr2011 = transactions.stream()
.filter(transaction -> transaction.getYear() == 2011)
.sorted(comparing(Transaction::getValue))
.collect(Collectors.toList());
System.out.println(tr2011);
/**
* 2 交易员都在哪些城市工作过
*/
List<String> cities = transactions.stream()
.map(transaction -> transaction.getTrader().getCity())
.distinct()
.collect(Collectors.toList());
System.out.println(cities);
/**
* 3 查找所有来自与剑桥的交易员,并按照姓名进行排序
*/
List<Trader> cambridge1 = transactions.stream()
.map(Transaction::getTrader)
.filter(trader -> trader.getCity().equals("Cambridge"))
.distinct()
.sorted(comparing(Trader::getName))
.collect(Collectors.toList());
System.out.println(cambridge1);
/**
* 4 返回所有交易员的姓名字符串,按字母顺序排序
*/
String reduce = transactions.stream()
.map(transaction -> transaction.getTrader().getName())
.distinct()
.sorted()
.reduce(" ", (n1, n2) -> n1 + n2);
System.out.println(reduce);
/**
* 5 有没有交易员在米兰工作的
*/
boolean milan = transactions.stream()
.anyMatch(transaction -> transaction.getTrader().getCity().equals("Milan"));
System.out.println(milan);
/**
* 6 打印生活在剑桥的交易员的所有交易额
*/
transactions.stream()
.filter(transaction -> transaction.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.forEach(System.out::println);
/**
* 7 所有交易中,最大的交易额
*/
Optional<Integer> maxValue = transactions.stream()
.map(Transaction::getValue)
.reduce(Integer::max);
System.out.println(maxValue);
/**
* 8 所有交易中,最小的交易额
*/
Optional<Integer> minValue = transactions.stream()
.map(Transaction::getValue)
.reduce(Integer::min);
System.out.println(minValue);
}
}
构建流
由值创建流
可以使用静态方法Stream.of,通过显示值创建一个流。它可以接受任意数量的参数。
将字符串转换为大写字母并且一个个打印出来
Stream<String> stream = Stream.of("Java 8","Lambdas","In","Action");
stream.map(String::toUpperCase).forEach(System.out::println);
由数组创建流
使用静态方法Arrays.stream从数据创建一个流。接受一个数组作为参数。
将一个原始类型int的数组转换成一个IntStream,
int[] numbers = {2,3,5,7,11,13};
int sum = Arrays.stream(numbers).sum();
由文件生成流
由函数生成流:创建无限流
Stream API 提供了两个静态方法来从函数生成流:Stream.itreate和
Sream.generate.这两个操作可以创建所谓的无限流。
-
迭代
Stream.iterate(0,n -> n + 2) .limit(10) .forEach(System.out::println);
iterate方法生成了一个所有正偶数的流:流的第一个元素是初始值0,然后加上2生成新的值2,再加上2来得到新的值4.使用limit来限制大小。调用forEach终端来作消费流。
-
生成
generate方法可以让你按需生成一个无限流。但generate不是依次对每个新生成的值应用函数的。
Stream.generate(Math::random) .limit(5) .forEach(System.out::println);
tem.out.println(minValue);
}
}
### 构建流
#### 由值创建流
可以使用静态方法Stream.of,通过显示值创建一个流。它可以接受任意数量的参数。
将字符串转换为大写字母并且一个个打印出来
Stream stream = Stream.of(“Java 8”,“Lambdas”,“In”,“Action”);
stream.map(String::toUpperCase).forEach(System.out::println);
#### 由数组创建流
使用静态方法Arrays.stream从数据创建一个流。接受一个数组作为参数。
将一个原始类型int的数组转换成一个IntStream,
```java
int[] numbers = {2,3,5,7,11,13};
int sum = Arrays.stream(numbers).sum();
由文件生成流
[外链图片转存中…(img-zNI3h7UR-1645079970556)]
由函数生成流:创建无限流
Stream API 提供了两个静态方法来从函数生成流:Stream.itreate和
Sream.generate.这两个操作可以创建所谓的无限流。
-
迭代
Stream.iterate(0,n -> n + 2) .limit(10) .forEach(System.out::println);
iterate方法生成了一个所有正偶数的流:流的第一个元素是初始值0,然后加上2生成新的值2,再加上2来得到新的值4.使用limit来限制大小。调用forEach终端来作消费流。
-
生成
generate方法可以让你按需生成一个无限流。但generate不是依次对每个新生成的值应用函数的。
Stream.generate(Math::random) .limit(5) .forEach(System.out::println);