您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

Java函数式编程实例分析

2024/6/26 18:52:00发布24次查看
这篇“java函数式编程实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“java函数式编程实例分析”文章吧。
一、lambda表达式 1.1 函数式编程思想概述在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”
面向对象思想强调“必须通过对象的形式来做事情”
函数式思想强调则金量忽略面向对象的复杂语句:“强调做什么,而不是以什么形式去做”
而我们要学习的lambda表达式就是函数式思想的体现
1.2 体验lambda表达式需求:启动一个线程,在控制台输出一句话:多线程程序启动了
方式1:
定义一个类myrunnable接口,重写run方法
创建myrunnable类的对象
创建thread类对象,把myrunnable的对象作为构造参数传递
启动线程
public class myrunnable implements runnable { @override public void run() { system.out.println("多线程程序启动了"); }}
myrunnable myrunnable = new myrunnable(); thread thread = new thread(myrunnable); thread.start();
方式2:
在方式1的基础上进行改进,使用匿名内部类的方式
new thread(new runnable() { @override public void run() { system.out.println("多线程程序启动了"); } }).start();

方式3:
lambda表达式的方式改进:
new thread(() -> { system.out.println("多线程程序启动了"); }).start();

1.3 lambda表达式的标准格式匿名内部类中重写run()方法的代码分析:
方法形式参数为空,说明调用方法时不需要传递参数
方法返回值类型为void,说明方法执行没有结果返回
方法体中的内容,是我们具体要做的事情
new thread(new runnable() { @override public void run() { system.out.println("多线程程序启动了"); } }).start();

lambda表达式的代码分析:
():里面没有内容,可以看成是方法形式参数为空
->:用箭头指向后面要做的事情
{}:包含一段代码,我们称之为代码块,可以看成是方法体中的内容
new thread(() -> { system.out.println("多线程程序启动了"); }).start();

