JDK8新特性-中部

🌕博客x主页:己不由心王道长🌕!
🌎文章说明:JDK8新特性🌎
✅系列专栏:Java基础
🌴本篇内容:对JDK8的新特性进行学习和讲解🌴
☕️每日一语:这个世界本来就不完美,如果我们再不接受不完美的自己,那我们要怎么活。☕️
🚩 交流社区:己不由心王道长(优质编程社区)

一、方法引用

1.1 为什么要有方法引用?

1.1.1 Lambda表达式冗余

在使用Lambda表达式的时候,也会出现代码冗余的情况,比如:用Lambda表达式求一个数组的和

/**
 * @Author Administrator
 * @Date 2023/6/26 13:59
 * @description
 * @Version 1.0
 */
public class FunctionRefTest01 {
    public static void main(String[] args) {
        getSum(arg1->{
            int sum = 0;
            for(int temp:arg1){
                sum+=temp;
            }
            System.out.println(sum);
        });
    }
    public static void getSum(Consumer<int[]> consumer){
        int[] arr = {10,8,6,4};
        consumer.accept(arr);
    }
}

1.1.2 解决方案

因为在Lambda表达式中要执行的代码和我们另一个方法中的代码是一样的,这时就没有必要重写一份逻辑了,这时我们就可以“引用”重复代码。

/**
 * @Author Administrator
 * @Date 2023/6/26 13:59
 * @description
 * @Version 1.0
 */
public class FunctionRefTest02 {
    public static void main(String[] args) {
       getSum(FunctionRefTest02::get);
    }

    /**
     * 获取数组元素之和
     * @param arr
     */
    public static void get(int[] arr){
        int sum = 0 ;
        for(int i:arr){
            sum+=i;
        }
        System.out.println("数组之和为:"+sum);
    }

    /**
     * Lambda表达式的用法
     * @param consumer
     */
    public static void getSum(Consumer<int[]> consumer){
        int[] arr = {10,8,6,4};
        consumer.accept(arr);
    }
}

解释: 其实就是在用Lambda表达式的时候,把小括号里面要做的操作抽离出来,作为一个单独的方法,进行引用,这样就不用每次都去编写重复的代码了。

:: 方法引用 也是JDK8中的新的语法

1.2 方法引用的格式

符号表示: ::

符号说明:双冒号为方法引用运算符,而它所在的表达式被称为 方法引用
应用场景:如果Lambda表达式所要实现的方案,已经有其他方法存在相同的方案,那么则可以使用方法引用。
常见的引用方式:
方法引用在JDK8中使用是相当灵活的,有以下几种形式:
1. instanceName::methodName 对象::方法名
2. ClassName::staticMethodName 类名::静态方法
3. ClassName::methodName 类名::普通方法
4. ClassName::new 类名::new 调用的构造器
5. TypeName[]::new String[]::new 调用数组的构造器

1.2 .1 对象::方法名
/**
 * @Author Administrator
 * @Date 2023/6/26 13:59
 * @description 对象::方法名
 * @Version 1.0
 */
public class FunctionRefTest03 {
    public static void main(String[] args) {
        Date now = new Date();
        Supplier<Long> supplier1 = ()->{return now.getTime();};
        System.out.println(supplier1.get());

        //对象::方法名
        Supplier<Long> supplier2 = now::getTime;
        System.out.println(supplier2.get());
    }
}

1687760646740
1687760646740

方法引用的注意事项:

  1. 被引用的方法,参数要和接口中的抽象方法的参数一样
  2. 当接口抽象方法有返回值时,被引用的方法也必须有返回值
1.2.2 类名::静态方法名
/**
 * @Author Administrator
 * @Date 2023/6/26 13:59
 * @description 对象::方法名
 * @Version 1.0
 */
public class FunctionRefTest04 {
    public static void main(String[] args) {
       Supplier<Long> supplier = ()->{
           return System.currentTimeMillis();
       };
        System.out.println(supplier.get());

        //类名:静态方法名
        Supplier<Long> supplier1 = System::currentTimeMillis;
        System.out.println(supplier1.get());
    }
}
1.2.3 类名::引用实例方法

Java面向对象中,类名只能调用静态方法,类名引用实例方法是用前提的,实际上是拿第一个参数作为方法的调用者:

/**
 * @Author Administrator
 * @Date 2023/6/26 13:59
 * @description 对象::方法名
 * @Version 1.0
 */
