什么是函数式编程?
一切都是数学函数。函数式编程语言里也可以有对象,但通常这些对象都是恒定不变的 —— 要么是函数参数,要什么是函数返回值。函数式编程语言里没有 for/next 循环,因为这些逻辑意味着有状态的改变。相替代的是,这种循环逻辑在函数式编程语言里是通过递归、把函数当成参数传递的方式实现的。
一、lambda表达式
组成:参数列表、箭头符号(->)和函数体
具体展现形式:
- 表达式函数(没有return):表达式会被执行然后返回执行结果。
- 语句块表达式(每一条路径都要有return):语句块中的语句会被依次执行,就像方法中的语句一样
事例:
package com.example.demo;
import org.junit.Test;
/**
* @Author helloc
* @Date 2020/4/14 11:15
* @Version 1.0
*/
public class Lambda {
@Test
public void test(){
//用lambda新建线程,线程内部只有一条语句
new Thread(()->System.out.println("i")).start();
//用lambda新建线程,线程内部有执行方法
new Thread(()->{
for (int i = 0; i <5 ; i++) {
System.out.println("i");
}
}
).start();
List<String> languages = Arrays.asList("java","scala","python");
//集合的遍历操作 java 8 前
System.out.println("java 8 前");
for(String s: languages){
System.out.println(s);
}
// java 8 lambda
System.out.println("java 8 lambda");
languages.forEach(s -> System.out.println(s));
// java 8 stream lambda
System.out.println("java 8 stream lambda");
languages.stream().forEach(s -> System.out.println(s));
}
}
集合基于1.8后进行流(Stream)操作;
大概能分成三类:
-
Intermediate(中间操作,意思就是用完这些方法还可以继续用终端操作)
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered -
Terminal(终端操作)
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator -
Short-circuiting(短路)
anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
常见操作如下:
package com.example.demo;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author helloc
* @Date 2020/4/14 11:15
* @Version 1.0
*/
public class Lambda {
@Test
public void test(){
List<String> languages = Arrays.asList("java","scala","python");
//对象数组取一个字段组成a,b,c 结果 java,scala,python
languages.stream().map(x->x).collect(Collectors.joining(","));
//1.map/flatMap
//map的作用就是把 inputStream 的每一个元素,映射成 outputStream 的另外一个元素 flatmap则代表一对多
//将list中每个字符都变成大写
languages.stream().map(String::toUpperCase).collect(Collectors.toList());
//结果:JAVA SCALA PYTHON
//将list中每个字符都追加一个1
languages.stream().map(n->n+'1').collect(Collectors.toList());
//结果:java1 scala1 python1
// flatMap 把多个集合的值都放进流中最后去转换成一个集合
Stream<List<Integer>> inputStream = Stream.of(Arrays.asList(1),Arrays.asList(2, 3),Arrays.asList(4, 5, 6));
Stream<Integer> outputStream = inputStream.
flatMap((childList) -> childList.stream());
List<Integer> num=outputStream.collect(Collectors.toList());
num.forEach(x->System.out.println(x));
//结果:1 2 3 4 5 6
//2.filter 过滤 筛选出来长度大于4的集合
languages=languages.stream().filter(x->x.length()>4).collect(Collectors.toList());
//结果:languages为 {"scala","python"}
//3.forEach forEach 和常规 for 循环的差异不涉及到性能,它们仅仅是函数式风格与传统 Java 风格的差别。
languages.stream().filter(x->x.length()>4).forEach(s->System.out.println("1:"+s));
//结果:1:scala 1:python
//4.peek 对每个元素操作并返回一个新的stream 然后之后操作都在这个新的stream上操作
languages.stream().filter(x->x.length()>4).peek(x->System.out.println(x)).map(String::toUpperCase).collect(Collectors.toList());
//结果:scala python SCALA PYTHON
//5.findFirst 用来判断空指针 因为集合为string 把list第一个元素拿出来用map output转换为int,集合为null则返回-1
languages.stream().findFirst().map(String::length).orElse(-1);
//打印集合中第一个元素,如果集合为空则打印false
languages.stream().findFirst().orElse("false");
//判断字符串是否为空字符串
String str="xxx";
int s= Optional.ofNullable(str).map(String::length).orElse(-1);
//reduce 主要作用是把 Stream 元素组合起来 reduce(初始位,BinaryOperator操作) 所谓初始位 结果=初始位+BinaryOperator得到的值
//合并所有元素 结果x=""+javascalapython
String x=languages.stream().reduce("",String::concat);
// 求最小值,minValue = -3.0 从10.0到-3.0 获取最小
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(10.0, Double::min);
// 求和,sumValue = 10, 有起始值 0+ 10=10
int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
// 求和,sumValue = 10, 无起始值 由于没有初始值 所以得到的是option 所以用get()
sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
//limit/skip limit返回前n个元素 skip则扔掉前n个元素 结果为scala
languages.stream().skip(1).limit(1).collect(Collectors.toList());
//sorted 排序 结果:javapythonscala
languages= languages.stream().sorted((a,b)-> a.compareTo(b)).collect(Collectors.toList());
//match
//allMatch:Stream 中全部元素符合传入的 predicate,返回 true 结果true
boolean s=languages.stream().allMatch(x->x.length()>2);
//anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true 结果true
boolean s=languages.stream().allMatch(x->x.equal("scala"));
//noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true 结果true
boolean s=languages.stream().allMatch(x->x.equal("xxxx"));
}
}
总之,Stream 的特性可以归纳为:
- 不是数据结构
- 它没有内部存储,它只是用操作管道从 source(数据结构、数组、generator function、IO channel)抓取数据。
- 它也绝不修改自己所封装的底层数据结构的数据。例如 Stream 的 filter 操作会产生一个不包含被过滤元素的新 Stream,而不是- - 从 source 删除那些元素。
- 所有 Stream 的操作必须以 lambda 表达式为参数
- 不支持索引访问
- 你可以请求第一个元素,但无法请求第二个,第三个,或最后一个。不过请参阅下一项。
- 很容易生成数组或者 List
- 惰性化
- 很多 Stream 操作是向后延迟的,一直到它弄清楚了最后需要多少数据才会开始。
- Intermediate 操作永远是惰性化的。
- 并行能力
- 当一个 Stream 是并行化的,就不需要再写多线程代码,所有对它的操作会自动并行进行的。
- 可以是无限的
- 集合有固定大小,Stream 则不必。limit(n) 和 findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成。
二、方法引用
类型 | 示例 | 代码示例 | 对应的Lambda表达式 |
---|---|---|---|
引用静态方法 | ContainingClass::staticMethodName | String::valueOf | (s) -> String.valueOf(s) |
引用某个对象的实例方法 | containingObject::instanceMethodName | x::toString() | () -> this.toString() |
引用某个类型的任意对象的实例方法 | ContainingType::methodName | String::toString | (s) -> s.toString |
引用构造方法 | ClassName::new String::new | () -> new String() |
package com.example.demo;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author helloc
* @Date 2020/4/14 11:15
* @Version 1.0
*/
public class Lambda {
@Test
public void test(){
List<String> languages = Arrays.asList("scala","java","python");
//方法引用
languages= languages.stream().sorted(String::compareTo).collect(Collectors.toList());
//普通lambda
languages= languages.stream().sorted((a,b)->a.compareTo(b)).collect(Collectors.toList());
languages.stream().forEach(System.out::println);
}
}
lambda两个集合操作
package com.ymdd.galaxy.appmanage.core.appauth.service;
import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;
public class Test {
public static void main(String[] args) {
List<String> list1 = new ArrayList<String>();
list1.add("1");
list1.add("2");
list1.add("3");
list1.add("5");
list1.add("6");
List<String> list2 = new ArrayList<String>();
list2.add("2");
list2.add("3");
list2.add("7");
list2.add("8");
// 交集
List<String> intersection = list1.stream().filter(item -> list2.contains(item)).collect(toList());
System.out.println("---交集 intersection---");
intersection.parallelStream().forEach(System.out :: println);
// 差集 (list1 - list2)
List<String> reduce1 = list1.stream().filter(item -> !list2.contains(item)).collect(toList());
System.out.println("---差集 reduce1 (list1 - list2)---");
reduce1.parallelStream().forEach(System.out :: println);
// 差集 (list2 - list1)
List<String> reduce2 = list2.stream().filter(item -> !list1.contains(item)).collect(toList());
System.out.println("---差集 reduce2 (list2 - list1)---");
reduce2.parallelStream().forEach(System.out :: println);
// 并集
List<String> listAll = list1.parallelStream().collect(toList());
List<String> listAll2 = list2.parallelStream().collect(toList());
listAll.addAll(listAll2);
System.out.println("---并集 listAll---");
listAll.parallelStream().forEachOrdered(System.out :: println);
// 去重并集
List<String> listAllDistinct = listAll.stream().distinct().collect(toList());
System.out.println("---得到去重并集 listAllDistinct---");
listAllDistinct.parallelStream().forEachOrdered(System.out :: println);
System.out.println("---原来的List1---");
list1.parallelStream().forEachOrdered(System.out :: println);
System.out.println("---原来的List2---");
list2.parallelStream().forEachOrdered(System.out :: println);
}
}