组成lambda表达式的三要素:形式参数、箭头、代码块
lambda表达式的格式:
格式:(形式参数)->{代码块}
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
1.4 lambda表达式的练习lambda表达式的使用前提
有一个接口
接口中有且仅有一个抽象方法
练习1:
定义一个接口(eatable),里面定义一个抽象方法:void eat();
定义一个测试类(eatabledemo),在测试类中提供两个方法:
一个方法是:useeatable(eatable e)
一个方法是主方法,在主方法中调用useeatable方法
定义一个接口:
public interface eatable { void eat();}
方式一:传统接口实现类
public class eatableimpl implements eatable{ @override public void eat() { system.out.println("一日三餐,必不可少"); }}
public class eatabledemo{ public static void main(string[] args) { eatable eatable = new eatableimpl(); eatable.eat(); } private static void useeatable(eatable eatable){ eatable.eat(); }}
方式2:匿名内部类
public class eatabledemo{ public static void main(string[] args) { useeatable(new eatable() { @override public void eat() { system.out.println("一日三餐,必不可少"); } }); } private static void useeatable(eatable eatable){ eatable.eat(); }}
方式3:lambda表达式
public class eatabledemo{ public static void main(string[] args) { useeatable(()->{ system.out.println("一日三餐,必不可少"); }); } private static void useeatable(eatable eatable){ eatable.eat(); }}
运行结果均相同
练习2:
定义一个接口(flyable),里面定义一个抽象方法:void fiy(string s);
定义一个测试类(flyabledemo),在测试类中提供两个方法
一个方法是:useflyable(flyable f)
一个方法是主方法,在主方法中调用useflayable方法
public interface flyable { void fly(string s);}
public class flyabledemo { public static void main(string[] args) { useflyable(new flyable() { @override public void fly(string s) { system.out.println(s); system.out.println("飞机可以起飞"); } }); system.out.println("--------------------"); useflyable((string s)->{ system.out.println(s); system.out.println("飞机可以起飞"); }); } private static void useflyable(flyable flyable){ flyable.fly("风和日丽,晴空万里"); }}
练习3:
定义一个接口(addable),里面定义一个抽象方法:int add(int x,int y);
定义一个测试类(addabledemo),在测试类中提供两个方法
一个方法是:useaddable(addable a)
一个方法是主方法,在主方法中调用useaddable方法
public interface addable { int add(int x,int y);}
public class addabledemo { public static void main(string[] args) { useaddable(new addable() { @override public int add(int x, int y) { return x + y; } }); useaddable((int x,int y)->{ return x + y; }); } private static void useaddable(addable addable) { int sum = addable.add(10, 20); system.out.println(sum); }}
1.5 lambda表达式的省略模式省略规则:
参数类型可以省略。如果有多个参数的情况下,不能只省略一个
如果参数有且仅有一个,那么小括号可以省略
如果代码块的语句只有一条,可以省略大括号和分号,甚至时return
public class lambdademo5 { public static void main(string[] args) { //参数类型可以省略 useaddable((x, y) -> { return x + y; }); system.out.println("------------------------"); //如果只有一个参数,小括号也可以省略 useflyable(s -> { system.out.println(s); }); system.out.println("------------------------"); //如果代码块的语句只有一条,可以省略大括号和分号(有return时要把return也去掉) useflyable(s -> system.out.println(s) ); useaddable((x,y)->x+y); } private static void useflyable(flyable flyable) { flyable.fly("风和日丽,晴空万里"); } private static void useaddable(addable addable) { int sum = addable.add(10, 20); system.out.println(sum); }}
接口类参考1.4
1.6 lambda表达式的注意事项注意事项:
使用lambda必须要有接口,并且要求接口中有且仅有一个抽象的方法
必须有上下文环境,才能推导出lambda对应的接口
根据局部变量的赋值得知lambda对应的接口:runnable r =() ->system.out.println(“lambda表达式”);
根据调用方法的参数得知lambda对应的接口:new thread(()->system.out.println(“lambda表达式”)).start();
public interface inter { void show();}
public class lambdademo6 { public static void main(string[] args) { useinter(()-> system.out.println("lambda表达式") ); new thread(new runnable() { @override public void run() { system.out.println("匿名内部类"); } }).start(); runnable r = () -> system.out.println("lambda表达式"); new thread(r).start(); new thread(()-> system.out.println("lambda表达式") ).start(); } private static void useinter(inter inter){ inter.show(); }}
1.7 lambda表达式和匿名内部类的区别所需类型不同:
匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
lambda表达式:只能是接口
使用限制不同:
如果接口中有且仅有一个抽象方法,可以使用lambda表达式,也可以使用匿名内部类
如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用lambda表达式
实现原理不同:
匿名内部类:编译之后,产生一个单独的.class字节码文件
lambda表达式:编译之后,没有一个单独的.class字节码文件,对应的字节码会在运行的时候动态生成
二、接口组成更新1.1 接口组成更新概述接口的组成:
常量:public static final
抽象方法:public abstract
默认方法(java 8)
静态方法(java 8)
私有方法 (java 8)
1.2 接口中默认方法接口中默认方法得定义格式:
格式:public default 返回值类型 方法名(参数列表){}
范例:public default void show3(){}
接口中默认方法的注意事项:
默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
public可以省略,default不能重写
public interface myinterface { void show1(); void show2(); default void show3(){ system.out.println("show3"); }}
public class myinterfaceimplone implements myinterface{ @override public void show1() { system.out.println("one show1"); } @override public void show2() { system.out.println("one show2"); }}
public class myinterfaceimpltwo implements myinterface{ @override public void show1() { system.out.println("two show1"); } @override public void show2() { system.out.println("two show2"); }}
public class interfacedemo { public static void main(string[] args) { myinterface myinterface = new myinterfaceimplone(); myinterface.show1(); myinterface.show2(); myinterface.show3(); system.out.println("------------------"); myinterface myinterface2 = new myinterfaceimpltwo(); myinterface2.show1(); myinterface2.show2(); myinterface2.show3(); }}
运行结果:
one show1
one show2
show3
------------------
two show1
two show2
show3
1.3 接口中静态方法接口中静态方法的定义格式:
格式:public static 返回值类型 方法名(参数列表){ }
范例:public static void show(){ }
接口中静态方法的注意事项:
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public可以省略,static不能省略
public interface inter { void show(); default void method() { system.out.println("inter 中的默认方法执行了"); } public static void test(){ system.out.println("inter 中的静态方法执行了"); }}
public class interimpl implements inter{ @override public void show() { system.out.println("show方法执行了"); }}
public class interdemo { public static void main(string[] args) { inter inter = new interimpl(); inter.show(); inter.method(); inter.test(); } }
1.4 接口中私有方法java 9中新增了带方法体的私有方法,这其实在java 8中就埋下了伏笔:java 8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题:当两个默认方法或者静态方法中包含一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法时不需要让别人使用的,因此用私有给隐藏起来,这就是java 9增加私有方法的必然性。
接口中私有方法的定义格式:
格式1:private 返回值类型方法名(参数列表){ }
范例1:private void show(){ }
格式2:private static 返回值类型 方法名(参数列表){ }
范例2:private static void method(){ }
接口中私有方法的注意事项:
默认方法可以调用私有的静态方法和非静态方法
静态方法只能调用私有的静态方法
public interface inter { default void show1(){ system.out.println("show1开始执行"); method(); system.out.println("show1结束执行"); } default void show2(){ system.out.println("show2开始执行"); method(); system.out.println("show2结束执行"); } static void method1(){ system.out.println("method1开始执行"); method(); system.out.println("method1结束执行"); } static void method2(){ system.out.println("method2开始执行"); method(); system.out.println("method2结束执行"); } static void method(){ system.out.println("初级工程师"); system.out.println("中级工程师"); system.out.println("高级工程师"); }}
public class interimpl implements inter{}
public class interdemo { public static void main(string[] args) { inter inter = new interimpl(); inter.show1(); system.out.println("------------------------"); inter.show2(); system.out.println("------------------------"); inter.method1(); system.out.println("------------------------"); inter.method2(); }}
三、方法引用1.1 体验方法引用通过方法引用来使用已经存在的方案
public interface printable { void printstring(string s);}
public class printabledemo { public static void main(string[] args) { useprintable(s-> system.out.println(s) ); useprintable(system.out::println); } private static void useprintable(printable p){ p.printstring("hello world"); }}
1.2 方法引用符::该符号为引用运算符,而它所在表达式被称为方法引用符
lambda表达式:useprintable(s->system.out.println(s));
分析:拿到参数s之后通过lambda表达式,传递给system.out.println方法去处理
方法引用:useprintable(system.out::println);
分析:直接使用system.out中的println方法来取代lambda,代码更加的简洁
推导与省略:
如果使用lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导
如果使用方法引用,也同要可以根据上下文进行推导
方法引用是lambda的孪生兄弟
public interface printable { void printint(int i);}
public class printabledemo2 { public static void main(string[] args) { useprintable(i -> system.out.println(i)); useprintable(system.out::println); } private static void useprintable(printable printable){ printable.printint(1); }}
1.3 lambda表达式支持的方法引用常见的引用方式:
引用类方法
引用对象的实例方法
引用类的实例方法
引用构造器
1.4 引用类方法引用类方法,其实就是引用类的静态方法
格式:类名::静态方法
范例:integer::parseint
integer类的方法:public static int parsenint(string s),将此string转换为int类型数据
lambda表达式被类方法替代的时候,它的形式参数全部传递给静态方法作为参数
public interface converter { int convert(string s);}
public class converterdemo { public static void main(string[] args) { useconverter(s -> integer.parseint(s)); useconverter(integer::parseint); } private static void useconverter(converter c) { int number = c.convert("666"); system.out.println(number); }}
1.5 引用对象的实例方法引用对象的实例方法,其实就是引用类中的成员方法
格式:对象::成员方法
范例:“helloworld"::touppercase
string 类中的方法:public string touppercase()将此string所有字符转为大写
lambda表达式被对象的实例方法替代的时候,它的形式参数全部传递给该方法作为参数
public interface printer { void printuppercase(string s);}
public class printstring { public void printupper(string s){ string result = s.touppercase(); system.out.println(result); }}
public class printerdemo { public static void main(string[] args) { useprinter(s -> system.out.println(s.touppercase())); printstring printstring = new printstring(); useprinter(printstring::printupper); } private static void useprinter(printer printer) { printer.printuppercase("helloworld"); }}
1.6 引用类的实例方法引用类的实例方法,其实就是引用类中的成员方法
格式:类名::成员方法
范例:string::substring
string类中的方法:public string substring(int beginindex,int endindex)从beginindex开始到endindex结束,截取字符串。返回一个子串,字串的长度为endindex-beginindex
lambda表达式被类的实例方法替代的时候,第一个参数作为调用者,后面的参数全部传递给该方法作为参数
public interface mystring { string mysubstring(string s, int x, int y);}
public class mystringdemo { public static void main(string[] args) { usemystring((s, x, y) -> s.substring(x, y)); usemystring(string::substring); } private static void usemystring(mystring mystring){ string s = mystring.mysubstring("helloworld", 5, 10); system.out.println(s); }}
1.7 引用构造器引用构造器,其实就是引用构造方法
格式:类名::new
范例:student::new
lambda表达式被构造器代替的时候,它的形式参数全部传递给构造器作为参数
public class student { private string name; private int age; public string getname() { return name; } public void setname(string name) { this.name = name; } public int getage() { return age; } public void setage(int age) { this.age = age; } public student() { } public student(string name, int age) { this.name = name; this.age = age; }}
public interface studentbuilder { student build(string name,int age);}
public class studentdemo { public static void main(string[] args) { usestudentbuilder((name, age) -> new student(name,age)); usestudentbuilder(student::new); } private static void usestudentbuilder(studentbuilder studentbuilder){ student student = studentbuilder.build("xuanxuan", 22); system.out.println(student.getname()+","+student.getage()); }}
四、函数式接口1.1 函数接口概述函数式接口:有且仅有一个抽象方法的接口
java中的函数式编程体现就是lambda表达式,所以函数式接口就是可以使用于lambda使用的接口
只有确保接口中有且仅有一个抽象方法,java中的lambda才能顺利地进行推导
如何检测一个接口是不是函数式接口呢?
@functionalinterface
放在接口定义的上方:如果接口是函数接口,编译通过;如果不是,编译失败
注意:
我们自己定义函数式接口的时候,@functionalinterface是可选的,就算我们不写这个注解,只要保证满足函数式接口定义的条件,也照样是函数式接口。但是,建议加上注解。
@functionalinterfacepublic interface myinterface { void show();}
public class myinterfacedemo { public static void main(string[] args) { myinterface myinterface = ()-> system.out.println("函数式接口"); myinterface.show(); }}
1.2 函数式接口作为方法的参数如果方法的参数是一个函数式接口,我们可以使用lambda表达式作为参数传递
startthread(() -> system.out.println(thread.currentthread().getname() + "线程启动了"));
public class runnabledemo { public static void main(string[] args) { startthread(new runnable() { @override public void run() { system.out.println(thread.currentthread().getname() + "线程启动了"); } }); startthread(() -> system.out.println(thread.currentthread().getname() + "线程启动了")); startthread(()->{ system.out.println(thread.currentthread().getname() + "线程启动了"); }); } private static void startthread(runnable runnable) { new thread(runnable).start(); }}
1.3 函数式接口作为方法的返回值如果方法的返回值是一个函数式接口,我们可以使用lambda表达式作为结果返回
private static comparator<string> getcomparator() { return (s1,s2) -> s1.length() - s2.length(); }
public class comparatordemo { public static void main(string[] args) { arraylist<string> arraylist = new arraylist<string>(); arraylist.add("ccc"); arraylist.add("aa"); arraylist.add("dddd"); arraylist.add("b"); system.out.println("排序前" + arraylist); collections.sort(arraylist); system.out.println("排序后" + arraylist); collections.sort(arraylist, getcomparator()); system.out.println("使用定义比较器排序方法后:" + arraylist); } private static comparator<string> getcomparator() {// return new comparator<string>() {// @override// public int compare(string s1, string s2) {// return s1.length() - s2.length();// }// }; return (s1,s2) -> s1.length() - s2.length(); }}
1.4 常用的函数式接口java 8 在java.util.function包下预定了大量的函数式接口供我们使用,常用如下:
supplier接口
consumer接口
predicate接口
function接口
1.5 supplier接口supplier接口
t get():获得结果
该方法不需要参数,它会按照某种实现逻辑(由lambda表达式实现)返回一个数据
supplier 接口也被称为生产型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用
public class supplierdemo { public static void main(string[] args) { string s = getstring(() -> "xuanxuan"); system.out.println(s); integer i = getinteger(() -> 666); system.out.println(i); } public static string getstring(supplier<string> supplier) { return supplier.get(); } public static integer getinteger(supplier<integer> supplier) { return supplier.get(); }}
练习:获取最大值
public class supplierdemo { public static void main(string[] args) { int[] arr = new int[]{17, 28, 49, 21, 32, 66}; int maxnumber = getmax(() -> { int max = arr[0]; for (int i = 1; i < arr.length; i++) { if (max < arr[i]) { max = arr[i]; } } return max; }); system.out.println("数组中的最大值是:" + maxnumber); } private static int getmax(supplier<integer> supplier) { return supplier.get(); }}
1.6 consumer接口consumer:包含两个方法
void accept(t t):对给定的参数执行此操作
default consumer andthen(consumer after):返回一个组合的consumer,依次执行此操作,然后执行after操作
consumer 接口也被称为消费型接口,它消费的数据类型由泛型指定
public class consumerdemo { public static void main(string[] args) { operatorstring("abc", s -> system.out.println(s)); operatorstring("abc", system.out::println); operatorstring("abc", s -> system.out.println(new stringbuilder(s).reverse().tostring())); system.out.println("----------------------------------"); operatorstring("abc", s -> system.out.println(s), s -> system.out.println(new stringbuilder(s).reverse().tostring())); } private static void operatorstring(string name, consumer<string> consumer) { consumer.accept(name); } private static void operatorstring(string name, consumer<string> consumer1, consumer<string> consumer2) {// consumer1.accept(name);// consumer2.accept(name); consumer1.andthen(consumer2).accept(name); }}
练习:
字符串数组中又多条信息,按照:“姓名:name,年龄:age"的格式将信息打印出来
public class consumerdemo { public static void main(string[] args) { string[] arr = new string[]{"abc,30", "cbd,35", "dna,33"}; printinfo(arr, s -> system.out.print("姓名:" + s.split(",")[0] + ","), s -> system.out.println("年龄:" + integer.parseint(s.split(",")[1]))); } private static void printinfo(string[] arr, consumer<string> consumer1, consumer<string> consumer2) { for (string s : arr) { consumer1.andthen(consumer2).accept(s); } }}
1.7 predicate接口常用方法:
练习:判断给定的字符串是否满足要求
public class predicatedemo { public static void main(string[] args) { boolean b1 = checkstring("hello", s -> s.length() > 5); system.out.println(b1); boolean b2 = checkstring("helloworld", s -> s.length() > 8); system.out.println(b2); boolean b3 = checkstring("hello", s -> s.length() > 5, s -> s.length() > 8); system.out.println(b3); boolean b4 = checkstring("helloworld", s -> s.length() > 5, s -> s.length() > 8); system.out.println(b4); } private static boolean checkstring(string s, predicate<string> predicate) { return predicate.test(s); } private static boolean checkstring(string s, predicate<string> predicate, predicate<string> predicate2) {// return predicate.and(predicate2).test(s); return predicate.or(predicate2).test(s); }}
练习2:
string[] strarray ={“孙悟空,30”,“唐僧,36”,“沙僧,34”,“猪八戒,32”,“白骨精,5000”}
字符串数组中有多条信息,请通过predicate接口的拼装将符合要求的字符串筛选到集合arraylitst中,并遍历arraylitst集合
同时满足如下要求:name长度大于2,age大于33
public class predicatedemo3 { public static void main(string[] args) { string[] strarray = new string[]{"孙悟空,30", "唐僧,36", "沙僧,34", "猪八戒,32", "白骨精,5000"}; arraylist<string> arraylist = myfilter(strarray, s -> s.split(",")[0].length() > 2, s -> integer.parseint(s.split(",")[1]) > 33); system.out.println("name长度大于2,age大于33有:"); for (string s : arraylist) { system.out.print("name:" + s.split(",")[0] + ","); system.out.println("age:" + integer.parseint(s.split(",")[1])); } } private static arraylist<string> myfilter(string[] strarray, predicate<string> predicate1, predicate<string> predicate2) { arraylist<string> arraylist = new arraylist<string>(); for (string s : strarray) { if (predicate1.and(predicate2).test(s)) { arraylist.add(s); } } return arraylist; }}
1.8 function接口function<t,r>两个常用方法:
function<t,r>接口通常用于对参数进行处理,转换(处理逻辑由lambda表达式实现)然后返回一个新的值
练习:
public class functiondemo { public static void main(string[] args) { convert("100", s -> integer.parseint(s)); convert("100", integer::parseint); convert(100, i -> string.valueof(100 + i)); convert("100", s -> integer.parseint(s), i -> string.valueof(i + 566)); } //定义一个方法,把一个int类型的数据加上一个整数之后,转为字符串在控制台输出 private static void convert(string s, function<string, integer> function) { integer i = function.apply(s); system.out.println(i); } //定义一个方法,把一个int类型的数据加上一个整数之后,转为字符串在控制台输出 private static void convert(int i, function<integer, string> function) { string s = function.apply(i); system.out.println(s); } //定义一个方法,把一个字符串转换为int类型,把int类型的数据加上一个整数之后,转为字符串在控制台输出 private static void convert(string s, function<string, integer> function1, function<integer, string> function2) { string ss = function2.apply(function1.apply(s)); system.out.println(ss); }}
练习2:提取string中的年龄加70岁,并以int型输出
public class functiondemo { public static void main(string[] args) { string s = "孙悟空,30"; convert(s, s1 -> s1.split(",")[1], s1 -> integer.parseint(s1) + 70); } private static void convert(string s, function<string, string> function1, function<string, integer> function2) { integer i = function2.apply(function1.apply(s)); system.out.println(i); }}
五、stream流1.1 体验stream流需求:按照下面的要求完成集合的创建和遍历
创建一个集合,存储多个字符串元素
把集合中所有以“张”开头的元素存储到一个新的集合再
把长度为3的元素存储到一个新集合
最后遍历上一步得到的集合
使用stream流的方式完成过滤操作:
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:生成流、过滤姓氏、过滤长度为3、逐一打印
stream流把真正的函数式编程风格引入到java中
list.stream().filter(s -> s.startswith("张")).filter(s -> s.length() == 3).foreach(s -> system.out.println(s));
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("张飞"); list.add("张三丰"); list.add("张三"); list.add("李四"); list.add("孙悟空"); list.add("张一飞"); arraylist<string> zhanglist = new arraylist<string>(); for (string s : list) { if (s.startswith("张")) { zhanglist.add(s); } } arraylist<string> treelist = new arraylist<string>(); for (string s : zhanglist) { if (s.length() == 3) { treelist.add(s); } } for (string s : treelist) { system.out.println(s); } system.out.println("-------------------------------"); //stream流改进 list.stream().filter(s -> s.startswith("张")).filter(s -> s.length() == 3).foreach(s -> system.out.println(s)); }}
1.2 stream流的生成方式stream流的使用
生成流:通过数据源(集合、数组等)生成流
list.stream();
中间操作:一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用
filter()
终结操作:一个流只能有一个终结操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作
foreach()
stream流的常见生成方式
collection体系的集合可以使用默认方法stream()生成流
default stream<e> stream()
map体系的集合间接的生成流
数组可以通过stream接口的静态方法of(t&hellip;values)生成流
public class streamdemo { public static void main(string[] args) { list<string> list = new arraylist<string>(); stream<string> liststream = list.stream(); set<string> set = new hashset<string>(); stream<string> setstream = set.stream(); map<string, integer> map = new hashmap<string, integer>(); stream<string> keystream = map.keyset().stream(); stream<integer> valuestream = map.values().stream(); stream<map.entry<string, integer>> entrystream = map.entryset().stream(); string[] strarray = {"hello", "world", "java"}; stream<string> strarraystream = stream.of(strarray); stream<string> strarraystream2 = stream.of("hello", "world", "java"); stream<integer> strarraystream3 = stream.of(10, 20, 30); }}
1.3 stream流的常见中间操作方法stream filter(predicate predicate):用于对流中的数据进行过滤
predicate接口中的方法:boolean test(t t):对给定的参数进行判断,返回一个布尔值
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("张飞"); list.add("张三丰"); list.add("张三"); list.add("李四"); list.add("孙悟空"); list.add("张一飞"); list.stream().filter(s -> s.startswith("张")).foreach(system.out::println); system.out.println("----------------------"); list.stream().filter(s -> s.length() == 3).foreach(system.out::println); system.out.println("----------------------"); list.stream().filter(s -> s.startswith("张")).filter(s -> s.length() == 3).foreach(system.out::println); }}
stream limit(long maxsize):返回此流中的元素组成的流,截取前指定参数个数的数据
stream skip(long n):跳过指定参数个数的数据,返回由该流的剩余元素组成的流
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("张飞"); list.add("张三丰"); list.add("张三"); list.add("李四"); list.add("孙悟空"); list.add("张一飞"); //取前三个数据在控制台输出 list.stream().limit(3).foreach(system.out::println); system.out.println("-----------------------------"); //跳过2个元素,把剩下的元素在控制台上输出 list.stream().skip(2).foreach(system.out::println); system.out.println("-----------------------------"); //跳过2个元素并将剩下元素的前两个元素在控制台上输出 list.stream().skip(2).limit(2).foreach(system.out::println); }}
stream stream concat(stream a,stream b):合并a和b两个流为一个流
stream distinct:返回由该流的不同元素(根据objectequals(object))组成的流
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("张飞"); list.add("张三丰"); list.add("张三"); list.add("李四"); list.add("孙悟空"); list.add("张一飞"); //需求1:取前4个数据组成一个流 stream<string> limitstream = list.stream().limit(4); //需求2:跳过2个数据组成一个流 stream<string> skipstream = list.stream().skip(2); //需求3:合并需求1和需求2得到的流,并把结果在控制台输出// stream.concat(limitstream,skipstream).foreach(system.out::println); //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复 stream.concat(limitstream,skipstream).distinct().foreach(system.out::println); }}
stream sorted():返回由此流的元素组成的流,根据自然顺序排序
stream sorted(comparator comparator):返回由该流的元素组成的流,根据提供的comparator进行排序
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("zhangfei"); list.add("zhangsanfeng"); list.add("zhangsan"); list.add("lisi"); list.add("sunwukong"); list.add("zhangyifei"); //需求1:按照字母顺序把数据在控制台输出 list.stream().sorted().foreach(system.out::println); //需求2:按照字符串长度把数据在控制台输出 list.stream().sorted((s1, s2) -> { int num = s1.length() - s2.length(); int num2 = num == 0 ? s1.compareto(s2) : num; return num2; }).foreach(system.out::println); }}
stream map(function mapper):返回由给定函数应用于此流的元素的结果组成的流(function接口中的方法 r apply(t t))
intstream maptoint(tointfunction mapper):返回一个intstream其中包含将给定函数应用于此流的元素的结果
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("10"); list.add("20"); list.add("30"); list.add("40"); list.add("50");// list.stream().map(s -> integer.parseint(s)).foreach(system.out::println); list.stream().map(integer::parseint).foreach(system.out::println); list.stream().maptoint(integer::parseint).foreach(system.out::println); int result = list.stream().maptoint(integer::parseint).sum(); system.out.println(result); }}
1.4 stream流的常见终结操作方法void foreach(consumer action):对此流的每个元素执行操作(consumer接口中的方法 void accept(t t):对给定的参数执行此操作)
long count():返回此流中的元素数
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("张飞"); list.add("张三丰"); list.add("张三"); list.add("李四"); list.add("孙悟空"); list.add("张一飞"); //需求1:把集合中的元素在控制台输出 list.stream().foreach(system.out::println); //需求2:统计集合中有几个姓张的元素并在控制台输出 list.stream().filter(s -> s.startswith("张")).foreach(system.out::println); }}
1.5 stream流的练习现在又两个arraylist集合,分别存储6名男演员和6名女演员名称,要求完成如下操作
男演员只要名字为3个字的前三人
女演员只要姓林的,并且不要第一个
把过滤后的男演员姓名和女演员姓名合并到一起
把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据(演员类actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法)
public class streamdemo { public static void main(string[] args) { arraylist<string> manlist = new arraylist<string>(); manlist.add("周润发"); manlist.add("成龙"); manlist.add("刘德华"); manlist.add("吴京"); manlist.add("周星驰"); manlist.add("李连杰"); arraylist<string> womanlist = new arraylist<string>(); womanlist.add("林心如"); womanlist.add("张曼玉"); womanlist.add("林青霞"); womanlist.add("柳岩"); womanlist.add("林志玲"); womanlist.add("王祖贤"); //男演员只要名字为3个字的前三人 stream<string> manstream = manlist.stream().filter(s -> s.length() == 3).limit(3); //女演员只要姓林的,并且不要第一个 stream<string> womanstream = womanlist.stream().filter(s -> s.startswith("林")).skip(1); //把过滤后的男演员姓名和女演员姓名合并到一起 stream<string> stream = stream.concat(manstream, womanstream); //把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据 stream.map(actor::new).foreach(p -> system.out.println(p.getname())); system.out.println("------------------------------------"); //改进 stream.concat(manlist.stream().filter(s -> s.length() == 3).limit(3), womanlist.stream().filter(s -> s.startswith("林")).skip(1)).map(actor::new).foreach(p -> system.out.println(p.getname())); }}
1.6 stream流的收集操作对数据使用stream流的方式操作完毕后,如何把流中的数据收集到集合中?
stream流的手机方法
r collect(collector collector)
但是这个收集方法的参数是一个collector接口
工具类collectors提供了具体的收集方式:
public static collector tolist():把元素收到list集合中
public static collector toset():把元素收集到set集合中
public static collector tomap(function keymapper,function valuemapper):把元素收集到map集合中
public class streamdemo { public static void main(string[] args) { arraylist<string> list = new arraylist<string>(); list.add("张飞"); list.add("张三丰"); list.add("张三"); list.add("李四"); list.add("孙悟空"); list.add("张一飞"); //需求1:得到名字为3个字的流 stream<string> liststream = list.stream().filter(s -> s.length() == 3); //需求2:把使用stream流操作完毕的数据收集到list集合中并遍历 list<string> collect = liststream.collect(collectors.tolist()); for (string s : collect) { system.out.println(s); } set<integer> set = new hashset<integer>(); set.add(10); set.add(20); set.add(30); set.add(33); set.add(35); //需求3:得到年龄大于25的流 stream<integer> integerstream = set.stream().filter(age -> age > 25); //需求4:把使用stream流操作完毕的数据收集到set集合中并遍历 set<integer> collect2 = integerstream.collect(collectors.toset()); for (integer i : collect2) { system.out.println(i); } string[] strarray = {"张飞,28", "张三丰,33", "张三,26", "李四,44"}; //需求5:得到字符串年龄中数据大于28的流 stream<string> stringstream = stream.of(strarray).filter(s -> integer.parseint(s.split(",")[1]) > 28); //需求6:把使用stream流操作完毕的数据收集到map集合中并遍历,字符串的姓名作为键,年龄作为值 map<string, integer> map = stringstream.collect(collectors.tomap(s -> s.split(",")[0], s -> integer.parseint(s.split(",")[1]))); set<string> keyset = map.keyset(); for (string key : keyset) { integer value = map.get(key); system.out.println(key + "," + value); } }}
以上就是java函数式编程实例分析的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product