目录
Stream流:JDK1.8新特征,关注“做什么”,而不是“怎么做”
1.3 获取流 :两种。stream &&stream.of()
Stream 接口的静态方法 of 可以获取数组对应的流。数组
所有的 Collection 集合都可以通过 stream 默认方法获取流; 集合
终结方法:返回值类型不再是 Stream 接口自身类型的方法(count,forEach)
Lambda表达式: () -> super.sayHello()
Lambda表达式: () -> this.buyHouse()
Lambda表达式: name -> new Person(name)
Lambda表达式: length -> new int[length]
第一章 Stream流
io流:主要用于进行读写
Stream流:对集合和数组进行简化操作
将集合和数组转换为Stream流再用Stream流对集合和数组进行简化操作,用于解决已有集合类库既有的弊端。
1.循环遍历的弊端
我们可以发现
2.循环和遍历的区别
3.Stream流取代for循环
先代码对比写
for循环:对集合元素进行过滤
1. 首先筛选所有姓张的人;
/*
使用传统的方式,遍历集合,对集合中的数据进行过滤
*/
public class Demo01List {
public static void main(String[] args) {
//创建一个List集合,存储姓名
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
List<String> listA = new ArrayList<>();
for(String s : list){
if(s.startsWith("张")){
listA.add(s);
}
}
//对listA集合进行过滤,只要姓名长度为3的人,存储到一个新集合中
List<String> listB = new ArrayList<>();
for (String s : listA) {
if(s.length()==3){
listB.add(s);
}
}
//遍历listB集合
for (String s : listB) {
System.out.println(s);
}
}
}
Stream流:JDK1.8新特征,关注“做什么”,而不是“怎么做”
/*
使用Stream流的方式,遍历集合,对集合中的数据进行过滤
Stream流是JDK1.8之后出现的
关注的是做什么,而不是怎么做
*/
public class Demo02Stream {
public static void main(String[] args) {
//创建一个List集合,存储姓名
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//对list集合中的元素进行过滤,只要以张开头的元素,存储到一个新的集合中
//对listA集合进行过滤,只要姓名长度为3的人,存储到一个新集合中
//遍历listB集合
list.stream()
.filter(name->name.startsWith("张"))
.filter(name->name.length()==3)
.forEach(name-> System.out.println(name));
}
}
1.2 流式思想概述
整体来看,流式思想类似于工厂车间的“生产流水线”。
- Pipelining: 中间操作都会返回流对象本身。
- 内部迭代: 流可以直接调用遍历方法。
1.3 获取流 :两种。stream &&stream.of()
-
Stream 接口的静态方法 of 可以获取数组对应的流。数组
public class Demo01GetStream {
public static void main(String[] args) {
//把数组转换为Stream流
Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5);
//可变参数可以传递数组
Integer[] arr = {1,2,3,4,5};
Stream<Integer> stream7 = Stream.of(arr);
String[] arr2 = {"a","bb","ccc"};
Stream<String> stream8 = Stream.of(arr2);
}
}
-
所有的 Collection 集合都可以通过 stream 默认方法获取流; 集合
public class Demo01GetStream {
public static void main(String[] args) {
//把集合转换为Stream流
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream2 = set.stream();
}
}
-
根据Map获取流
public class Demo01GetStream {
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
//获取键,存储到一个Set集合中
Set<String> keySet = map.keySet();
Stream<String> stream3 = keySet.stream();
//获取值,存储到一个Collection集合中
Collection<String> values = map.values();
Stream<String> stream4 = values.stream();
//获取键值对(键与值的映射关系 entrySet)
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> stream5 = entries.stream();
}
}
1.4 常用方法
-
延迟方法:返回值类型仍然是 Stream 接
-
终结方法:返回值类型不再是 Stream 接口自身类型的方法(count,forEach)
1.逐一处理:forEach (终结方法)
void forEach(Consumer<? super T> action)
复习Consumer接口
java . util . function . Consumer < T > 接口是一个消费型接口。Consumer 接口中包含抽象方法 void accept ( T t ) ,意为消费一个指定泛型的数据
基本使用:
public class Demo02Stream_forEach {
public static void main(String[] args) {
//获取一个Stream流
Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六", "田七");
//使用Stream流中的方法forEach对Stream流中的数据进行遍历
/*stream.forEach((String name)->{
System.out.println(name);
});*/
stream.forEach(name->System.out.println(name));
}
}
2.过滤:fifilter
可以通过 filter 方法将一个流转换成另一个子集流。方法签名:
Stream < T > filter ( Predicate <? super T > predicate );
复习Predicate接口
boolean test(T t)
基本使用
import java . util . stream . Stream ;public class Demo07StreamFilter {public static void main ( String [] args ) {Stream < String > original = Stream . of ( " 张无忌 " , " 张三丰 " , " 周芷若 " );Stream < String > result = original . filter ( s ‐> s . startsWith ( " 张 " ));}}
3.映射:map
< R > Stream < R > map ( Function <? super T , ? extends R > mapper );
复习Function接口
R apply ( T t );
基本使用
import java . util . stream . Stream ;public class Demo08StreamMap {public static void main ( String [] args ) {Stream < String > original = Stream . of ( "10" , "12" , "18" );Stream < Integer > result = original . map ( (String str )‐> Integer . parseInt ( str ));}}
4.统计个数:count (终结方法)
long count ();
基本使用
import java . util . stream . Stream ;public class Demo09StreamCount {public static void main ( String [] args ) {Stream < String > original = Stream . of ( " 张无忌 " , " 张三丰 " , " 周芷若 " );Stream < String > result = original . filter ( s ‐> s . startsWith ( " 张 " ));System . out . println ( result . count ()); // 2}}
5.取用前几个:limit
Stream < T > limit ( long maxSize );
基本使用
import java.util.stream.Stream;
public class Demo10StreamLimit {public static void main ( String [] args ) {Stream < String > original = Stream . of ( " 张无忌 " , " 张三丰 " , " 周芷若 " );Stream < String > result = original . limit ( 2 );System . out . println ( result . count ()); // 2}}
6.跳过前几个:skip
Stream<T> skip(long n);
基本使用
import java . util . stream . Stream ;public class Demo11StreamSkip {public static void main ( String [] args ) {Stream < String > original = Stream . of ( " 张无忌 " , " 张三丰 " , " 周芷若 " );Stream < String > result = original . skip ( 2 );System . out . println ( result . count ()); // 1}}
7.组合:concat
static < T > Stream < T > concat ( Stream <? extends T > a , Stream <? extends T > b )
基本使用
import java . util . stream . Stream ;public class Demo12StreamConcat {public static void main ( String [] args ) {Stream < String > streamA = Stream . of ( " 张无忌 " );Stream < String > streamB = Stream . of ( " 张翠山 " );Stream < String > result = Stream . concat ( streamA , streamB );}}
第二章 方法引用 (对Lambda表达式进行优化)
2.1 冗余的Lambda场景
@FunctionalInterfacepublic interface Printable {void print ( String str );}
public class Demo01PrintSimple {private static void printString ( Printable data ) {data . print ( "Hello, World!" );}public static void main ( String [] args ) {printString ( s ‐> System . out . println ( s ));}}
2.2 问题分析
有现成的打印方法,我们可以直接调用
2.3 用方法引用改进代码
public class Demo02PrintRef {private static void printString ( Printable data ) {data . print ( "Hello, World!" );}public static void main ( String [] args ) {printString ( System . out :: println );}}
请注意其中的双冒号 :: 写法,这被称为“方法引用”,而双冒号是一种新的语法
2.4 方法引用符
- Lambda表达式写法: s -> System.out.println(s);
- 方法引用写法: System.out::println
2.5 通过对象名引用成员方法
public class MethodRefObject {public void printUpperCase ( String str ) {System . out . println ( str . toUpperCase ());}}
函数式接口仍然定义为:
@FunctionalInterfacepublic interface Printable {void print ( String str );}
通过对象名引用方法,
使用前提是对象名已经存在,成员方法也已经存在
就可以使用对象名引用成员方法
public static void main(String[] args) {
//调用printString方法,方法的参数Printable是一个函数式接口,所以可以传递Lambda表达式
printString((s)->{
//创建MethodRerObject对象
MethodRerObject obj = new MethodRerObject();
//调用MethodRerObject对象中的成员方法printUpperCaseString,把字符串按照大写输出
obj.printUpperCaseString(s);
});
/*
使用方法引用优化Lambda
对象是已经存在的MethodRerObject
成员方法也是已经存在的printUpperCaseString
所以我们可以使用对象名引用成员方法
*/
//创建MethodRerObject对象
MethodRerObject obj = new MethodRerObject();
printString(obj::printUpperCaseString);
}
2.6 通过类名称引用静态方法
@FunctionalInterfacepublic interface Calcable {int calc ( int num );}
public class Demo05Lambda {private static void method ( int num , Calcable lambda ) {System . out . println ( lambda . calc ( num ));}public static void main ( String [] args ) {method ( ‐ 10 , n ‐> Math . abs ( n ));}}
更好写法是:
public class Demo05Lambda {private static void method ( int num , Calcable lambda ) {System . out . println ( lambda . calc ( num ));}public static void main ( String [] args ) {method ( ‐ 10 , Math :: abs );}}
-
Lambda表达式: n -> Math.abs(n)
-
方法引用: Math::abs
2.7 通过super引用成员方法
@FunctionalInterfacepublic interface Greetable {void greet ();}
然后是父类 Human 的内容:
public class Human {
public void sayHello () {System . out . println ( "Hello!" );}}
最后是子类 Man 的内容,其中使用了Lambda的写法:
public class Man extends Human {@Overridepublic void sayHello () {System . out . println ( " 大家好 , 我是 Man!" );}// 定义方法 method, 参数传递 Greetable 接口public void method ( Greetable g ){g . greet ();}public void show (){//调用 method 方法 , 使用 Lambda 表达式method (() ‐> {//创建 Human 对象 , 调用 sayHello 方法new Human (). sayHello ();});// 简化 Lambdamethod (() ‐> new Human (). sayHello ());//使用 super 关键字代替父类对象method (() ‐> super . sayHello ());}}
但是如果使用方法引用来调用父类中的 sayHello 方法会更好,
public class Man extends Human {@Overridepublic void sayHello () {System . out . println ( " 大家好 , 我是 Man!" );}// 定义方法 method, 参数传递 Greetable 接口public void method ( Greetable g ){g . greet ();}public void show (){method ( super :: sayHello );}}
-
Lambda表达式: () -> super.sayHello()
-
方法引用: super::sayHello
2.8 通过this引用成员方法
this::成员方法
@FunctionalInterfacepublic interface Richable {void buy ();}
丈夫 Husband 类:
public class Husband {private void marry ( Richable lambda ) {lambda . buy ();}public void beHappy () {marry (() ‐> System . out . println ( " 买套房子 " ));}}
public class Husband {private void buyHouse () {System . out . println ( " 买套房子 " );}private void marry ( Richable lambda ) {lambda . buy ();}public void beHappy () {marry (() ‐> this . buyHouse ());}}
public class Husband {private void buyHouse () {System . out . println ( " 买套房子 " );}private void marry ( Richable lambda ) {lambda . buy ();}public void beHappy () {marry ( this: buyHouse ());}}
-
Lambda表达式: () -> this.buyHouse()
-
方法引用: this::buyHouse
2.9 类的构造器引用
package com.itheima.demo09.ConstructorMethodReference;
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface PersonBuilder {Person buildPerson ( String name );}
要使用这个函数式接口,可以通过Lambda表达式:
public class Demo09Lambda {public static void printName ( String name , PersonBuilder builder ) {System . out . println ( builder . buildPerson ( name ). getName ());}public static void main ( String [] args ) {printName ( " 赵丽颖 " , name ‐> new Person ( name ));}}
但是通过构造器引用,有更好的写法:
public class Demo10ConstructorRef {public static void printName ( String name , PersonBuilder builder ) {System . out . println ( builder . buildPerson ( name ). getName ());}public static void main ( String [] args ) {printName ( " 赵丽颖 " , Person :: new );}}
在这个例子中,下面两种写法是等效的:
-
Lambda表达式: name -> new Person(name)
-
方法引用: Person::new
2.10 数组的构造器引用
@FunctionalInterfacepublic interface ArrayBuilder {int [] buildArray ( int length );}
public class Demo11ArrayInitRef {private static int [] initArray ( int length , ArrayBuilder builder ) {return builder . buildArray ( length );}public static void main ( String [] args ) {int [] array = initArray ( 10 , length ‐> new int [ length ]);}}
但是更好的写法是使用数组的构造器引用:
public class Demo12ArrayInitRef {private static int [] initArray ( int length , ArrayBuilder builder ) {return builder . buildArray ( length );}public static void main ( String [] args ) {int [] array = initArray ( 10 , int []:: new );}}
-
Lambda表达式: length -> new int[length]
-
方法引用: int[]::new