函数编程和Stream

news2024/9/29 13:19:27

在函数编程里用到了一些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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/128916.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

专家通过六点考证唐村《李氏族谱》:辨别家谱真伪,有这些窍门

如何辨别家谱真实性 家谱与史书、地方志都是史学界无比重视的史料文献&#xff0c;诸如唐村《李氏族谱》就为我们解开了明末、传统武术、太极拳等谜团&#xff0c;也让我们站在社会底层的角度看到了明末清初的种种变革和生活影响。但家谱的内容相比较史书与地方志而言&#xf…

DEJA_VU3D - Cesium功能集 之 091-绘制等高线(纯前端)

前言 编写这个专栏主要目的是对工作之中基于Cesium实现过的功能进行整合,有自己琢磨实现的,也有参考其他大神后整理实现的,初步算了算现在有差不多实现小130个左右的功能,后续也会不断的追加,所以暂时打算一周2-3更的样子来更新本专栏(尽可能把代码简洁一些)。博文内容…

Allegro如何实现交换functions操作详细指导

Allegro如何实现交换functions操作详细指导 在做PCB设计的时候,换function也是用的较多的功能。但是前提是确保交换是被允许的 同样下面用下图为例介绍Allegro中是如何实现交换function的 具体操作如下 选择File选择Export-Libraries

学习使用html2canvas生成渐变色背景图片

学习使用html2canvas生成渐变色背景图片全部代码html2canvas官网生成图片的下载全部代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>生成渐变色背景图片</title> </head><style>#grad1 {width: 75…

c#入门-数字的字面量

指定类型 整数类型适应性类型 通常情况下&#xff0c;整数的字面量写出来是int类型。 如果数字足够大&#xff0c;那么会逐渐变成long&#xff0c;ulong类型 指定整数类型 或者&#xff0c;在数字后加上L&#xff08;不区分大小写&#xff0c;但一般用大写的L&#xff0c;…

Blender K帧与曲线编辑器

文章目录关键帧.三种K帧方式.自动K帧.物体属性K帧.快捷键K帧.曲线编辑器.打开曲线编辑器.曲线编辑器介绍.控制柄类型.插值模式.关键帧. 1 点击一个模型&#xff0c;即可在时间轴上看到这个模型的关键帧 2 blender的关键帧使用菱形表示 3 未选中的关键帧是灰色&#xff0c;选中…

Eyeshot 2023 预期 Eyeshot 2023 二月发布

Eyeshot 2023 预期 定价和包装 Eyeshot 2023 许可证将仅限于多平台。为了简化激活码的管理并防止平台升级/降级/切换疯狂&#xff0c;所有 Eyeshot 2023 许可证将包括 WinForms、WPF 和中立的跨平台核心。 因此&#xff0c;客户可以免费试用 WinForms、WPF 或中立的跨平台核心&…

FPGA知识汇集-源同步时序系统

02. 源同步时序系统 针对普通时钟系统存在着限制时钟频率的弊端&#xff0c;人们设计了一种新的时序系统&#xff0c;称之为源同步时序系统。它最大的优点就是大大提升了总线的速度&#xff0c;在理论上信号的传送可以不受传输延迟的影响。下面我们来看看这种源同步时钟系统的结…

Python接口测试实战3(下)- unittest测试框架

本节内容 unittest简介用例编写用例组织及运行生成测试报告 unitttest简介 参考&#xff1a;unittest官方文档 翻译版 为什么要使用unittest&#xff1f; 在编写接口自动化用例时&#xff0c;我们一般针对一个接口建立一个.py文件&#xff0c;一条测试用例封装为一个函数&…

前端性能优化(二):浏览器渲染优化

目录 一&#xff1a;浏览器渲染原理和关键渲染路径&#xff08;CRP&#xff09; 1.1.浏览器渲染过程 1.2.DOM树 1.3.CSS树 1.4.浏览器构建渲染树 二&#xff1a;回流与重绘 2.2.影响回流的操作 2.3.避免布局抖动&#xff08;layout thrashing&#xff09; 三&#xff1a…