public class FunctionRefTest05 {
    public static void main(String[] args) {
        Function<String,Integer> function = (s)->{
            return s.length();
        };
        System.out.println(function.apply("为年少不可得而遗憾终身"));
        //通过方法引用实现
        Function<String,Integer> function1 = String::length;
        System.out.println(function1.apply("为年少不可得而遗憾终身"));

        BiFunction<String,Integer,String> function2 = String::substring;
        System.out.println(function2.apply("为年少不可得而遗憾终身",3));
    }
}
1.2.4 类名::构造器

由于构造器的名称和类名完全一致,所以构造器引用使用 ::new 的格式使用:

/**
 * @Author Administrator
 * @Date 2023/6/26 13:59
 * @description 构造器
 * @Version 1.0
 */
public class FunctionRefTest06 {
    public static void main(String[] args) {
        Supplier<Person> supplier1 = ()->{
            return new Person();
        };
        System.out.println(supplier1.get());
        //构造器
        Supplier<Person> supplier2 = Person::new;
        System.out.println(supplier2.get());
        BiFunction<String,Integer,Person> biFunction = Person::new;
        System.out.println(biFunction.apply("王也",18));
    }
}

结果:

Person(name=null, age=null)
Person(name=null, age=null)
Person(name=王也, age=18)

1.2.5 数组::构造器
/**
 * @Author Administrator
 * @Date 2023/6/26 13:59
 * @description 构造器
 * @Version 1.0
 */
public class FunctionRefTest07 {
    public static void main(String[] args) {
        Function<Integer,String[]> function = (len)->{
            return new String[len];
        };
        String[] strs = function.apply(3);
        System.out.println(strs.length);

        //构造器
        Function<Integer,String[]> function1 = String[]::new;
        String[] strs2 = function1.apply(5);
        System.out.println(strs2.length);
    }
}

3
5

二、Stream API

2.1 集合处理的弊端

当我们在需要对集合中的元素进行操作的时候,除了必需的添加,删除,获取外,最典型的操作就是集合遍历:

/**
 * @Author Administrator
 * @Date 2023/6/26 15:45
 * @description
 * @Version 1.0
 */
public class StreamTest01 {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("王也","通下下士","张楚岚","张灵玉");
        List<String> list1 = new ArrayList<>();
        for(String str:list){
            if(str.length()==3){
                list1.add(str);
            }
        }
        List<String> list2 = new ArrayList<>();
        for(String str:list1){
            if(str.startsWith("张")&&str.endsWith("玉")){
                list2.add(str);
            }
        }
        System.out.println(list2);
    }
}

上面的代码针对与我们不同的需求总是一次次的循环循环循环.这时我们希望有更加高效的处理方式,这时我们就可以通过JDK8中提供StreamAPI来解决这个问题了。Stream更加优雅的解决方案:

/**
 * @Author Administrator
 * @Date 2023/6/26 15:45
 * @description
 * @Version 1.0
 */
public class StreamTest02 {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("王也", "通下下士", "张楚岚", "张灵玉");
        //
        list.stream()
                .filter(s->s.startsWith("通"))
                .filter(s->s.length()==4).
                forEach(s -> System.out.println(s));

        //更加优雅写法
        list.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.endsWith("玉"))
                .forEach(System.out::println);
    }
}

上面的SteamAPI代码的含义:获取流,过滤张,过滤长度,逐一打印。代码相比于上面的案例更加的简洁直观

2.2 Steam流式思想概述

Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数
据进行加工
处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商
品。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。

2.3 Stream流的获取方式

2.3.1 通过Collection获取

首先,java.util.Collection 接口中加入了default方法 stream,也就是说Collection接口下的所有的实现都可以通过steam方法来获取Stream流:

/**
 * @Author Administrator
 * @Date 2023/6/26 16:33
 * @description
 * @Version 1.0
 */
public class StreamTest03 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.stream();
        Set<String> set = new HashSet<>();
        set.stream();
        Queue<String> queue = new ArrayDeque<>();
        queue.stream();
        Vector<String> vector = new Vector<>();
        vector.stream();
    }
}


值得注意的是Map接口别没有实现Collection接口,那这时怎么办呢?这时我们可以根据Map获取对应的key、value的集合。

/**
 * @Author Administrator
 * @Date 2023/6/26 16:33
 * @description
 * @Version 1.0
 */
public class StreamTest04 {
    public static void main(String[] args) {
        Map<String,Object> map = new HashMap<>();
        Stream<String> stream = map.keySet().stream();
        Stream<Object> stream1 = map.values().stream();
        Stream<Map.Entry<String,Object>> stream2 = map.entrySet().stream();
    }
}

2.3.2 通过Stream的of方法

