8.Stream笔记

1.Stream流常用方法

  • Stream流是一个集合元素的函数模型,既不是集合,也不是数据结构,其本身并不存储任何元素,仅按需计算
  • Stream流函数模型每一步并没有处理集合元素,仅当终结方法count执行时,模型才会执行操作(得益于Lambda的延迟执行特性)
  • Pipelining: 中间操作都会返回流对象本身
  • 内部迭代:流可以直接调用遍历方法,不同于Iterator或者增强for的集合外部迭代方式

①获取方法

		//所有的Collection集合都可以通过stream默认方法获取流;
		public interface Collection<E> extends Iterable<E> {
  			default Stream<E> stream() 
       		 	return StreamSupport.stream(spliterator(), false);
   		 }
   		 
   		//Stream接口的静态方法of可以获取数组对应的流 
		public interface Stream<T> {
		 	public static<T> Stream<T> of(T... values) 
        		return Arrays.stream(values);
    	}
		1.把单列集合转换为Stream流
        
        List<String> list = new ArrayList<>();
        Set<String> set = new HashSet<>();        
        Stream<String> strmList = list.stream(); 
        Stream<String> strmSet = set.stream();
     	
     	2.把双列集合转换为Stream流
     	
        Map<String,String> map = new HashMap<>();      
        Set<String> keySet = map.keySet();//获取键,存储到一个Set集合中    
        Collection<String> values = map.values();//获取值,存储到一个Collection集合中
		
		Stream<String> strmMapk = keySet.stream();
        Stream<String> strmMapv = values.stream();

        //获取键值对(键与值的映射关系 entrySet)
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> strmEtry = entries.stream();

        //把数组转换为Stream流
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);    
        Integer[] arr = {1,2,3,4,5};
        String[] arr2 = {"a","bb","ccc"};
        Stream<Integer> stream7 = Stream.of(arr);       
        Stream<String> stream8 = Stream.of(arr2);

②操作方法

 		void forEach(Consumer<? super T> action); 		
		public interface Consumer<T> void accept(T t);//消费接口
		
		Stream<T> filter(Predicate<? super T> predicate);		
		public interface Predicate<T> boolean test(T t);//判断接口
		
		<R> Stream<R> map(Function<? super T, ? extends R> mapper);
		public interface Function<T, R>  R apply(T t);//转换接口
		
		long count();//个数
		
		Stream<T> limit(long maxSize);//截取方法
		
		Stream<T> skip(long n);//跳过方法
		
		static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)//把两个流合并成为一个流
        Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");       
        Stream<String> stream2 = stream1.filter( name->name.startsWith("张"));
        stream2.forEach(name-> System.out.println(name));
				       
        Stream<String> stream1 = Stream.of("1", "2", "3", "4");
        //把字符串类型映射为Integer类型
        Stream<Integer> stream2 = stream1.map( s-> Integer.parseInt(s));
        
        long num = stream2.count();
        Stream<Integer> stream3 = stream2.limit(3); //1 2 3 
        Stream<Integer> stream3 = stream2.skip(3); //4
          	
        Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");      
        Stream<String> stream2 = Stream.of("美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼");
     
        Stream<String> concat = Stream.concat(stream1, stream2);
        concat.forEach(name-> System.out.println(name));                              

forEach count都是终结方法

  		//IllegalStateException: stream has already been operated upon or closed
        stream1.forEach(name-> System.out.println(name));//已关闭,无法使用

2.方法引用

在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑?

		@FunctionalInterface
		public interface Printable { void print(String str); }
		
		private static void printString(Printable data) {
				data.print("Hello, World!");
		}
			
		printString(s ‐> System.out.println(s));

  • printString 方法只管调用Printable 接口的print 方法,而并不管print 方法如何实现字符串打印
  • 经Lambda,继而传递给System.out.println 方法去处理
  • 问题在于:然而打印字符串有现成的操作方案System.out对象中的println(String) 方法。既然Lambda希望做的事情就是调用println(String) 方法,又何必手动调用呢?
  • 直接让System.out 中的println 方法来取代Lambda
		printString(System.out::println);
		//函数式接口是Lambda的基础,而方法引用是Lambda的孪生兄弟		 
  1. System.out对象是已经存在的,println方法也是已经存在的,
  2. 所以我们可以使用使用System.out方法直接引用(调用)println方法