如何创建Android图表数据可视化应用程序?图表工具LightningChart助力轻松实现(上)

LightningChart JS 是一款高性能的 JavaScript 图表工具&#xff0c;专注于性能密集型、实时可视化图表解决方案。 LightningChart .JS | 下载试用https://www.evget.com/product/4189/download本次我们将介绍如何使用Android Studio 和 LightningChart JS (IIFE)创建一个 and…

Linux基础-学会使用命令帮助

概述 Linux 命令及其参数繁多&#xff0c;大多数人都是无法记住全部功能和具体参数意思的。在 linux 终端&#xff0c;面对命令不知道怎么用&#xff0c;或不记得命令的拼写及参数时&#xff0c;我们需要求助于系统的帮助文档&#xff1b; linux 系统内置的帮助文档很详细&…

KubeSphere多租户系统

目录 &#x1f9e1;多租户系统层级 &#x1f360;集群 &#x1f360;企业空间 &#x1f360;项目 &#x1f49f;这里是CS大白话专场&#xff0c;让枯燥的学习变得有趣&#xff01; &#x1f49f;没有对象不要怕&#xff0c;我们new一个出来&#xff0c;每天对ta说不尽情话&…

路由器OpenConnect图文教程

前提需求 openwrt 路由器或其他能够部署 OpenConnect 的设备建议 上行 30M的宽带以保证使用体验拥有 公网 IP并配置端口映射本文以 openwrt 路由器内网网段 192.168.1.0 为例. 基本设置 登录 OpenWRT路由器,打开 服务 – OpenConnect . 勾选 Enable server 启动服务 默认端…

第005课 - 项目微服务划分图

文章目录 项目微服务划分图项目微服务划分图 admin-vue是面向工作人员使用的前端系统。 shop-vue是面向用户使用的前端系统。 当然我们可以有手机app和小程序。 请求通过api到达微服务群。 业务微服务群: 商品服务优惠服务仓储服务订单服务中央认证服务支付服务用户服务秒杀…

Kubernetes 正式发布 v1.26,稳定性显著提升

太平洋时间 2022 年 12 月 8 号 Kubernetes 正式发布了主题为 Electrifying 的 v1.26。 作为 2022 年最后的一个版本&#xff0c;增加了很多新的功能&#xff0c;同时在稳定性上也得到显著提升&#xff0c;我们将从以下多个角度来介绍 1.26 版本的更新。 更新概览&#xff1a…

app渗透为何一开启代理就断网?

前言 今天测试app&#xff0c;开启安卓代理&#xff0c;一点击准备登录时&#xff0c;抛出了如下提示“java.security.cert.CertPathValidatorException: Trust anchor for certification path not found”&#xff0c;大概意思就是证书的安全性问题 而当我把代理关闭了&#…

一、常用文件管理命令

目录1、LinuxOS 基本文件结构2、文件常用指令1、LinuxOS 基本文件结构 几种路径&#xff1a; 绝对路径&#xff1a;以 / 开头相对路径当前路径&#xff1a;.上一级路径&#xff1a;..home 目录&#xff1a;~/ 2、文件常用指令 ctrl c&#xff1a;取消命令&#xff0c;并且换…

Ubuntu设置USB设备别名

Ubuntu设置USB设备别名硬件连接软件设置更新电平转换芯片的serial创建设备别名使用设备别名硬件连接 ROS主控通过usb线连接到一个TTL电平转换芯片&#xff0c;再由这个电平转换芯片连接STM32芯片 电平转换芯片可以通过PCB设计在STM32芯片的电路板上&#xff0c;也可以使用一个…

2022-12-29 [整理]flex弹性布局

文章目录0.前言1.设置flex布局后的父子元素2.容器(父元素)的属性3.项目(子元素)的属性4.示例一:flex布局实现flex容器中子元素的水平垂直居中5.示例二:flex:1实现子元素平分flex容器宽度6.示例三:换行,多行布局7.示例四:flex-grow,flex-shrink和flex-basis属性的使用7.1.flex-g…