在实际开发中我们不可避免的还是会操作到数组中的数据,由于数组对象不可能添加默认方法,所有Stream接口中提供了静态方法of:

    /**
     * Returns a sequential {@code Stream} containing a single element.
     *
     * @param t the single element
     * @param <T> the type of stream elements
     * @return a singleton sequential stream
     */
    public static<T> Stream<T> of(T t) {
        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
    }

    /**
     * Returns a sequential ordered stream whose elements are the specified values.
     *
     * @param <T> the type of stream elements
     * @param values the elements of the new stream
     * @return the new stream
     */
    @SafeVarargs
    @SuppressWarnings("varargs") // Creating a stream from an array is safe
    public static<T> Stream<T> of(T... values) {
        return Arrays.stream(values);
    }
/**
 * @Author Administrator
 * @Date 2023/6/26 16:33
 * @description
 * @Version 1.0
 */
public class StreamTest05 {
    public static void main(String[] args) {
        Stream<String> a1 = Stream.of("己不由心","王也","冯宝宝");
        Integer[] arr = {18,20,30};
        Stream<Integer> b1 = Stream.of(arr);
        String[] arr1 = {"己不由心","心岂会由己","自欺欺人"};
        Stream<String> b2 = Stream.of(arr1);
        b2.forEach(System.out::println);
    }
}

2.4 Stream流常用方法介绍

Stream常用方法
Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

方法名方法作用返回值类型方法种类
count统计个数long终结
forEach逐一处理void终结
filter过滤Stream函数拼接
limit取用前几个Stream函数拼接
skip跳过前几个Stream函数拼接
map映射Stream函数拼接
concat组合Stream函数拼接

终结方法:返回值类型不再是 Stream 类型的方法,不再支持链式调用。本小节中,终结方法包括count 和forEach 方法。
非终结方法:返回值类型仍然是 Stream 类型的方法,支持链式调用。(除了终结方法外,其余方法均为非终结方法。)
Stream注意事项(重要)

  1. Stream只能操作一次
  2. Stream方法返回的是新的流
  3. Stream不调用终结方法,中间的操作不会执行
2.4.1 forEach

用法:forEach用来遍历流中的数据
该方法接收一个Consumer接口,会将每一个流元素交给函数处理

    /**
     * Performs an action for each element of this stream.
     *
     * <p>This is a <a href="package-summary.html#StreamOps">terminal
     * operation</a>.
     *
     * <p>The behavior of this operation is explicitly nondeterministic.
     * For parallel stream pipelines, this operation does <em>not</em>
     * guarantee to respect the encounter order of the stream, as doing so
     * would sacrifice the benefit of parallelism.  For any given element, the
     * action may be performed at whatever time and in whatever thread the
     * library chooses.  If the action accesses shared state, it is
     * responsible for providing the required synchronization.
     *
     * @param action a <a href="package-summary.html#NonInterference">
     *               non-interfering</a> action to perform on the elements
     */
    void forEach(Consumer<? super T> action);

举例:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest06ForEach {
    public static void main(String[] args) {
        Stream.of("王也","诸葛青","冯宝宝","张楚岚")
                .forEach(System.out::println);
    }
}

结果:

王也
诸葛青
冯宝宝
张楚岚

2.4.2 count

Stream流中的count方法用来统计其中的元素个数的:

long count();

该方法返回一个long型数据,表示元素个数:
使用·:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest07Count {
    public static void main(String[] args) {
        long count = Stream.of("王也", "诸葛青", "冯宝宝", "张楚岚")
                .count();
        System.out.println(count);
    }
}
2.4.2 filter

filter方法的作用是用来过滤数据的。返回符合条件的数据
该方法接收一个Predicate接口作为参数

Stream<T> filter(Predicate<? super T> predicate);

用法:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest08Filter {
    public static void main(String[] args) {
        Stream.of("王也", "诸葛青", "冯宝宝", "张楚岚")
                .filter((s)->s.contains("王"))
                .forEach(System.out::println);
    }
}
2.4.4 limit

