在函数编程里用到了一些Lamada语法,因此要先了解一些lamada的内容,然后再了解函数编程,进一步再去了解stream
一、lamada使用语法
1.1、使用格式
lambda 表达式的语法格式如下:
(parameters) -> expression
或
(parameters) ->{ statements; }
简单理解就是:“接收” -> “返回”
1.2、双冒号
这种[方法引用]或者说[双冒号运算]对应的参数类型是Function<T,R> T表示传入类型,R表示返回类型。比如表达式person -> person.getAge(); 传入参数是person,返回值是person.getAge(),那么方法引用Person::getAge就对应着Function<Person,Integer>类型。
双冒号(::)操作符是 Java 中的方法引用。 当们使用一个方法的引用时,目标引用放在 :: 之前,目标引用提供的方法名称放在 :: 之后,即 目标引用::方法。比如:
Person::getAge;
在 Person 类中定义的方法 getAge 的方法引用。
然后我们可以使用 Function 对象进行操作:
// 获取 getAge 方法的 Function 对象
Function<Person, Integer> getAge = Person::getAge;
// 传参数调用 getAge 方法
Integer age = getAge.apply(p);
目标引用的参数类型是 Function<T,R>,T 表示传入类型,R 表示返回类型。比如,表达式 person -> person.getAge();,传入参数是 person,返回值是 person.getAge(),那么方法引用 Person::getAge 就对应着 Function<Person,Integer> 类型。
1.3、简单例子
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
1.4、常见使用
/**
* 引用自:
* https://segmentfault.com/a/1190000009186509
* https://www.cnblogs.com/acelin/p/15016045.html
* 使用条件
*
* 必须有接口(不能是抽象类),接口中有且仅有一个需要被重写的抽象方法。
* 必须支持上下文推导,要能够推导出来Lambda 表达式表示的是哪个接口中的内容。
*
* 使用语法
* lambda 表达式的语法格式如下:(parameters) -> expression或(parameters) ->{ statements; }
* 简单理解就是:“接收” -> “返回”
*
* 使用例子
* Lambda 表达式的简单例子:
* // 1. 不需要参数,返回值为 5
* () -> 5
*
* // 2. 接收一个参数(数字类型),返回其2倍的值
* x -> 2 * x
*
* // 3. 接受2个参数(数字),并返回他们的差值
* (x, y) -> x – y
*
* // 4. 接收2个int型整数,返回他们的和
* (int x, int y) -> x + y
*
* // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
* (String s) -> System.out.print(s)
*
*
* 具体用法
*
* 常见使用
*/
@Service
public class UseToEight {
public static void main(String[] args) {
sort();
useThread();
useFor();
useMap();
testLogic();
useMaohao();
useStream();
}
//排序使用
public static void sort(){
List<Integer> integerList = Lists.newArrayList();
integerList.add(1);
integerList.add(10);
integerList.add(8);
System.out.println(integerList);
//[1, 10, 8]
integerList.sort((a,b) -> a-b);
System.out.println(integerList);
//[1, 8, 10]
}
//线程初始化
public static void useThread(){
// Old way
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello world,old");
}
}).start();
// New way
new Thread(
() -> System.out.println("Hello world,new")
).start();
}
//遍历输出
public static void useFor(){
// old way
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for (Integer n : list) {
System.out.print(n);
}
System.out.println();
// 使用 -> 的 Lambda 表达式
list.forEach(n -> System.out.print(n));
System.out.println();
// 使用 :: 的 Lambda 表达式
list.forEach(System.out::print);
}
//遍历map是因为有匿名内部类
public static void useMap(){
HashMap<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
for(Map.Entry<Integer, String> entry : map.entrySet()){
System.out.println(entry.getKey() + "=" + entry.getValue());
}
HashMap<Integer, String> mapNi = new HashMap<>();
mapNi.put(1, "one");
mapNi.put(2, "two");
mapNi.put(3, "three");
mapNi.forEach(new BiConsumer<Integer, String>(){
@Override
public void accept(Integer k, String v){
System.out.println(k + "=" + v);
}
});
HashMap<Integer, String> mapLa = new HashMap<>();
mapLa.put(1, "one");
mapLa.put(2, "two");
mapLa.put(3, "three");
mapLa.forEach((k, v) -> System.out.println(k + "=" + v));
//如果要执行逻辑
mapLa.forEach((k, v) -> {
k = 1;
v ="2";
});
}
public static void testLogic(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
System.out.print("输出所有数字:");
evaluate(list, (n) -> true);
System.out.print("不输出:");
evaluate(list, (n) -> false);
System.out.print("输出偶数:");
evaluate(list, (n) -> n % 2 == 0);
System.out.print("输出奇数:");
evaluate(list, (n) -> n % 2 == 1);
System.out.print("输出大于 5 的数字:");
evaluate(list, (n) -> n > 5);
}
public static void evaluate(List<Integer> list, Predicate<Integer> predicate) {
list.forEach(n -> {
if (predicate.test(n)) {
System.out.print(n + " ");
}
});
System.out.println();
}
public static void useMaohao(){
List<String> collected = new ArrayList<>();
collected.add("alpha");
collected.add("beta");
collected = collected.stream().map(string -> string.toUpperCase()).collect(Collectors.toList());
System.out.println(collected);
List<String> collectedMao = new ArrayList<>();
collectedMao.add("alpha");
collectedMao.add("beta");
collectedMao = collectedMao.stream().map(String::toUpperCase).collect(Collectors.toCollection(ArrayList::new));//注意发生的变化
System.out.println(collectedMao);
}
public static void useStream(){
// old way
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = 0;
for(Integer n : list) {
int x = n * n;
sum = sum + x;
}
System.out.println(sum);
List<Integer> lisNew = Arrays.asList(1,2,3,4,5,6,7);
int sumNew = lisNew.stream().map(x -> x*x).reduce((x,y) -> x + y).get();
System.out.println(sumNew);
}
}
public class Java8Lamada {
public static void main(String args[]){
Java8Lamada tester = new Java8Lamada();
/* 类型声明 */
MathOperation addition = (int a, int b) -> a + b;
/* 不用类型声明 */
MathOperation subtraction = (a, b) -> a - b;
/* 大括号中的返回语句 */
MathOperation multiplication = (int a, int b) -> { return a * b; };
/* 没有大括号及返回语句 */
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
/* 不用括号 */
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
/* 用括号 */
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);
greetService1.sayMessage("Lambda");
greetService2.sayMessage("Google");
}
interface MathOperation {
int operation(int a, int b);
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
interface GreetingService {
void sayMessage(String message);
}
}
1.5、使用限定
使用 Lambda 的前提
- 使用 Lambda 表达式必须具有接口,无论这个接口是 JDK 内置的接口还是自定义接口,都要求接口中有且仅有一个抽象方法(函数式接口)。
- 使用 Lambda 必须具有上下文推断。也就是方法的参数或局部变量类型必须为 Lambda 对应的接口类型,才能使用 Lambda 作为该接口的实例。
标准形式:(参数类型 参数名称) ‐> { 方法体 }
- 参数:
- 如果小括号里没有参数就使用空
()
,不可省略; - 小括号内的参数类型可以省略;
- 如果只存在一个参数,可以省略小括号;
- 如果存在多个参数,则参数名称之间使用逗号分隔,小括号不可省略;
- 如果小括号里没有参数就使用空
- 方法体:
- 如果大括号内的方法体只有一条语句,无论是否有返回值,都可以省略大括号、return 关键字及语句分号。
- 如果方法体处理逻辑过于臃肿复杂,建议使用具体子类改写,保证可读性。
1.6、参考
https://juejin.cn/post/6976478013408067598
https://blog.csdn.net/weixin_37770552/article/details/77905826
https://juejin.cn/post/6976478013408067598
https://segmentfault.com/a/1190000009186509
https://www.cnblogs.com/acelin/p/15016045.html
二、函数编程
Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,例如:
Predicate<T>——接收T对象并返回boolean
Consumer<T>——接收T对象,不返回值
Function<T, R>——接收T对象,返回R对象
Supplier<T>——提供T对象(例如工厂),不接收值
UnaryOperator<T>——接收T对象,返回T对象
BinaryOperator<T>——接收两个T对象,返回T对象
其他的参见:https://www.twle.cn/c/yufei/java8/java8-basic-funtional-interface.html
2.1、什么是函数编程
函数式编程(Function Programming,简写 FP ),和面对对象编程,面向过程编程一样,是一种编程范式。
- 面向对象编程: 把现实世界的事物和事务抽象成程序世界中的类和对象,通过封装继承多态来演示事物事件的联系。
- 函数式编程: 把现实世界的事物和事物之间的联系抽象到程序世界,抽象的是运算过程。函数式编程中的函数不是程序中的函数,而是数学中的函数(映射关系),例如:y = sin(x). 函数式编程用来描述数据之间的映射,相同的输入始终要得到相同的输出。
以上是函数式编程在程序上的解释,函数式编程最早提出是在数学领域,具体描述可查看相关资料部分的文章链接。
// 面向过程
let num1 = 1;
let num2 = 2;
let sum = num1 + num2;
console.log(sum)
//函数式
function add(n1, n2){
return n1 + n2;
}
let sum = add(2,1);
console.log(sum)
2.2、使用例子
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.RateLimiter;
import lombok.*;
import org.apache.commons.collections4.CollectionUtils;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* 函数接口
*/
public class UseToSAM {
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public static class People {
private String name;
private int age;
}
public static void main(String[] args) {
List<People> peopleList = new ArrayList<>();
peopleList.add(new People("LuoTianyan",23));
peopleList.add(new People("ff",26));
peopleList.add(new People("Tony",33));
/**
* 过滤大于25的
*/
List<People> peopleListNew = PredicateHelper.predicate(peopleList, p -> ((People) p).getAge() > 25);
System.out.println(peopleListNew);//[UseToSAM.People(name=ff, age=26), UseToSAM.People(name=Tony, age=33)]
List<People> peopleListNewOne = PredicateHelper.predicate(peopleList, new Predicate() {
@Override
public boolean test(Object o) {
return false;
}
});
/**
* setAge操作不需要返回值
*/
Consumer<People> setAgeConsumer = p -> ((People) p).setAge(18);
ConsumerHelper.consumer(peopleListNew, setAgeConsumer);
System.out.println(peopleListNew);//[UseToSAM.People(name=ff, age=18), UseToSAM.People(name=Tony, age=18)]
/**
* 输出操作不需要返回值
*/
Consumer<People> sout = p -> System.out.println((People)p);
ConsumerHelper.consumer(peopleListNew, sout);//UseToSAM.People(name=ff, age=18) UseToSAM.People(name=Tony, age=18)
/**
* 设置4个属性
*/
Supplier<People> peopleSupplier = () -> new People("init",18);
List<People> people = SupplierHelper.listFactory(4, peopleSupplier);
System.out.println(people);//[UseToSAM.People(name=init, age=18), UseToSAM.People(name=init, age=18), UseToSAM.People(name=init, age=18), UseToSAM.People(name=init, age=18)]
/**
* 输出操作不需要返回值
*/
Consumer<People> soutNew = p -> System.out.println((People)p);
ConsumerHelper.consumer(people, soutNew);//输出4个UseToSAM.People(name=init, age=18)
System.out.println();
/**
* 将People对象,转换为如下形式的字符串
*/
Function<People, String> function = (People p) -> p.getName() + p.getAge();
List<String> strings = FuctionHelper.function(peopleList, function);
System.out.println(strings);//[LuoTianyan23, ff18, Tony18]
/**
* 输出操作不需要返回值
*/
Consumer<String> soutf = p -> System.out.println(p);
ConsumerHelper.consumer(strings, soutf);//一个个输出:[LuoTianyan23, ff18, Tony18]
System.out.println();
//等价上边
List<String> collect = peopleList.stream()
.map(p -> p.getName() + p.getAge())
.collect(Collectors.toList());
collect.forEach(System.out::println);//一个个输出:[LuoTianyan23, ff18, Tony18]
}
/**
* Predicate<T> 接口,该接口定义了一个支持泛型的boolean test( T)的抽象方法
* 其函数描述符为 (T)-> boolean。
*/
public static class PredicateHelper{
/**
* 统一处理对于list的筛选条件
* 应用:
* 1.对于输入的参数进行各种判断,传递不同的表达式,用于工具类的判断
* 2. 实现方法中的内容
* 3. 封装相同的对比逻辑
*/
public static <T> List<T> predicate(List<T> list, Predicate predicate){
if (CollectionUtils.isEmpty(list)){
return new ArrayList<>(0);
}
List<T> result = new ArrayList<>(list.size());
for(int i=0; i<list.size(); i++){
T t = list.get(i);
if (predicate.test(t)) {
result.add(t);
}
}
return result;
}
public static void same(){
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> words = Arrays.asList("a", "ab", "abc");
numbers.forEach(x -> {
if (x % 2 == 0) {
//process logic
}
});
words.forEach(x -> {
if (x.length() > 1) {
//process logic
}
});
}
public static void filter(List list, Predicate condition) {
list.forEach(x -> {
if (condition.test(x)) {
//process logic
}
});
};
}
/**
* Consumer<T>接口,该接口定义了一个void accept(T)的抽象方法,其函数描述符为 (T) -> void,
* 如果你需要一个操作某一对象,但无需返回的的函数式接口,那么就可以使用Consumer<T>接口。
*/
public static class ConsumerHelper{
/**
* 对于list的值进行设置
* 应用:对输入的参数进行各种设置、输出等
*/
public static <T> void consumer(List<T> list, Consumer consumer){
if (CollectionUtils.isEmpty(list)){
return ;
}
List<T> result = new ArrayList<>(list.size());
for(int i=0; i<list.size(); i++){
T t = list.get(i);
consumer.accept(t);
}
}
}
/**
* Supplier<T>接口,既然有消费者接口(Consumer<T>),那就要有生产者接口(Supplier<T>)
* 该接口定义了一个 T get() 的抽象方法,其函数描述符为 () -> T,如果不接受入参,直接为我们生产一个指定的结果,那么就可以用Supplier<T>。
* 应用:1. 在数据库获取内容;2. 在三方接口获取内容
*/
public static class SupplierHelper{
/**
* 获取并添加
*/
public static <T> List<T> listFactory(int count, Supplier<T> supplier){
List<T> result = new ArrayList<>(count);
for(int i=0; i<count; i++){
T t = supplier.get();
result.add(t);
}
return result;
}
/**
* supplier应用
* 发生异常时重试
*/
public static class RetryUtil {
private static final int DEFAULT_RETRY_COUNT = 2;
private static final int DEFAULT_INTERVAL_MILLIS = 1000;
public static <T> T retryOnException(Supplier<T> supplier) {
return retryOnException(supplier, DEFAULT_RETRY_COUNT, DEFAULT_INTERVAL_MILLIS);
}
public static <T> T retryOnException(Supplier<T> supplier, int retryCount, int intervalTimeInMillis) {
Preconditions.checkArgument(retryCount >= 0);
int count = 0;
while (true) {
try {
return supplier.get();
} catch (Exception e) {
if (count++ < retryCount) {
Uninterruptibles.sleepUninterruptibly(intervalTimeInMillis, TimeUnit.MILLISECONDS);
continue;
}
throw e;
}
}
}
public static void retryOnException(Runnable runnable) {
retryOnException(runnable, DEFAULT_RETRY_COUNT, DEFAULT_INTERVAL_MILLIS);
}
public static void retryOnException(final Runnable runnable, int retryCount, int intervalTimeInMillis) {
retryOnException(
new Supplier<Object>() {
@Override
public Object get() {
runnable.run();
return null;
}
},
retryCount,
intervalTimeInMillis);
}
}
private static final Function<Double, RateLimiter> rateLimiterBuilder = new Function<Double, RateLimiter>() {
@Override
public RateLimiter apply(Double rate) {
return RateLimiter.create(rate);
}
};
PoiData poiData = RetryUtil.retryOnException(
new Supplier<PoiData>() {
@Override
public PoiData get() {
PoiData poiData;
try {
queryArchiveRateLimiterHolder.get().acquire();
poiData = waimaiDataFeatureThriftServiceAdaptor.getWmPoiIds(archiveId, currentPageNum,
5000, DOC_JOB_ID);
} catch (TException e) {
throw new RuntimeException(e);
}
Preconditions.checkArgument(poiData != null);
Preconditions.checkArgument(poiData.getCode() == 0);
Preconditions.checkArgument(poiData.getData() != null);
return poiData;
}
});
public class RedisSupplier <T> {
private int expire;
private TimeUnit timeUnit;
Supplier<T> supplier;
public int getExpire() {
return expire;
}
public void setExpire(int expire) {
this.expire = expire;
}
public TimeUnit getTimeUnit() {
return timeUnit;
}
public void setTimeUnit(TimeUnit timeUnit) {
this.timeUnit = timeUnit;
}
public Supplier<T> getSupplier() {
return supplier;
}
public void setSupplier(Supplier<T> supplier) {
this.supplier = supplier;
}
public RedisSupplier(int expire, TimeUnit timeUnit, Supplier<T> supplier) {
this.expire = expire;
this.timeUnit = timeUnit;
this.supplier = supplier;
}
public T get() {
return this.supplier.get();
}
}
public static class CacheUtil {
private static HashMap<String, Object> localCache = new HashMap<>();
public <T> T get(String key, RedisSupplier<T> redisSupplier) {
Object value = localCache.get(key);
if (Objects.isNull(value)) {
T result = redisSupplier.get();
this.set(key, result, redisSupplier.getExpire(), redisSupplier.getTimeUnit());
return result;
}
return (T) value;
}
public void set(String key, Object value, int expire, TimeUnit timeUnit) {
localCache.put(key, value);
}
}
public static void main(String[] args) {
RedisSupplier<String> redisSupplier = new RedisSupplier<>(1, TimeUnit.DAYS, () -> "valueB");
CacheUtil cacheUtil = new CacheUtil();
String result = cacheUtil.get("B", redisSupplier);
System.out.println(result);
}
}
/**
* Function<T,R>接口,定义了一个 R apply(T)类型的抽象函数
* 它接受一个泛型变量T,并返回一个泛型变量R,如果你需要将一个对象T映射成R,那么就可以使用Function<T,R>接口。
* 应用:输入A,返回B
*/
public static class FuctionHelper{
/**
* 对象转化成String
*
*/
public static <T> List<String> function(List<T> list, Function<T,String> function){
if (CollectionUtils.isEmpty(list)){
return new ArrayList<>(0);
}
List<String> result = new ArrayList<>(list.size());
for(int i=0; i<list.size(); i++){
T t = list.get(i);
String apply = function.apply(t);
result.add(apply);
}
return result;
}
}
public static class FunctionTest<In, Out> {
private Function<In, Out> processor = new Function<In, Out>() {
@Override
public Out apply(In in) {
return (Out) new String("apply:" + in);
}
};
public static void main(String[] args) {
FunctionTest<String, String> functionTest = new FunctionTest();
System.out.println(functionTest.processor.apply("hello~!"));
}
}
}
三、Stream
3.1、流式操作
Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中,它可以极大的提升程序员的生产力,帮助程序员写出高效率、干净、简洁的代码。Stream分为三个步骤:
1. 创建Stream
2. 中间操作
3. 终止操作
注意点:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
3.2、创建Stream
//实例化方式一:通过集合
List<String> lists = new ArrayList<String>(){{
add("Amy");
add("Tom");
add("Jine");
}};
//返回一个顺序流
Stream<String> stream = lists.stream();
//返回一个并行流
Stream<String> stream2 = lists.parallelStream();
//实例化方式二:通过数组
int[] nums = {1,2,3,4,5,56};
IntStream arrStream = Arrays.stream(nums);
//实例化方式三:通过Stream的of()
3.3、中间操作
3.4、中止操作
3.5、应用例子
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;
public class StreamFinal {
public static void main(String[] args) {
streamWithList();
streamWithMap();
streamWithObject();
streamWithOther();
}
public static void streamWithList(){
List<String> list = Arrays.asList("aaa","aaa","aaa", "bbb", "cccc", "ccccc");
/**
* 筛选:以a为开头的数据的过滤
*/
List<String> selectResult = list.stream().filter(value-> value.startsWith("a")).collect(Collectors.toList());
//或者代码块的方式
List<String> selectResultnew = selectResult.stream().filter(value-> {
return value.startsWith("a");
}).collect(Collectors.toList());
System.out.println(selectResultnew);//[aaa, aaa, aaa]
/**
* 筛选:去重复
*/
List<String> resultChong = list.stream().distinct().collect(Collectors.toList());
System.out.println(resultChong);//[aaa, bbb, ccc]
/**
* 筛选和排序:长度最长的两个
*/
List<String> resultDao = list.stream().sorted((a,b)-> b.length() - a.length()).limit(2).collect(Collectors.toList());
System.out.println(resultDao);//[ccccc, cccc]
/**
* 筛选:跳过前两个元素
*/
List<String> resultTiaoguo = list.stream().skip(2).collect(Collectors.toList());
System.out.println(resultTiaoguo);//[aaa, bbb, cccc, ccccc]
/**
* 映射:接受一个函数为参数,这个函数会应用到每一个元素,并映射成一个新元素
*/
List<String> resultBianDa = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(resultBianDa);//[AAA, AAA, AAA, BBB, CCCC, CCCCC]
//将每个元素+xin,并且返回新的数组
List<String> newIntList = list.stream().map(str -> str+"xin").collect(Collectors.toList());
System.out.println(newIntList);//[aaaxin, aaaxin, aaaxin, bbbxin, ccccxin, cccccxin]
/**
* 映射:mapToInt、mapToLong、mapToDouble
* 这三个方法除了对应返回三种指定类型的stream外其他使用方法和作用和map类似,相当于map方法的特例
* mapToDouble方法统计集合中个元素的字符长度,统计结果保存在DoubleStream流中返回,该流中只能包含int类型数据,map方法也能达到同样的目的
* list.stream().map(a -> a.length()).forEach(System.out::println);
* 可以用来求:mapToDouble求最大、最小、和、平均值
*/
OptionalDouble resultBianDaTe = list.stream().mapToDouble(str -> str.length()).max();
System.out.println(resultBianDaTe.getAsDouble());//5.0
/**
*
* 映射:接受一个函数为参数,将流中的每一个值都换成另外一个流,然后把所有的流都连接成一个流,打平
*/
List<List<Integer>> flatIntList = Arrays.asList(Arrays.asList(1,2,4),Arrays.asList(4,12),Arrays.asList(5,32),Arrays.asList(23,11));
List<Integer> collect = flatIntList.stream().flatMap(Collection::stream).collect(Collectors.toList());
System.out.println(collect);//[1, 2, 4, 4, 12, 5, 32, 23, 11]
/**
* 匹配:是否所有的项都是以a开头
*/
boolean result = list.stream().allMatch(c->{
return c.startsWith("a");
});
System.out.println(result);//false
/**
* 匹配:是否有任何一项是否以a开头
*/
result = list.stream().anyMatch(c->{
return c.startsWith("a");
});
System.out.println(result);//true
/**
* 匹配:是否都不以a开头
*/
result = list.stream().noneMatch(c->{
return c.startsWith("a");
});
System.out.println(result);//false
/**
* 匹配:返回第一个元素
*/
String resultFirst = list.stream().findFirst().get();
System.out.println(resultFirst);//aaa
/**
* 匹配:返回任意一条数据
*/
String resultAny = list.stream().findAny().get();
System.out.println(resultAny);//aaa
System.out.println();
/**
*
* reduce:map()和filter()都是Stream的转换方法,而Stream.reduce()则是Stream的一个聚合方法,它可以把一个Stream的所有元素按照聚合函数聚合成一个结果。
* 规约:加和,identity:是初始化的值,比如下边identity为8的话,总和就是53
*/
int sum = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(0, (sumSlow, n) -> sumSlow + n);
System.out.println(sum); // 45
/**
* 规约:相乘
*/
int s = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(1, (acc, n) -> acc * n);
System.out.println(s); // 362880
/**
* 规约:连接字符串
*/
String[] strings = {"a", "b", "c", "d", "e"};
// |a|b|c|d|e , the initial | join is not what we want
String reduce = Arrays.stream(strings).reduce("", (a, b) -> a + "|" + b);
System.out.println(reduce);//|a|b|c|d|e|
// a|b|c|d|e, filter the initial "" empty string
String reduce2 = Arrays.stream(strings).reduce("", (a, b) -> {
if (!"".equals(a)) {
return a + "|" + b;
} else {
return b;
}
});
System.out.println(reduce2);//a|b|c|d|e|
/**
* 规约:list转为string
*/
//Reduce List to String.
List<String> listReduce = Arrays.asList("Mohan", "Sohan", "Mahesh");
Optional<String> re = listReduce.stream().reduce((x, y) -> x +"," + y);
System.out.println(re.get());//Mohan,Sohan,Mahesh
/**
* 规约:求最大的元素
*/
List<Integer> listmax = Arrays.asList(4, 2, 6, 5, 9, 1);
int resu = listmax.stream().reduce(Integer.MIN_VALUE, (a,b) ->{
if(a>b){
return a;
}else {
return b;
}
});
System.out.println(resu);//9
}
public static void streamWithMap(){
Map<String, String> mapUsed = Maps.newHashMap();
mapUsed.put("1","10");
mapUsed.put("2","20");
mapUsed.put("3","30");
mapUsed.put("4","30");
/**
* map转list
*/
List<String> resultZhuan = mapUsed.values().stream().collect(Collectors.toList());
System.out.println(resultZhuan);//[10, 20, 30, 30]
/**
* map转list并去重
*/
List<String> resultCHong = mapUsed.values().stream().distinct().collect(Collectors.toList());
System.out.println(resultCHong);//[10, 20, 30]
}
public static void streamWithObject(){
List<People> list = new ArrayList();
list.add(new People(20, 30000, "张"));
list.add(new People(25, 20000, "王"));
list.add(new People(30, 40000, "李"));
/**
* Function.identity() 等价于形如t -> t形式的Lambda表达式
* 使用toMap()函数之后,返回的就是一个Map了,自然会需要key和value。
* toMap()的第一个参数就是用来生成key值的,第二个参数就是用来生成value值的。
*
*/
Map<Integer, People> collect = list.stream().collect(Collectors.toMap(People::getAge, Function.identity()));
System.out.println(collect);//{20=People{age=20, salary=30000, name='张'}, 25=People{age=25, salary=20000, name='王'}, 30=People{age=30, salary=40000, name='李'}}
collect.forEach((key, value) -> {
System.out.println(key + ":" +value.toString());
});
/**
* 使用toMap()函数之后,返回的就是一个Map了,自然会需要key和value。
* toMap()的第一个参数就是用来生成key值的,第二个参数就是用来生成value值的。
* 第三个参数用在key值冲突的情况下:如果新元素产生的key在Map中已经出现过了,第三个参数就会定义解决的办法。
* 第一个参数:Person:getId表示选择Person的getId作为map的key值;
* 第二个参数:v->v表示选择将原来的对象作为Map的value值
* 第三个参数:(a,b)->a中,如果a与b的key值相同,选择a作为那个key所对应的value值。
*/
Map<Integer, People> collect1 = list.stream().collect(Collectors.toMap(People::getAge, Function.identity(), (a,b)->a));
System.out.println(collect1);//,如果两个key是20的话,第一个key是张的{20=People{age=20, salary=30000, name='张'}, 30=People{age=30, salary=40000, name='李'}}
Map<Integer, People> collect2 = list.stream().collect(Collectors.toMap(People::getAge, v -> v, (a,b)->a));
Map<Integer, Integer> collectKeyValue = list.stream().collect(Collectors.toMap(People::getAge, People::getSalary, (a,b)->a));
System.out.println(collectKeyValue);//根据两个属性构造map:{20=30000, 25=20000, 30=40000}
Map<Integer, Integer> collectKeyValueCon = list.stream().collect(Collectors.toMap(People::getAge, People::getSalary, (a,b)->a, ConcurrentHashMap::new));//构造ConcurrentHashMap
Collection<People> values = list.stream().collect(Collectors.toMap(People::getAge, Function.identity(), (a, b) -> a)).values();
long count = list.stream().collect(Collectors.toMap(People::getAge, Function.identity(), (a, b) -> a)).values().stream().count();
System.out.println(count);//3
/**
* list对象转化为list字符串
*/
List<String> hobby1 = Arrays.asList("java", "c", "音乐");
List<String> hobby2 = Arrays.asList("c++", "c", "游戏");
List<User> users = Arrays.asList(new User(1, "张三", hobby1), new User(2, "李四", hobby2));
// 将集合中每个用户的爱好进行计算,取并集
List<String> result = users.stream()
// 获取出每个用户的hobby列表,.map()处理完之后的流中包含若干list
.map(user -> user.hobby)
// 通过flatMap对流中的list进行展平
.flatMap(Collection::stream)
// 去重
.distinct()
// 收集为list
.collect(Collectors.toList());
System.out.println(result); // [java, c, 音乐, c++, 游戏]
/**
* 对象的排序
*/
List<People> peopleList=Arrays.asList(new People(20, 30000, "张"),new People(20, 10000, "王"),new People(25, 29121, "李"));
List<People> studentList1= peopleList.stream().sorted(Comparator.comparing(People::getAge)).collect(Collectors.toList());//根据年龄自然顺序
System.out.println(studentList1);//[People{age=20, salary=30000, name='张'}, People{age=20, salary=10000, name='王'}, People{age=25, salary=29121, name='李'}]
List<People> studentList2= peopleList.stream().sorted(Comparator.comparing(People::getAge).reversed()).collect(Collectors.toList());//根据年龄逆序
System.out.println(studentList2);//[People{age=25, salary=29121, name='李'}, People{age=20, salary=30000, name='张'}, People{age=20, salary=10000, name='王'}]
List<People> studentList3= peopleList.stream().sorted(Comparator.comparing(People::getAge).thenComparing(People::getSalary)).collect(Collectors.toList());//相同更具薪水排序
System.out.println(studentList3);//[People{age=20, salary=10000, name='王'}, People{age=20, salary=30000, name='张'}, People{age=25, salary=29121, name='李'}]
/**
* 根据列表中对象的某一个值取最大最小值
*/
Double resultA = studentList1.stream().mapToDouble(People::getAge).sum();//和
System.out.println(resultA);//67.0
Double resultB = studentList1.stream().mapToDouble(People::getAge).max().getAsDouble();//最大
System.out.println(resultB);//25.0
Double resultC = studentList1.stream().mapToDouble(People::getAge).min().getAsDouble();//最小
System.out.println(resultC);//20.0
Double resultD = studentList1.stream().mapToDouble(People::getAge).average().getAsDouble();//平均值
System.out.println(resultD);//22.33
/**
* 统计信息
*/
IntSummaryStatistics stat = studentList1.stream().mapToInt(People::getSalary).summaryStatistics();
System.out.println(stat.getMax() + ":" + stat.getMin() + ":" + stat.getCount());//30000:10000:3
/**
* 统计personList每个年龄对应的人数
*/
Map<Integer,Long> countPeople = studentList1.stream().collect(Collectors.groupingBy(People::getAge, Collectors.counting()));
System.out.println(countPeople);//{20=2, 25=1}
/**
* 根据年龄分组,和下边的效果一样
*/
Map<Integer, List<People>> map = studentList1.stream().collect(Collectors.toMap(People::getAge,
Lists::newArrayList, (listToMap, value) -> {
listToMap.addAll(value);
return listToMap;
}));
System.out.println(map);//{20=[People{age=20, salary=30000, name='张'}, People{age=20, salary=10000, name='王'}], 25=[People{age=25, salary=29121, name='李'}]}
/**
* 根据年龄分组,和上边的效果一样
*/
Map<Integer, List<People>> groupByAge = studentList1.stream().collect(Collectors.groupingBy(People::getAge));
System.out.println(groupByAge);//{20=[People{age=20, salary=30000, name='张'}, People{age=20, salary=10000, name='王'}], 25=[People{age=25, salary=29121, name='李'}]}
/**
* 根据年龄分组,并把组的内容转化成名字的list
*/
Map<Integer, List<String>> collect5 = studentList1.stream().collect(Collectors.groupingBy(People::getAge, Collectors.mapping(People::getName, Collectors.toList())));
System.out.println(collect5);//{20=[张, 王], 25=[李]}
/**
* 多层分组
*/
Map<Integer, Map<Integer, List<People>>> collect7 = studentList1.stream().collect(Collectors.groupingBy(People::getAge, Collectors.groupingBy(People::getAge)));
System.out.println(collect7);//{20={20=[People{age=20, salary=30000, name='张'}, People{age=20, salary=10000, name='王'}]}, 25={25=[People{age=25, salary=29121, name='李'}]}}
/**
* 这 partitioningBy(predicate) 方法返回一个 Collector 根据给定的划分输入元素 Predicate, 并将它们组织成一个 Map<Boolean, List<T>>.
*/
Map<Boolean, List<People>> collect8 = studentList1.stream().collect(Collectors.partitioningBy(per -> per.getAge() > 20));
System.out.println(collect8);//{false=[People{age=20, salary=30000, name='张'}, People{age=20, salary=10000, name='王'}], true=[People{age=25, salary=29121, name='李'}]}
}
public static void streamWithOther(){
//从给定句子中返回单词长度大于1的单词列表,按长度倒序输出,最多返回2个
Arrays.stream("st,wq,yu".split(",")).filter(w->w.length()>1).sorted((x, y) -> x.length() - y.length()).limit(2).collect(Collectors.toList());
}
public static class People{
private int age;
private int salary;
private String name;
public People(int age, int salary, String name) {
this.age = age;
this.salary = salary;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"age=" + age +
", salary=" + salary +
", name='" + name + '\'' +
'}';
}
}
public static class User {
Integer id;
String name;
List<String> hobby;
public User(Integer id, String name, List<String> hobby) {
this.id = id;
this.name = name;
this.hobby = hobby;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", hobby=" + hobby +
'}';
}
}
}
3.6、参考
https://heapdump.cn/article/4481824
https://developer.aliyun.com/article/757681
https://juejin.cn/post/7021062808326373383
https://juejin.cn/post/6844903564993626120
https://www.cnblogs.com/therhyme/p/10768367.html