函数式接口(Functional Interface)就是一个有且仅有一个抽象方法
,但是可以有多个非抽象方法的接口
interface MathOperation { // 函数式接口
int operation(int a, int b);
}
函数式接口可以被隐式转换为 lambda 表达式
(parameters) -> expression
或
(parameters) ->{ statements; }
Lambda表达式(也可称为闭包)就是一个匿名函数(匿名方法)
public class FunctionInter {
public static void main(String[] args) {
Function function = (age)->{return "我今年"+age+"岁";};
System.out.println(function.apply(10));
}
}
public class FunctionInter {
public static void main(String[] args) {
Predicate<Integer> predicate = (num)->{return num == 0;};
System.out.println(predicate.test(1));
}
}
public class FunctionInter {
public static void main(String[] args) {
Consumer consumer = (str)->{
System.out.println(str);
};
consumer.accept("zhang");
}
}
public class FunctionInter {
public static void main(String[] args) {
Supplier supplier = ()->{return 1024;};
System.out.println(supplier.get());
}
}
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果
Stream流不保存数据,只是对数据加工处理
±-------------------+ ±-----+ ±-----+ ±–+ ±------+
| stream of elements ±----> |filter±> |sorted±> |map±> |collect|
±-------------------+ ±-----+ ±-----+ ±–+ ±------+
串行流
public class Demo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
Stream<String> stream = list.stream();
Set<String> set = new HashSet<>();
Stream<String> stream1 = set.stream();
HashMap<Integer, String> map = new HashMap<>();
Stream<Integer> stream2 = map.keySet().stream();
Stream<String> stream3 = map.values().stream();
Stream<Map.Entry<Integer, String>> stream4 = map.entrySet().stream();
}
}
public class ForEach {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("zhang");
list.add("liu");
list.add("wang");
list.stream().forEach((str)->{
System.out.println(str);
});
list.stream().forEach( // :: 这个符号代表方法调用
System.out::println
);
}
}
public class Filter {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("zhang");
list.add("liu");
list.add("wang");
list.stream().filter((str)->{
return str.length()>3;
}).forEach(s -> {
System.out.println("长度大于3的姓氏"+s);
});
}
}
public class Limit {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("zhang");
list.add("liu");
list.add("wang");
list.stream().limit(2).forEach(System.out::println); // 获取前两个数组
}
}
public class Skip {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("zhang");
list.add("liu");
list.add("wang");
list.stream().skip(2).forEach(System.out::println); // 跳过前两个数据
}
}
函数型接口,map可以将流的类型变成另外一种类型,返回的依旧是Stream流
调用map方法,将每一个字符串类型变成字符数组类型!调用foreach循环遍历每一个数组arr,对arr遍历输出每一个字符
public class MapTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("zhang");
list.add("liu");
list.add("wang");
list.stream().map((s) -> s.toCharArray()).forEach((arr) -> {
for (char c : arr) {
System.out.println(c);
}
});
}
主要用来对集合数据排序,分为无参数和有参数(下图)两种
public class Sort {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(64);
list.add(1024);
list.add(2048);
list.add(64);
list.stream().sorted().forEach(System.out::println); // 无参数排序,自然排序
System.out.println("===========");
list.stream().sorted((Integer o1,Integer o2) -> { // 自定义降序排序
return o2 - o1;
}).forEach(System.out::println);
}
}
主要用来去重集合数据
public class Distinct {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(64);
list.add(1024);
list.add(2048);
list.add(64);
list.stream().distinct().forEach(System.out::println);
}
}
注意,如果是自定义的对象,去重会失败,我们必须重写类的eaquls更改判断条件才可以实现去重
判断集合的元素是否满足某个条件,是断定型接口
public class Match {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream1 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream2 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
boolean res = stream.allMatch((num) -> { // 是否都大于40?
return num > 40;
});
System.out.println(res);
boolean res2 = stream1.anyMatch((num) -> {
return num > 99; // 是否有大于99的数据?
});
System.out.println(res2);
boolean res3 = stream2.noneMatch((num) ->{ // 是否没有小于0的元素?
return num < 0;
});
System.out.println(res3);
}
}
主要用来获取集合中的最大值和最小值,注意,必须要指定一个比较器
public class Max_Min {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream1 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
// 升序,max取最后一个数据
Optional<Integer> max = stream.max(((o1, o2) -> o1 - o2));
System.out.println(max.get());
Optional<Integer> min = stream1.min(((o1, o2) -> o1 - o2));
System.out.println(min.get());
}
}
主要用来选取一些数据进行处理
public class MapReduce {
//
public static void main(String[] args) {
Stream<Person> stream = Stream.of(
new Person("jack",18),
new Person("rose",26),
new Person("ac",23)
); // of一个流
stream.map((person) ->{
return person.getAge(); // 获取年龄
}).reduce(0,Math::max); // 0代表默认值,比如第一次0和18会比较,18大,18在和26比.....
}
}
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
int[] ints = stream.mapToInt((num) -> num.intValue()).toArray();
for (int i : ints) {
System.out.println(i);
}
}
}
进行数据收集,将数据收集到一个新的集合
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("zhang");
list.add("liu");
list.add("wang");
ArrayList<String> collect = list.stream().filter((str) -> {
return str.length() > 3;
}).collect(Collectors.toCollection(ArrayList::new));
List<Integer> integerList = stream6.collect(Collectors.toList());
}
public class Collect {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream1 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream2 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream3 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream4 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream5 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> stream6 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Optional<Integer> max = stream.collect(Collectors.maxBy((o1, o2) -> o1 - o2)); // 获取最大值
System.out.println("最大值"+max.get());
Optional<Integer> min = stream1.collect(Collectors.minBy((o1, o2) -> o1 - o2)); // 最小值
System.out.println("最小值"+min.get());
IntSummaryStatistics sum = stream2.collect(Collectors.summarizingInt((num) -> num));// 总和,ToIntFunction接口
System.out.println("总和"+sum.toString());
Double avg = stream3.collect(Collectors.averagingInt((num) -> num));// 平均值,ToIntFunction接口
System.out.println("平均值"+avg);
Map<String, List<Integer>> map = stream4.collect(Collectors.groupingBy((num) -> {
if (num > 60) return "大于60的一组";
else return "小于60的组";
}));
map.forEach((K,V) ->{
System.out.println(K +":"+V);
});
Map<Boolean, List<Integer>> booleanListMap = stream5.collect(Collectors.partitioningBy((num) -> { // 根据条件的布尔值进行分区
return num > 60;
}));
booleanListMap.forEach((K,V) ->{
System.out.println(K +":"+V);
});
}
}
示例
public class Parallel {
public static void main(String[] args) {
Stream<Integer> stream2 = Stream.of(10, 50, 24, 6, 8, 100); // of一个流
Stream<Integer> parallel = stream2.parallel();
parallel.filter((num) -> {
System.out.println(Thread.currentThread().getName()+"处理了数字"+num);
return num > 20;
}).forEach((num) ->{
System.out.println(num+"大于20");
});
}
}
可以看到多个线程处理了这个流,因此效率比较高,当然因为是多线程,处理不当会引起问题
解决线程不安全的方法
我们注意到,上面有的线程出现了ForkJoinPool,那ForkJoin是什么?
Fork/Join模块
原理
分治法
if(任务很小){
直接计算得到结果
}else{
分拆成N个子任务
调用子任务的fork()进行计算
调用子任务的join()合并计算结果
}
工作窃取
案例
计算1-1000000的和
思路:我们将任务拆分,小于2000的直接计算,否则进行拆分
实现:继承RecursiveTask,重写compute方法
public class ForkJoinTest {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
SumTask sumTask = new SumTask(1,10000000);
long start = System.currentTimeMillis();
Long res = forkJoinPool.invoke(sumTask);
long end = System.currentTimeMillis();
System.out.println(res);
System.out.println(end - start);
}
}
class SumTask extends RecursiveTask<Long>{
private static final long THRESHOLD = 2000L;
private final long start;
private final long end;
SumTask(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start; // 计算数的长度
if(length <= THRESHOLD){ // 计算
long count = 0;
for (long i = start; i <= end; i++) {
count += i;
}
return count;
}else{ // 拆分
long mid = (start+end) / 2;
SumTask left = new SumTask(start,mid);
left.fork();
SumTask right = new SumTask(mid+1,end);
right.fork();
return left.join() + right.join();
}
}
}