limit方法可以对流进行截取处理,只取前n个数据:

    /**
     * Returns a stream consisting of the elements of this stream, truncated
     * to be no longer than {@code maxSize} in length.
     *
     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
     * stateful intermediate operation</a>.
     *
     * @apiNote
     * While {@code limit()} is generally a cheap operation on sequential
     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
     * especially for large values of {@code maxSize}, since {@code limit(n)}
     * is constrained to return not just any <em>n</em> elements, but the
     * <em>first n</em> elements in the encounter order.  Using an unordered
     * stream source (such as {@link #generate(Supplier)}) or removing the
     * ordering constraint with {@link #unordered()} may result in significant
     * speedups of {@code limit()} in parallel pipelines, if the semantics of
     * your situation permit.  If consistency with encounter order is required,
     * and you are experiencing poor performance or memory utilization with
     * {@code limit()} in parallel pipelines, switching to sequential execution
     * with {@link #sequential()} may improve performance.
     *
     * @param maxSize the number of elements the stream should be limited to
     * @return the new stream
     * @throws IllegalArgumentException if {@code maxSize} is negative
     */
    Stream<T> limit(long maxSize)

用法:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest09limit {
    public static void main(String[] args) {
        Stream.of("王也", "诸葛青", "冯宝宝", "张楚岚")
                .limit(3)
                .forEach(System.out::println);
    }
}

结果:

王也
诸葛青
冯宝宝
2.4.5skip

如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest10Skip {
    public static void main(String[] args) {
        Stream.of("王也", "诸葛青", "冯宝宝", "张楚岚")
                .skip(3)
                .forEach(System.out::println);
    }
}
2.4.6 map

如果我们需要将流中的元素映射到另一个流中,可以使用map方法:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest11Map {
    public static void main(String[] args) {
       Stream.of("1","2","3","4")
               .map(Integer::parseInt)
               .forEach(System.out::println);
              
    }
}
2.4.7 sorted

对数据进行排序,支持默认排序(升序)和自定义排序(实现compartor)

Stream<T> sorted();

用法:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest12Sorted {
    public static void main(String[] args) {
       Integer[] arr = {9,8,10,7,6};
       Stream.of(arr)
               .sorted()
               .forEach(System.out::println);
    }
}
2.4.8 distinct

对元素进行去重:

普通去重:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest12Distinct {
    public static void main(String[] args) {
       Integer[] arr = {9,9,10,7,6,6};
       Stream.of(arr)
               .distinct()
               .forEach(System.out::println);
    }
}

结果:

9
10
7
6

自定义去重:
Stream流中的distinct方法对于基本数据类型是可以直接出重的,但是对于自定义类型,我们是需要重写hashCode和equals方法来移除重复元素。

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest13Distinct {
    public static void main(String[] args) {
//       Integer[] arr = {9,9,10,7,6,6};
//       //普通去重
//       Stream.of(arr)
//               .distinct()
//               .forEach(System.out::println);
//       //自定义去重
        Stream.of(
                new Person("王也",18),
                new Person("冯宝宝",18),
                new Person("张楚岚",19),
                new Person("冯宝宝",18)
        ).distinct()
                .forEach(System.out::println);

    }
}
2.4.9 match

如果需要判断数据是否匹配指定的条件,可以使用match相关的方法:注意match是一个终结方法

boolean anyMatch(Predicate<? super T> predicate); // 元素是否有任意一个满足条件
boolean allMatch(Predicate<? super T> predicate); // 元素是否都满足条件
boolean noneMatch(Predicate<? super T> predicate); // 元素是否都不满足条件

使用:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest13Match {
    public static void main(String[] args) {
       Integer[] arr = {9,9,10,7,6,6};
        boolean b = Stream.of(arr)
                .allMatch(s -> s > 3);
        System.out.println(b);//true
        boolean b1 = Stream.of(arr)
                .anyMatch(s -> s == 10);

        System.out.println(b1);//true

        boolean b2 = Stream.of(arr)
                .noneMatch(s -> s > 9);
        System.out.println(b2);
    }
}

结果:

2.4.10 find

如果我们需要找到某些数据,可以使用find方法来实现

Optional<T> findFirst();
Optional<T> findAny();
/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest15Find {
    public static void main(String[] args) {
       Integer[] arr = {9,9,10,7,6,6};
        Optional<Integer> first = Stream.of(arr)
                .findFirst();
        System.out.println(first.get());
        Optional<Integer> any = Stream.of(arr)
                .findAny();
        System.out.println(any.get());
    }
}
2.4.11 max和min

如果我们想要获取最大值和最小值,那么可以使用max和min方法:

Optional<T> min(Comparator<? super T> comparator);
Optional<T> max(Comparator<? super T> comparator);

使用:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest16MaxMin {
    public static void main(String[] args) {
      String[] arr = {"1","6","5","2000","7200","35","24"};
        Optional<Integer> max = Stream.of(arr)
                .map(Integer::parseInt)
                .max(((o1, o2) -> o1-o2));
        System.out.println(max.get());
        Optional<Integer> min = Stream.of(arr)
                .map(Integer::parseInt)
                .min(((o1, o2) -> o1-o2));
        System.out.println(max.get());
    }
}