①通过对象引用成员方法 / 类引用静态方法

  • 前提是:对象 类 成员方法 静态方法均存在
		1.成员方法是已经存在的printUpperCaseString
		public class MethodRefObject {
			public void printUpperCase(String str) { System.out.println(str.toUpperCase());}
		}
		
		@FunctionalInterface
		public interface Printable { void print(String str); }

		2.对象是已经存在的MethodRerObject
		
		那么当需要使用这个printUpperCase成员方法来替代Printable接口
		的Lambda的时候,则可以通过对象名引用成员方法
				
		private static void printString(Printable lambda) {
			lambda.print("Hello");
		}
		
		printString((s)->{
            MethodRerObject obj = new MethodRerObject();           
            obj.printUpperCaseString(s);
        });
		
		MethodRefObject obj = new MethodRefObject();
		printString(obj::printUpperCase);
		public final class Math {
			 public static int abs(int a)
		}
		
		@FunctionalInterface
		public interface Calcable { int calsAbs(int number); }
		
		public static int method(int number,Calcable c){
       		return c.calsAbs(number);
    	}
       
        int number = method(-10,(n)->{ return Math.abs(n); });
        System.out.println(number);

        /*
            使用方法引用优化Lambda表达式
            Math类是存在的
            abs计算绝对值的静态方法也是已经存在的
            所以我们可以直接通过类名引用静态方法
         */
        int number2 = method(-10,Math::abs);//n -> Math.abs(n)
        System.out.println(number2);
    }

②通过super / this引用父 / 本类成员方法

		public class Human {
    		public void sayHello(){ System.out.println("Hello 我是Human!");}        	
		}

		@FunctionalInterface
		public interface Greetable { void greet(); }
		
		public class Man extends Human{
    		@Override
    		public void sayHello() { System.out.println("Hello 我是Man!");}
        	//定义一个方法参数传递Greetable接口
    		public void method(Greetable g){  g.greet(); }

    		public void show(){
        		method(()->{ Human h = new Human();  h.sayHello(); });
			
			method(()->{ super.sayHello(); });
			method(()->{ this.sayHello(); });

      	/*
           使用super引用类的成员方法
           super是已经存在的
           父类的成员方法sayHello也是已经存在的
           所以我们可以直接使用super引用父类的成员方法
       */
      		method(super::sayHello);
      		method(this::sayHello);
    	}   
    	
        	new Man().show();

③类 / 数组 的构造器引用

		public class Person {
    		private String name;
    		...
    		public Person() { }
    		public Person(String name) { this.name = name; }
    	}
		
		@FunctionalInterface
		public interface Born {
    		//定义一个方法,根据传递的姓名,创建Person对象返回
    		Person builderPerson(String name);
		}
		
    	//定义一个方法,参数传递姓名和PersonBuilder接口,方法中通过姓名创建Person对象
    	public static void printName(String name,Born pb){
        	Person person = pb.builderPerson(name);
        	System.out.println(person.getName());
    	}

        //调用printName方法,方法的参数PersonBuilder接口是一个函数式接口,可以传递Lambda
        printName("迪丽热巴",(String name)->{ return new Person(name); });

        /*
            使用方法引用优化Lambda表达式
            构造方法new Person(String name) 已知
            创建对象已知 new
            就可以使用Person引用new创建对象
         */
        printName("古力娜扎",Person::new);//使用Person类的带参构造方法,通过传递的姓名创建对象

		@FunctionalInterface
		public interface ArrayBuilder { int[] builderArray(int length); }
    	//定义一个创建int类型数组的方法,参数传递数组的长度,返回创建好的int类型数组

 		public static int[] createArray(int length, ArrayBuilder ab){
        	return  ab.builderArray(length);
    	}

        //调用createArray方法,传递数组的长度和Lambda表达式
        int[] arr1 = createArray(10,(len)->{ return new int[len];  });

        /*
            使用方法引用优化Lambda表达式
            已知创建的就是int[]数组
            数组的长度也是已知的
            就可以使用方法引用
            int[]引用new,根据参数传递的长度来创建数组
         */
        int[] arr2 =createArray(10,int[]::new);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值