面向对象编程思想
面向对象强调的是对象 , “必须通过对象的形式来做事情”,相对来讲比较复杂,有时候我们只是为了做某件事情而不得不创建一个对象 , 例如线程执行任务,我们不得不创建一个实现Runnable接口对象,但我们真正希望的是将run方法中的代码传递给线程对象执行
函数编程思想
在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿什么东西做什么事情”。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。例如线程执行任务 , 使用函数式思想 , 我们就可以通过传递一段代码给线程对象执行,而不需要创建任务对象
函数式编程思想强调做什么,而不是以什么形式做,也就是直接传入一段代码,不需要创建对象。Lambda表达式就是函数编程思想的体现
Lambda的前提条件
用Lambda必须具有接口,且要求接口中的抽象方法有且仅有一个。(别的方法没有影响) (条件)。使用Lambda必须具有上下文推断。如果一个接口中只有一个抽象方法,那么这个接口叫做是函数式接口。 @FunctionalInterface这个注解 就表示这个接口是一个函数式接口。
Lambda表达式的标准格式:
Lambda表达式的作用:
Lambda表达式的格式说明:
使用Lambda表达式步骤:
Lambda表达式省略格式:
Lambda的表现形式:
代码示例
package demo06;
import java.util.ArrayList;
import java.util.Collections;
@FunctionalInterface
interface A {
void method(int num);
}
public class Test {
public static void show(A a) {
a.method(10);
}
public static void main(String[] args) {
/*
Lambda表达式省略格式:
1.小括号中的形参类型可以省略
2.如果小括号中只有一个参数,那么小括号也可以省略
3.如果大括号中只有一条语句,那么大括号,分号,return可以一起省略
*/
// 案例1:创建线程执行任务
new Thread(() ->
System.out.println("任务代码")
).start();
// 案例2: 对ArrayList集合元素进行排序
ArrayList list = new ArrayList<>();
list.add(300);
list.add(200);
list.add(100);
list.add(500);
list.add(400);
System.out.println("排序前:" + list);
// 对集合中的元素按照降序排序
// 函数式编程:Lambda表达式
Collections.sort(list, (i1, i2) -> i2 - i1);
System.out.println("排序后:" + list);
System.out.println("=======================================");
// Lambda标准格式
show((int num) -> {
System.out.println(num);
});
// Lambda省略格式
show(num ->
System.out.println(num)
);
}
}
说到Stream便容易想到I/O Stream,而实际上,谁规定“流”就一定是“IO流”呢?在Java 8中,得益于Lambda所带 来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。
整体来看,流式思想类似于工厂车间的“生产流水线”。当需要对多个元素进行操作(特别是多步操作)的时候,考虑到性能及便利性,我们应该首先拼好一个“模型”步骤方案,然后再按照方案去执行它。
Stream(流)是一个来自数据源的元素队列 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。 数据源 流的来源。 可以是集合,数组 等。 和以前的Collection操作不同, Stream操作还有两个基础的特征:
当使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以 像链条一样排列,变成一个管道。
总结:
1:获取流
代码示例
package demo07;
import java.util.*;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
// 创建List集合
List list = new ArrayList<>();
Stream stream1 = list.stream(); //获取list集合的流
// 创建Set集合
Set set = new HashSet<>();
Stream stream2 = set.stream(); //获取set集合的流
// 创建Map集合
Map map = new HashMap<>();
// 1.根据Map集合的键获取流
Set keys = map.keySet();
Stream stream3 = keys.stream();
// 2.根据Map集合的值获取流
Collection values = map.values();
Stream stream4 = values.stream();
// 3.根据Map集合的键值对对象获取流
Set> entrys = map.entrySet();
Stream> stream5 = entrys.stream();
}
}
数组获取流
// 根据数组获取流
String[] array = { "张无忌", "张翠山", "张三丰", "张一元" };
Stream stream = Stream.of(array);
2:常用方法
流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
常用的方法如下所示
package demo08;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
/*
forEach方法:
void forEach(Consumer super T> action);逐一处理流中的元素
参数Consumer: 函数式接口,抽象方法void accept(T t);
*/
List list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(""+i);
}
// 函数模型: 获取流->逐一消费流中的元素。该方法保证元素的逐一消费动作在流中是被有序执行的。
list.stream().forEach((String e)->{
System.out.println(e);
});
System.out.println("========================================");
// 并行流: 通过Collection的parallelStream()方法可以得到并行流,不保证元素的逐一消费动作在流中是被有序执行的。
list.parallelStream().forEach((String e)->{
System.out.println(e);
});
}
}
统计个数
package demo08;
import java.util.ArrayList;
import java.util.List;
public class Test2_count {
public static void main(String[] args) {
/*
count方法:
long count();统计流中元素的个数
*/
List list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张杰");
list.add("张三丰");
long count = list.stream().count();
System.out.println("流中元素的个数:"+count);// 5
}
}
过滤
import java.util.stream.Stream;
public class Test3_filter {
/*
filter方法:
Stream filter(Predicate super T> predicate);过滤出满足条件的元素
参数Predicate: 函数式接口, 抽象方法 boolean test(T t);
Predicate接口:是一个判断接口
*/
public static void main(String[] args) {
// 获取Stream流
Stream stream = Stream.of("张三丰", "张无忌", "灭绝师太", "周芷若", "张翠山", "殷素素");
// 需求:过滤出姓张的元素
stream.filter((String s) -> {
return s.startsWith("张");
}).forEach((String name)->{
System.out.println(name);
});
}
}
取用前几个
package demo08;
import java.util.stream.Stream;
public class Test2_count {
public static void main(String[] args) {
/*
limit方法:
Stream limit(long maxSize);取用前几个
注意:参数是一个long型,如果流的当前长度大于参数则进行截取;否则不进行操作
*/
// 获取Stream流
Stream stream = Stream.of("张三丰", "张无忌", "灭绝师太", "周芷若", "张翠山", "殷素素");
// 需求: 保留前3个元素
stream.limit(3).forEach(name-> System.out.println(name));
System.out.println("===============================");
//注意:参数是一个long型,如果流的当前长度大于参数则进行截取;否则不进行操作
// 获取Stream流
Stream stream1 = Stream.of("张三丰", "张无忌", "灭绝师太", "周芷若", "张翠山", "殷素素");
// 需求: 保留前7个元素,如果流的当前长度大于参数则进行截取;否则不进行操作
stream1.limit(7).forEach(name-> System.out.println(name));
}
}
跳过前几个
package demo08;
import java.util.stream.Stream;
public class Test2_count {
public static void main(String[] args) {
/*
skip方法:
Stream skip(long n);跳过前几个元素
如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。
*/
// 获取Stream流
Stream stream = Stream.of("张三丰", "张无忌", "灭绝师太", "周芷若", "张翠山", "殷素素");
// 需求: 跳过前3个元素
stream.skip(3).forEach(name -> System.out.println(name));
}
}
map:映射
/*
map方法:
Stream map(Function super T, ? extends R> mapper);
参数Function: 函数式接口,抽象方法 R apply(T t);
Function其实就是一个类型转换接口(T和R的类型可以一致,也可以不一致)
*/
// 获取流
Stream stream1 = Stream.of("10", "20", "30", "40");
// 需求:把stream1流中的元素转换为int类型
stream1.map((String s)->{return Integer.parseInt(s);}).forEach((Integer i)->{
System.out.println(i+1);
});
System.out.println("=========================");
// 获取流
Stream stream2 = Stream.of("10", "20", "30", "40");
// 需求:把stream1流中的元素转换为String类型
stream2.map((String s)->{return s+"itheima";}).forEach((String i)->{
System.out.println(i+1);
});
concat:组合
/*
concat方法:
static Stream concat(Stream extends T> a, Stream extends T> b);合并2个流
*/
// 获取流
Stream stream1 = Stream.of("10", "20", "30", "40");
// 获取Stream流
Stream stream2 = Stream.of("张三丰", "张无忌", "灭绝师太", "周芷若", "张翠山", "殷素素");
// 需求:合并stream1和stream2
Stream stream = Stream.concat(stream1, stream2);
stream.forEach(name-> System.out.println(name));
对流操作完成之后,如果需要将其结果进行收集,例如获取对应的集合、数组等,如何操作?
收集到数组中
Stream提供toArray
方法来将结果放到一个数组中,返回值类型是Object[ ]的:
package demo08;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
/*
收集到数组中:
Stream流的一个方法:
Object[] toArray() 返回一个包含此流的元素的数组。
*/
// 传统方式操作集合:
List list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张杰");
list.add("张三丰");
// 需求:过滤过滤出姓张的并且长度为3的元素
Stream stream = list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3);
// 需求:把stream流中的元素收集到数组中
Object[] arr = stream.toArray();
System.out.println(Arrays.toString(arr));
}
}
收集到集合中
package demo08;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Demo {
public static void main(String[] args) {
/*
Stream流中提供了一个方法,可以把流中的数据收集到单列集合中:
R collect(Collector super T,A,R> collector): 把流中的数据收集到单列集合中
返回值类型是R,也就是说R指定为什么类型,就是收集到什么类型的集合
参数Collector super T,A,R>中的R类型: 决定把流中的元素收集到哪个集合中
- 参数Collector如何得到? 使用java.util.stream.Collectors工具类中的静态方法:
- public static Collector> toList():转换为List集合。
- public static Collector> toSet():转换为Set集合。
*/
// 传统方式操作集合:
List list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张杰");
list.add("张三丰");
// 需求:过滤过滤出姓张的并且长度为3的元素
Stream stream1 = list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3);
// 收集到List单列集合中
List list1 = stream1.collect(Collectors.toList());
System.out.println(list1);// [张无忌, 张三丰]
// 需求:过滤过滤出姓张的并且长度为3的元素
Stream stream2 = list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3);
// 收集到Set单列集合中
Set set = stream2.collect(Collectors.toSet());
System.out.println(set);// [张无忌, 张三丰]
}
}