2.4.12 reduce

如果需要将所有数据归纳得到一个数据,可以使用reduce方法:

T reduce(T identity, BinaryOperator<T> accumulator);
/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest17Reduce {
    public static void main(String[] args) {
        Integer reduce = Stream.of(1, 2, 3, 4)
                .reduce(0, (x, y) -> {
                    return x + y;
                });
        System.out.println(reduce);
    }
}
说明:0,初始化x为0,x,y作为参数,y每次都从of里顺序取数与x进行操作并且返回给x。
2.4.13 map和reduce的组合

在实际的应用中,map与reduce的组合使用是非常多的
我们举个例子使用一下:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest18ReduceMap {
    public static void main(String[] args) {
        //1、求出所有年龄的综合
        Integer reduce = Stream.of(
                        new Person("王也", 18),
                        new Person("冯宝宝", 18),
                        new Person("张楚岚", 19),
                        new Person("冯宝宝", 18)
                ).map(Person::getAge)
                .reduce(0, (x, y) -> {
                    return x + y;
                });
        System.out.println(reduce);
        //2、求出所有年龄中的最大值
        Integer Max = Stream.of(
                        new Person("王也", 18),
                        new Person("冯宝宝", 18),
                        new Person("张楚岚", 19),
                        new Person("冯宝宝", 18)
                ).map(Person::getAge)
                .reduce(0, Math::max);
        System.out.println(Max);

        //统计字符出现的次数
        Integer reduce1 = Stream.of("1", "2", "2", "3", "4")
                .map(ch -> "2".equals(ch) ? 1 : 0)
                .reduce(0, (x, y) -> {
                    return x + y;
                });
        System.out.println(reduce1);
    }
}

结果:

73
19
2
2.4.14 mapToInt

如果需要将Stream中的Integer类型转换成int类型,可以使用mapToInt方法来实现:
出现这个的原因:

由于Stream流中基本数据类型的数组类型不能有效输出,而包装类型的内存消耗比基本内容大很多,所以在进入流之后应该对其进行拆箱。
/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest19mapToInt {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        Stream.of(arr)
                .forEach(System.out::println);
        //结果:[I@404b9385
    }
}

使用:

/**
 * @Author Administrator
 * @Date 2023/6/26 20:12
 * @description
 * @Version 1.0
 */
public class StreamTest19mapToInt {
    public static void main(String[] args) {
        Integer[] arr = {2,3,5,9,7,8};
        Stream.of(arr)
                .filter(i->i>3)
                .mapToInt(Integer::intValue)
                .sorted()
                .forEach(System.out::println);
    }
}

2.4.15 concat

如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat:

    /**
    * Creates a lazily concatenated stream whose elements are all the
    * elements of the first stream followed by all the elements of the
    * second stream.  The resulting stream is ordered if both
    * of the input streams are ordered, and parallel if either of the input
    * streams is parallel.  When the resulting stream is closed, the close
    * handlers for both input streams are invoked.
    *
    * @implNote
    * Use caution when constructing streams from repeated concatenation.
    * Accessing an element of a deeply concatenated stream can result in deep
    * call chains, or even {@code StackOverflowException}.
    *
    * @param <T> The type of stream elements
    * @param a the first stream
    * @param b the second stream
    * @return the concatenation of the two input streams
    */
   public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
       Objects.requireNonNull(a);
       Objects.requireNonNull(b);

       @SuppressWarnings("unchecked")
       Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
               (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
       Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
       return stream.onClose(Streams.composedClose(a, b));
   }

使用:

/**
* @Author Administrator
* @Date 2023/6/26 20:12
* @description
* @Version 1.0
*/
public class StreamTest20Contact {
   public static void main(String[] args) {
       Stream<String> stream1 = Stream.of("1","2","3","a");
       Stream<String> stream2 = Stream.of("4","5","6","a");
       Stream.concat(stream1,stream2)
               .forEach(System.out::println);
   }
}

结果:

1
2
3
a
4
5
6
a

3、小结

这里介绍的方法并不是Stream流的全部方法,而是Stream流的常用方法,
其实很好理解,自己动手写一遍。

总结

**本来想分为上下部的,结果一看,好家伙,这字数就挺多的啦,不能再多,所以就暂且分为中部吧,最后一部是结尾篇,下部。在完成JDK8新特新的学习之后,我会把上中下整合起来,当然分开的也留着。 **

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

己不由心王道长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值