java8 新特性(接口更新+方法引用+函数式接口+Stream流)+java 9模块化
1.接口组成更新
接口的组成
- 常量
public static final - 抽象方法
public abstract - 默认方法(java 8)
- 静态方法(java 8)
- 私有方法(java 9)
1.1 接口中的默认方法
方便实现接口的升级,而不破坏现有代码。
应用场景如已有接口和实现类,此时为新增实现类添加方法更新接口,用默认方法来定义。
原有的实现类不更新也不会报错,不用去大量的修改原有实现类,也不用写新的子接口去继承原有接口类。
- 格式 :
public default 返回值类型 方法名(参数列表){}
如 public default void show3(){} - 注意事项
- 默认方法不是抽象方法有方法体,所以不强制重写,但是可以被重写,重写时去掉default关键字
- public可以省略,但是default不可以省略
例
public interface MyInterface {
void show1();
void show2();
default show3();
}
//////////////////
public class MyInterfaceImplOne implements MyInterface{
public void show1(){
System.out.println("one show1");
}
public void show2(){
System.out.println("one show2");
}
}
/////////////////
public class MyInterfaceTwo implements MyInterface{
public void show1(){
System.out.println("two show1");
}
public void show2(){
System.out.println("two show2");
}
}
////////////////
public class MyInterfaceDemo {
public static void main(String[] args){
MyInterface my =new MyInterfaceImplOne();
my.show1();
my.show2();
}
}
//////////////
public class MyInterfaceThree implements MyInterface{
public void show1(){
System.out.println("3 show1");
}
public void show2(){
System.out.println("3 show2");
}
public void show3(){
System.out.println("3 show3");
}
}
1.3 接口中静态方法
- 格式:
public static 返回值类型方法名(参数列表){}
如 public static void show(){} - 注意事项
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用。
(否则实现类继承多个接口,含有同名的静态方法,无法判断具体使用哪个。静态方法在接口中有方法体,不在实现类中实现) - public可以省略,static不能省略
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用。
1.4 接口中的私有方法
引入原因:java8埋下伏笔,两个默认方法或者静态方法中包含一段相同的代码,考虑提取成一个共性方法,仅在接口内的方法使用,所以时私有的
- 格式:
- private 返回值类型 方法名(参数列表){}
如:private void show() - private static 返回值类型 方法名(参数列表){}
如: private static void method{}
- private 返回值类型 方法名(参数列表){}
- 注意事项
- 默认方法可以调用私有的静态方法和非静态方法
- 静态方法只能调用私有的静态方法
2. 方法引用
2.1概述
引用符:
-
::为引用运算符,它所在的表达式称为方法引用
-
Lambda表达式:usePrintable(s->System.out.println(s);
分析拿到参数s之后通过Lambda表达式,传递给System.out.println(s) -
方法引用: usePrintable(System.out::println);
分析:直接使用System.out中的println方法取代Lambda,代码更加的简洁 -
推导与省略
- 如果使用Lambda,那么根据“可推到就是可省略”的原则,无需指定参数类型,也无需指定重载形式,它们都将被自动推导
- 如果使用方法引用,同样可以根据上下文进行推导
- 引用方法和lambda是孪生兄弟,要传递给Lambda体的操作,已经有了实现方法,就可以使用引用方法。
实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致
2.2 Lambda表达式支持的方法引用
- 常见的应用方式:
- 引用类方法, 类名::静态方法
例:Integer::parserInt - 引用对象的实例方法, 对象::成员方法
例:“HelloWorld”::toUpperCase()将所有字符转换为大写 - 引用类的实例方法, 类名::成员方法
例String::substring
注意**lambda表达式被类的实例方法替代的时候。引用处写法没差别,但是实际接口调用方法处,第一个参数作为调用者,后面的参数传递给方法体 - 引用构造器,类名::new
lambda表达式被构造器引用替代时,它的形参全部传递给构造器作为参数
- 引用类方法, 类名::静态方法
例 引用“类方法"
public class ConvertDemo {
public static void main(String[] args) {
useConvert(Integer::parseInt);
}
private static void useConvert(Convert c){
int number = c.convert("666");
System.out.println(number);
}
}
/////////
public interface Convert {
public int convert(String s);
}
例 引用对象方法
public class PrinterDemo {
public static void main(String[] args) {
PrintString p = new PrintString();
usePrinter(p::printUpper);
}
private static void usePrinter(Printer p){
p.printUpperCase("HelloWorld");
}
}
////////////
public interface Printer {
public void printUpperCase(String s);
}
///////////
public class PrintString {
public void printUpper(String s){
String result = s.toUpperCase();
System.out.println(result);
}
}
例引用类的实例方法
public class MyStringDemo {
public static void main(String[] args) {
/* useMyString((String s ,int x, int y)->{
s.substring(2, 4)
});*/
useMyString((s,x,y)->s.substring(x,y));
useMyString(String::substring);
//lambda表达式被类的实例方法替代的时候
//第一个参数作为调用者,后面的参数传递给方法体
}
private void useMyString(MyString my){
//引用处写法没差别,但是实际接口调用方法处,第一个参数作为调用者,后面的参数传递给方法体
String s = my.mySubString("hello world", 2, 4);
System.out.println(s);
}
}
////////
public interface MyString {
String mySubString(String s,int x,int y);
}
例 引用构造器
public class StudnetDemo {
public static void main(String[] args) {
useStudentBuilder((name,age)->new Student(name,age));
useStudentBuilder(Student::new);
//lambda表达式被构造器引用替代时,它的形参全部传递给构造器作为参数
}
private void useStudentBuilder(StudentBuilder s){
Student st = s.build("zhangmanyu", 39);
System.out.println(st.getName()+","+st.getAge());
}
}
//////////////
public interface StudentBuilder {
Student build(String name, int age);
}
3 函数式接口
3.1 什么是函数式接口
函数式接口:有且只有一个抽象方法的接口
建议使用@FunctionalInterface注解标识函数式接口,方便阅读。且会自动检验接口是否符合函数式接口要求
3.2 函数式接口作为方法的参数
如果一个方法的参数是函数式接口,则可以用lambda表达式作为参数传递
例 需求:
- 定义一个类(RunnableDemo),在类中提供两个方法
一个方法startThread(Runnable r)方法参数Runnable是一个函数式接口
一个方法是主方法,在该方法中调用startThread方法
public class RunnableDemo {
public static void main(String[] args) {
startThread(new Runnable(){
public void run() {
System.out.println(Thread.currentThread().getName()+"thread start");
}
});
startThread(()->System.out.println(Thread.currentThread().getName()+"thread start"));
}
private static void startThread(Runnable r){
new Thread(r).start();
}
}
3.3 函数式接口作为方法的返回值
如果方法的返回值是一个函数式接口,则可以用lambda表达式作为结果返回
需求
- 定义一个类(ComparatorDemo) 在类中提供两个方法
一个方法是:ComparatorgetComparator(),返回值Comparator是一个函数式接口
一个方法是主方法,在方法中调用Comparator方法
例:
public class ComparatorDemo {
public static void main(String[] args) {
ArrayList<String> array = new ArrayList<String>();
array.add("ccccc");
array.add("dd");
array.add("aaa");
System.out.println("before sort "+ array);
Collections.sort(array);
System.out.println("after sort "+ array);
Collections.sort(array, getComparator());
System.out.println("after sort "+ array);
}
//
static Comparator<String> getComparator(){
return new Comparator<String>(){
public int compare(String s1, String s2) {
return s1.length()-s2.length();
}
};
//return ((s1,s2)->s1.length()-s2.length())
}
}
注意 :Comparator是函数式接口,里面只有compareto方法式抽象方法。
其他方法都有方法体,equals方法是对Object里的方法的重新声明,为了加注释用的,也不是抽象方法
3.4 常用的函数式接口
java 8 在java.util.function包下提供了大量函数式接口
四个重点接口
- Supplier接口
- Consumer接口
- Predicate接口
- Function接口
3.4.1 Supplier接口
Supplier
- T get()包含一个无参的get方法
- 方法不需要参数,会按照某种实现逻辑(由Lambda表达式)返回一个数据
- Supplier
接口也被称为生产型接口,指定了接口的泛型,get方法就会生产相应类型的数据
例: get方法的方法体对应return语句
public class SupplierDemo {
public static void main(String[] args) {
String s = getString(()->return "hello");
System.out.println(s);
}
private static String getString(Supplier<String> sup){
return sup.get();
}
}
定义一个类SupplierTest,在类中提供两个方法
一个方法是: int getMax(Supplier
一个方法是主方法,在主方法中调用getMax方法
public class SupplierTest {
public static void main(String[] args) {
int[] arr = {19,50,28,37,46};
int maxvalue = getMax(()->{
//lambda表达式或者说匿名内部类,可以直接引用外面花括号内的变量
int max = arr[0];
for(int i =0; i<arr.length;i++){
if(arr[i]>max){
max = arr[i];
}
}
return max;
});
System.out.println(maxvalue);
}
private static int getMax(Supplier<Integer> sp){
return sp.get();
}
}
3.4.2 Consumer接口
Consumer
Consumer
- void accept(T t)对给定的参数执行此操作
- default Consumer
andThen(Consumer after):返回一个组合的Consumer,依次执行此操作,然后执行after操作
如con1.andThen(con2).accept(name);
例 accpet
package interfaces;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
operatorString("林青霞",name-> System.out.println(name));
//operatorString("林青霞",System.out::println);
operatorString("林青霞",name-> System.out.println(
new StringBuilder(name).reverse().toString()
));
}
private static void operatorString(String name, Consumer<String> con){
con.accept(name);
}
}
例 andThen方法
package interfaces;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
operatorString("林青霞",name-> System.out.println(name));
//operatorString("林青霞",System.out::println);
operatorString("林青霞",name-> System.out.println(
new StringBuilder(name).reverse().toString()
));
operatorString2("林青霞",name-> System.out.println(name),
name-> System.out.println(new StringBuilder(name).append("1111")));
}
//消费一个字符串数据
private static void operatorString(String name, Consumer<String> con){
con.accept(name);
}
//用不同的方式,消费同一个字符串数据两次
private static void operatorString2(String name, Consumer<String> con1,Consumer<String>con2){
/* con1.accept(name);
con2.accept(name);*/
//返回组合的consumer,然后调用accept方法
/*
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
//组合的consumer返回值使用lambda表达式,accept方法先调用con1的accept,再调用con2的accept
return (T t) -> { accept(t); after.accept(t); };
}
*/
con1.andThen(con2).accept(name);
}
}
例
- String[]strArray =
- 字符串数组中有多条信息,请按照格式:"姓名:XX,年龄:XX"的格式将信息打印出来
- 要求:
把打印姓名的动作作为第一个Consumer接口的Lambda实例
把打印年龄的动作作为第二个Consumer接口的Lambda实例
将两个Consumer接口按照顺序组合一起使用
package interfaces;
import java.util.function.Consumer;
/*
* String[]strArray = {"林青霞,30","张曼玉,35","王祖贤,33"}
* 字符串数组中有多条信息,请按照格式:"姓名:XX,年龄:XX"的格式将信息打印出来
* 要求:
把打印姓名的动作作为第一个Consumer接口的Lambda实例
把打印年龄的动作作为第二个Consumer接口的Lambda实例
将两个Consumer接口按照顺序组合一起使用
*/
public class ConsumerDemo2 {
public static void main(String[] args) {
String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33"};
/*
错误示范,传给消费者的是每个字符串,不是数组,否则打印格式不对
operator(strArray,arr->{
for(int i=0;i<arr.length;i++){
System.out.println(arr[i].substring(0,arr[i].indexOf(",")));
}},arr1->{
for(int i=0;i<arr1.length;i++){
System.out.println(arr1[i].substring(arr1[i].indexOf(",")+1));
}
}
);
}
private static void operator(String[] arr, Consumer<String[]> con1, Consumer<String[]> con2){
con1.andThen(con2).accept(arr);
}*/
printInfo(strArray,s -> System.out.print("姓名:"+s.split(",")[0])
,s1-> System.out.println(",年龄: "+s1.split(",")[1])
);
}
private static void printInfo(String[] strArray,Consumer<String>con1,Consumer<String>con2){
for(String s : strArray){
con1.andThen(con2).accept(s);
}
}
}
3.4.3 Predicate接口
- 谓词,该函数式接口是用来做判断参数是否满足指定条件,返回值为布尔值
- Predicate
常用的四个方法 - boolean test(T t):对给定的参数进行判断(判断逻辑由lambda表达式实现),返回一个布尔值
- default Predicate
negate()返回一个逻辑的否定,对应逻辑非
pre.negate().test(s) - default Predicate
and(Predicate other)返回一个组合判断,对应短路与 - default Predicate
or (Predicate other)返回一个组合判断,短路或
例 test和negate演示
public class PredicateDemo01 {
public static void main(String[] args) {
System.out.println(checkString("helloworld",s->s.startsWith("hello")));
}
//判断指定的字符串是否满足要求
private static boolean checkString(String s, Predicate<String> pre){
//return pre.test(s); //true
return pre.negate().test(s);//false==!pre.test
}
}
例 and和or演示
import java.util.function.Predicate;
public class PredicateDemo02 {
public static void main(String[] args) {
System.out.println(checkString1("hellow",
s->s.length()>3,
s1-> s1.length()<5));
}
//判断指定的字符串是否满足要求
private static boolean checkString1(String s,Predicate<String>pre1,Predicate<String>pre2){
//return pre1.test(s) && pre2.test(s);
//return pre1.and(pre2).test(s);
return pre1.or(pre2).test(s);
}
private static boolean checkString(String s, Predicate<String> pre){
return pre.test(s); //true
}
}
例
String[] strArray ={"林青霞,30","柳岩,34","张曼玉,35","王祖贤,33"}
字符串数组中有多条信息,请通过Predicate接口的拼装将符合要求的字符串筛选到集合ArrayList中,并遍历ArrayList集合
同时满足一下条件,姓名长度大于2,年龄大于33
public class PredicateTest {
public static void main(String[] args) {
String[] strArray ={"林青霞,30","柳岩,34","张曼玉,35","王祖贤,33"}
myFilter(strArray,s->return s.split(",")[0].length()>2,
s1->return Integer.parseInt(s1.split(",")[1]>33));
}
private static ArrayList myFilter(String[] strArray,Predicate<String>p1,
Predicate<String>p2){
ArrayList<String>array = new ArrayList<String>();
for(String s:strArray){
if(p1.and(p2).test(s)){
array.add(s);
}
}
}
}
3.4.4 Function接口
Function< T,R > T表示输入参数,R标识输出结果。用于对参数进行处理,转换后返回一个值,转换过程一般由Lambda表达式来实现
- R apply(T t):将次函数应用于给定的参数
- default
Function andThen(Function after):返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
例
public class FunctionDemo {
public static void main(String[] args) {
convert("100", s -> Integer.parseInt(s));
convert("100", Integer::parseInt);
convert(100, i -> String.valueOf(i + 666));
convert("100", Integer::parseInt, String::valueOf);
}
private static void convert(String s, Function<String, Integer> fun) {
int i = fun.apply(s);
System.out.println(i);
}
private static void convert(int i, Function<Integer, String> fun) {
String s = fun.apply(i);
System.out.println(s);
}
private static void convert(String s, Function<String, Integer> fun1,
Function<Integer, String> fun2) {
String s1 = fun1.andThen(fun2).apply(s);
System.out.println(s1);
}
}
例
- String s ="林青霞,30"
- 按照一下要求进行操作:
1.将字符串截取得到数字年龄部分
2.将上一步的年龄字符串转换成为int类型的数据
3.将上一步的int数据加70,得到一个int结果,在控制台输出 - 请通过Function接口来实现函数拼接
public class FunctionTest {
public static void main(String[] args) {
String s="linqingxia,33";
convert(s,str->str.split(",")[1],str1->Integer.parseInt(str1),i->i+70);
convert(s,str->str.split(",")[1],Integer::parseInt,i->i+70);
}
private static void convert(String s,Function<String,String>fun1,
Function<String,Integer> fun2,Function<Integer,String>fun3){
int i = fun1.andThen(fun2).andThen(fun3).apply(s);
System.out.print(i);
}
}
4 Stream流
since java 1.8, java.util.stream包
- Stream流的使用
- 生成流
通过数据源(集合,数组等)生成流
list.stream() - 中间操作
一个流后面可以跟零个或者多个中间操作,其主要目的是打开流,做出某种程度的过滤/映射,然后返回一个新的流,交给下一个操作使用
filter() - 终结操作
一个流只能有一个终结操作,当这个操作执行后,流就被使用光了,无法再被操作。所以这必定是流的最后一个操作
forEach()
- 生成流
4.1 体验Stream流
需求:按照下面的要求完成集合的创建和遍历
- 创建一个集合,存储多个字符串元素
- 把集合中所有以“张”开头的元素存储到一个新的集合
- 把“张”开头的集合中的长度为3的元素存储到一个新的集合
- 遍历上一步得到的集合
package io;
import java.util.ArrayList;
public class StreamDemo01 {
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);
}
}
System.out.println(zhangList);
ArrayList<String> threeList = new ArrayList<String>();
for(String s: zhangList){
if(s.length()==3){
threeList.add(s);
}
}
System.out.println(threeList);
System.out.println("-------------");
list.stream().filter(s -> s.startsWith("张")).filter(s->s.length()==3).forEach(System.out::println);
}
}
使用Stream流的方式完成过滤操作
- list.stream().filter(s -> s.startsWith("张")).filter(s->s.length()==3).forEach(System.out::println);
- 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:生成流,过滤姓张的,过滤长度为3的,逐一打印(filter结合lambda表达式使用)
- Stream流把真正的函数式编程风格引入到java中
4.2 Stream流的生成方式
- Stream流的常见生成方式
- Collection体系的集合可以使用默认方法stream()生成流
default Streamstream() - Map体系的集合间接生成流,keySet,valueSet和entrySet可以分别生成集合
- 数组可以通过Stream接口的静态方法of(T ... values)生成流
- Collection体系的集合可以使用默认方法stream()生成流
package io;
import java.util.*;
import java.util.stream.Stream;
public class StreamDemo02 {
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, String> map = new HashMap<String,String>();
Stream<String> keyStream = map.keySet().stream();
Stream<String> valueStream = map.values().stream();
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
//数组可以通过Stream接口的静态方法of(T...values)生成流
String[] strArr = {"hello","world","java"};
Stream<String> strArrStream = Stream.of(strArr);
Stream.of("hello","world","java");
Stream<Integer> integerStream = Stream.of(10, 20, 30);
}
}
4.3 Stream流的常见中间操作方法
- Stream
filter(Predicate predicate):用于对流中的数据进行过滤,返回的新的流由与成功匹配给定谓词的元组组成
Predicate函数式接口中的方法 boolean test(T t)对给定的参数进行判断,返回一个boolen值 - Steam
limit(long maxSize)返回此流中的元素组成的流,截取当前指定参数个数的数据 - Stream
skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流 - static
concat(Stream a, Stream b)合并a和b两个流为一个流 - Stream
distinct()返回由该流中的不同元素(根据Object.equals(Object))组成的流 - Stream
sorted()返回由此流的元素组成的流,根据自然顺序排序 - Steam
sorted(Comparator)返回由该流的元素组成的流,根据提供的Comparator进行排序 Stream map(Function mapper)返回由给定函数应用于此流的元素的结果组成的流
Function接口中的方法 R apply(T t)- IntStream mapToInt(ToIntFunction mapper)返回一个IntStream其中包含将给定函数应用于此流的元素的结果
IntStream 表示原始Int流,获得该流后可以调用其特有方法
ToIntFunction接口的方法 int applyAsInt(T value)
例 filter
public static void main(String[] args) {
ArrayList<String>list = new ArrayList<String>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("zhaomin");
list.add("zhangsanfeng");
list.add("zhangmin");
list.stream().filter(s->s.startWith("zhang")).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.startWith("zhang")).filter(s->s.length()==3).
foreach(System.out.println);
}
例 limit和skip
public class StreamDemo02 {
public static void main(String[] args) {
ArrayList<String>list = new ArrayList<String>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("zhaomin");
list.add("zhangsanfeng");
list.add("zhangmin");
//输出前三个
list.stream().limit(3).forEach(System.out::println);
//跳过前三个输出后面的
list.stream().skip(3).forEach(System.out.println);
//跳过前两个只输出其后的两个
list.stream().skip(2).limit(2).forEach(System.out::println);
}
}
例:concact和distinct
public class StreamDemo03 {
public static void main(String[] args) {
ArrayList<String>list = new ArrayList<String>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("zhaomin");
list.add("zhangsanfeng");
list.add("zhangmin");
Stream<String> s1 = list.stream().limit(4);
Stream<String> s2 = list.steam().skip(2);
Stream<String> s3 = Stream.concact(s1,s2);
s3.forEach(System.out::println);
Stream.concact(s1,s3).distinct().forEach();
s4.forEach(System.out::println);
}
}
例
public class StreamDemo04 {
public static void main(String[] args) {
ArrayList<String>list = new ArrayList<String>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("zhaomin");
list.add("zhangsanfeng");
list.add("zhangmin");
list.stream().sorted().forEach(System.out::println);
list.stream().sorted((s1,s2)).forEach(System.out::println);
}
}
例 sort(),sort(comparator)
package streams;
import java.util.ArrayList;
public class StreamDemo04 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("linqingxia");
list.add("zhangmanyu");
list.add("wangzuxian");
list.add("zhaomin");
list.add("zhangsanfeng");
list.add("zhangmin");
//按照自然顺序排序
list.stream().sorted().forEach(System.out::println);
System.out.println("——————————————————————————————");
//按照字符串长度排序
list.stream().sorted((s1,s2)->s1.length()-s2.length()).
forEach(System.out::println);
System.out.println("----------------------------");
//先按字符串长度排序,长度相同时按照自然顺序排
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);
}
}
例 map和mapToInt方法
package streams;
import java.util.ArrayList;
/*
<R> Stream<R> map(Function mapper)返回由给定函数应用于刺溜的元素的结果组成的流
Function接口中的方法 R apply(T t)
IntStream mapToInt (ToIntFunction mapper)返回一个IntStream其中包含将给定函数应用于
刺溜的元素的结果
IntStream表示原始int流
ToIntFunction 接口中的方法 int applyAsInt(T value)
*/
public class StreamDemo05 {
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);
System.out.println("-------------------");
list.stream().mapToInt(Integer::parseInt).forEach(System.out::println);
System.out.println("-------------");
//mapToInt返回IntStream,可以调用该流特有方法sum
int sum = list.stream().mapToInt(Integer::parseInt).sum();
System.out.println(sum);
}
}
4.4 Stream常见终结操作方法
- void forEach(Consumer action): 对此流的每个元素执行操作
Consumer接口中的方法 void accept(T t)对给定的参数执行此操作 - long count()返回此流中的元素数
例
package streams;
import java.util.ArrayList;
public class StreamDemo06 {
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().forEach(System.out::println);
//统计集合有几个以张开头的元素,并把结果输出
long count = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(count);
}
}
例 Stream综合练习
现有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下操作
- 男演员只要名字为3个字的前三个人 filter,limit
- 女演员只要姓林的并且不要第一个 filter,skip
- 把过滤后的男演员和女演员姓名合并到一起 contact
- 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
演员类Actor已经提供,厘米那有一个成员变量,一个带参构造方法,一级成员变量对应的get/set方法
package streams;
import java.util.ArrayList;
import java.util.stream.Stream;
public class StreamDemo07 {
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("张琪");
womanList.add("白冰");
Stream<String> limit = manList.stream().
filter(s -> s.length() == 3).limit(3);
Stream<String> skip = womanList.stream().
filter(s -> s.startsWith("林")).skip(1);
//Stream.concat(limit,skip).map(s->new Actor(s)).
// forEach(System.out::println);
//注意所有流操作熟练后可以直接写为一行
Stream.concat(limit,skip).map(Actor::new).
forEach(p->System.out.println(p.getName()));
}
}
4.5 Stream流的收集操作
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集合中
第一个参数对应key的lambda表达式,第二个参数对应value的lambda表达式
package streams;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CollectDemo {
public static void main(String[] args) {
//stream->list
List<String> list = new ArrayList<String>();
list.add("林青霞");
list.add("张曼玉");
list.add("王祖贤");
list.add("柳岩");
list.add("林志玲");
//得到名字为3个字的流
Stream<String> strStream = list.stream().filter(s -> s.length() == 3);
//操作完毕,将流收入List集合中并遍历
List<String> names = strStream.collect(Collectors.toList());
for(String name:names){
System.out.println(name);
}
//stream->set
Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(20);
set.add(30);
set.add(40);
set.add(50);
//得到年龄大于25的流
Stream<Integer> integerStream = set.stream().filter(i -> i > 25);
Set<Integer> ages = integerStream.collect(Collectors.toSet());
for(int age:ages){
System.out.println(age);
}
//stream -> map
HashMap<String, Integer> persons = new HashMap<>();
persons.put("林青霞",10);
persons.put("张曼玉",20);
persons.put("王祖贤",30);
persons.put("柳岩",40);
persons.put("王心凌",50);
Stream<Map.Entry<String, Integer>> entryStream = persons.entrySet().stream().
filter(keyentry -> keyentry.getKey().length() == 3).filter(str -> str.getValue() > 25);
Map<String, Integer> collect = entryStream.collect(
Collectors.toMap(s -> s.getKey(), s1 -> s1.getValue()));
Set<String> keySet = collect.keySet();
for(String key:keySet){
System.out.println(key+" , "+collect.get(key));
}
System.out.println("------------");
//从数组生成流 然后steam-> map
String[] strArrays = {"林青霞,10","张曼玉,20","王祖贤,30","柳岩,40","王菲,50"};
Stream<String> stringStream = Stream.of(strArrays).
filter(str -> str.split(",")[0].length() == 3).
filter(str1 -> Integer.parseInt(str1.split(",")[1])>28);
Map<String, String> collect1 = stringStream.collect(Collectors.toMap(s -> s.split(",")[0], s -> s.split(",")[1]));
Set<String> keySet1 = collect1.keySet();
for(String key:keySet1){
System.out.println(key+" , "+collect1.get(key));
}
}
}
5. 模块化(java 9)
5.1 什么是模块化
即使运行一个小程序,只需要java的部分核心功能,JVM也要加载整个JRE环境。JAVA 9推出模块化系统。
Java被拆分为N多个模块,并允许Java程序可以根据需要选择加载程序必须的java模块,轻量化的方式来运行
5.2 模块化基本使用
- 创建模块(按照以前的讲解方式创建模块,创建包,创建类,定义方法)
为了体现模块的使用,我们创建2个模块,一个是myOne,一个是myTwo
File->Project Structure->Modules->new module-> - 在模块的src目录下新建一个名为module-info.java的描述性文件,该文件专门定义模块化,访问权限,模块依赖等信息
描述性文件中使用模块导出和模块依赖来进行配置并使用
File->New->module-info.java - 模块中所有未导出的包都是模块私有的,他们是不能在模块之外被访问的
在myOne这个模块下的描述性文件中配置模块导出
模块导出格式: export 包名; - 一个模块要访问其他的模块,必须明确指定依赖哪些模块,未明确指定依赖的模块不能访问
在myTwo这个模块下的描述行文件中配置模块依赖
模块依赖格式:requires 模块名;
注意:写模块名报错,需要按下Alt+Enter提示,然后选择模块依赖 - 在myTwo这个模块类中可以似乎用依赖模块下的内容
/////myOne里的module-info.java/////
module myOne{
exports it.io;
}
/////myTwo里的module-info.java/////
module myTwo{
requires myOne;
}
5.3 模块服务的使用
- 服务:从java6开始,提供的一种服务机制,允许服务提供者和服务使用者之间完成解耦
简单的说,就是服务使用指面向接口编程,但不清楚服务使用者的实现类 - Java9 简化了服务机制,允许将服务接口定义在一个模块中。
针对该服务接口提供不同的服务实现类,这些服务实现类可以分布在不同的模块中,
服务实现模块则使用provides语句为服务接口提供实现类
并使用uses语句在另一个模块中声明将使用该服务接口。
服务使用者只需要面向接口编程即可 - 模块服务的使用步骤
- 在myOne模块下常见一个包com.itheima_03,在该包下提供一个接口,接口中定义一个抽象方法
public interface myService{
void service();
} - 在com.itheima_03包下创建一个包impl,在该包下提供接口的连个实现类itheima和Czxy
- 在myOne这个模块下的描述性文件中添加看如下配置
模块导出:export com.itheima_03; 包名
服务提供:provides MyService with itheima;类名,指定MyService的服务实现类是itheima - 在myTwo这个模块下的描述性文件添加如下配置
声明会使用服务接口:use MyService; - 真正使用,在myTwo这个模块的类中使用MyService接口提供的服务
ServiceLoader:一种加载服务实现的工具,继承iterable可用增强for遍历
- 在myOne模块下常见一个包com.itheima_03,在该包下提供一个接口,接口中定义一个抽象方法
module myOne{
exports com.itheima_01;
exports com.itheima_03;
provides MyService with Itheima;
}
/////////////////
module myOne{
exports com.itheima_01;
exports com.itheima_03;
provides MyService with Itheima;
}
////////myTwo模块下test类/////
import java.util.ServiceLoader;
public class Test02 {
public static void main(String args[]){
//load services
ServiceLoader<MyService> myServices = ServiceLoader.load(MyService.class);
//tranvers service
for(MyService my: myServices){
my.service();//使用服务
}
}
}

浙公网安备 33010602011771号