[lambda表达式]-[函数式接口]-[Stream接口]

一. lambda表达式

1. lambda表达式基础语法格式

  1. 无参数,无返回值
    (1)语法:() -> System.out.println("hello lambda");
    (2)例子

    public void test1() {
        Runnable r1 = () -> System.out.println("hello lambda");
        r1.run();
    }
    
    // 函数式接口Runnable
    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }
    
  2. 有1个参数,无返回值
    (1)语法:(x) -> System.out.println(x); 或 x -> System.out.println(x);
    (2)说明:当只有一个参数时,可以省略参数的小括号。
    (3)例子

    public void test2(){
        // 定义函数式接口的实现
        Consumer<String> con = (x) -> System.out.println(x);
        // 调用接口实现的方法
        con.accept("有一个参数,无返回值");
    }
    
    // 函数式接口Consumer
    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
    }
    
  3. 有2个参数,有返回值
    (1)语法:(x, y) -> x + y
    (2)例子

public void test3() {
    BinaryOperator<Integer> binary = (x, y) -> x + y;
    System.out.println(binary.apply(1, 2)); // 3
}
  1. 有多个参数
    (1)说明:如果lambda表达式的代码块有多行语句,只需要用大括号{}把语句包含起来;对于有返回值和无返回值的情况,只有一个return的区别。如果只有一条语句,大括号和return都可以不用写。
    (2)例子
public void test4() {
    // 无返回值lambda函数体中用法
    Runnable r1 = () -> {
        System.out.println("hello lambda1");
        System.out.println("hello lambda2");
        System.out.println("hello lambda3");
    };
    r1.run();

    // 有返回值lambda函数体中用法
    BinaryOperator<Integer> binary = (x, y) -> {
        int a = x * 2;
        int b = y + 2;
        return a + b;
    };
    System.out.println(binary.apply(1, 2));// 3

2. lambda表达式支持的方法引用和构造器引用

  1. 概述
    • 如果lambda表达式的代码块只有一条代码,可以在代码块中使用方法引用和构造器引用。它们可以让Lambda表达式更简洁。
    • 方法引用和构造器引用都需要使用两个英文冒号
  2. 方法引用和构造器引用总览
种类对应的lambda表达式语法说明举例
指向类方法的方法引用(a,b)->类名.类方法(a,b)类名::类方法函数式接口被实现方法的全部参数传给该类方法作为参数(x)->Integer.parseInt(x) Integer::parseInt
指向某类对象的实例方法的方法引用(a,b)->a.实例方法(b)某类对象的类名::实例方法函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数(x,y)->x.equals(y) String::equals
指向特有对象/现有对象的实例方法的方法引用(a,b,…)->特定对象.实例方法(a,b,…)特定对象::实例方法函数式接口被实现方法的全部参数传给该方法作为参数x->System.out.println(x) System.out::println
构造器的引用(a,b,…)->new 类名(a,b,…)类名::new函数式接口中被实现方法的全部参数传给该构造器作为参数()->new Emp() Emp::new
  1. 举例
@FunctionalInterface
interface Converter{
    Integer convert(Stirng from);
}

public void test6() {
    /*************** 方法引用 ****************/
    // 1. 指向类方法的方法引用
    Converter convert = from -> Integer.valueOf(from);
    Converter convert = Integer::valueOf;
    Integer val = convert.convert("99);

    // 2. 指向某类对象的实例方法的方法引用
    BiPredicate<String, String> bp = (x, y) -> x.equals(y);
    BiPredicate<String, String> bp = String::equals;
    System.out.println(bp.test("a", "b"));

    // 3.1 指向特有对象的实例方法的方法引用
    Converter convert2 = from -> "fkit".indexOf(from);
    Converter convert2 = "fkit"::indexOf;
    Integer val = convert2.convert("it);

    // 3.2 指向现有对象的实例方法的方法引用
    Consumer<String> con = x -> System.out.println(x);
    Consumer<String> con = System.out::println;
    con.accept("abc");

    /*************** 构造器引用 ****************/
    // 无参构造函数,创建实例
    Supplier<Emp> supper = () -> new Emp();
    Supplier<Emp> supper = Emp::new;
    Emp emp = supper.get();
    emp.setAddress("上海");
    // 一个参数
    Function<String, Emp> fun = address -> new Emp(address);
    Function<String, Emp> fun = Emp::new;
    System.out.println(fun.apply("beijing"));
    // 两个参数
    BiFunction<String, Integer, Emp> bFun = (name, age) -> new Emp(name, age);
    BiFunction<String, Integer, Emp> bFun = Emp::new;
    System.out.println(bFun.apply("xiaohong", 18));
}

class Emp {
    private String address;
    private String name;
    private Integer age;
}

二. 函数式接口

1. 函数式接口简介

  1. 函数式接口定义:接口中只有一个抽象方法的接口,称为函数式接口。
  2. 说明
    • 可以使用@FunctionalInterface注解修饰,对该接口做检查。如果接口里有多个抽象类,使用该注解会有语法错误。
    • 在java8中,lambda表达式所用的接口,必须是函数式接口。

2. 常用的函数式接口介绍

2.1 JDK1.8之前已有的函数式接口

java.lang.Runnable  
    public abstract void run();
java.util.concurrent.Callable 
    V call(); 
java.util.Comparator 
    int compare(T o1, T o2);
java.security.PrivilegedAction
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener

2.2 java8中java.util.function包下内置的核心接口

  1. Function<T,R> 函数型接口:接受一个输入参数,返回一个结果。
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
  1. Consumer 消费型接口:接受一个输入参数,无返回结果。
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
  1. Supplier 供给型接口:无输入参数,返回一个结果。
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
  1. Predicate 断言型接口或判断型接口:接受一个输入参数,返回一个布尔型结果。
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

2.3 java8中java.util.function包下内置的其他常用的函数式接口

  1. BiFunction<T,U,R> 函数式接口:接受两个输入参数的方法,并且返回一个结果。
@FunctionalInterface
public interface BiFunction<T, U, R> {
    /**
     * Applies this function to the given arguments.
     * @param t the first function argument
     * @param u the second function argument
     * @return the function result
     */
    R apply(T t, U u);
}
  1. BiConsumer<T,U> 函数式接口:接受两个输入参数的操作,并且不返回任何结果。
@FunctionalInterface
public interface BiConsumer<T, U> {
    /**
     * Performs this operation on the given arguments.
     * @param t the first input argument
     * @param u the second input argument
     */
    void accept(T t, U u);
}
  1. BiPredicate<T,U> 函数式接口:接受两个参数,返回一个布尔型结果。
@FunctionalInterface
public interface BiPredicate<T, U> {
    boolean test(T t, U u);
}

3. Java8 Function接口

  1. Funtion接口概述:定义了一个apply的抽象方法,接收一个泛型T对象,返回一个泛型R对象。
  2. 源码
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
  1. 举例
Function<Integer, Integer> function1 = x -> x * 2;
System.out.println(function1.apply(4));// 8

Function<Integer, String> function2 = x -> x * 2 + "dd";
System.out.println(function2.apply(4));//8dd

Function<String, Emp> objFunction1 = (str) -> new Emp(str);
System.out.println(objFunction1.apply("cc").getName());//cc
Function<String, Emp> objFunction2 = Emp::new;
System.out.println(objFunction2.apply("dd").getName());//dd

4. Java8 Consumer接口

  1. Consumer接口概述
    • 接收一个泛型的参数T,然后调用accept,对这个参数做一系列的操作,没有返回值。
    • 理解:Consumer是消费者的意思。它主要对入参做一些业务操作,没有返回值。在stream里,主要用于forEach方法。
  2. 源码
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
  1. 举例
 Consumer<Integer> consumer = x -> {
    int a = x + 2;
    System.out.println(a);// 12
    System.out.println(a + "_");// 12_
};
consumer.accept(10);

5. Java8 Supplier接口

  1. Supplier接口概述:这个接口是提供者的意思,提供一个对象,可以理解成创建对象的工厂。它传入一个泛型T参数,返回一个泛型T对象。
  2. 源码
@FunctionalInterface
public interface Supplier<T> {
    T get();
}
  1. 举例
// 这个接口,只是为我们提供一个创建好的对象
Supplier<String> supplier = String::new;
System.out.println(supplier.get()); //""

Supplier<Emp> supplierEmp = Emp::new;
Emp emp = supplierEmp.get();
emp.setName("dd");
System.out.println(emp.getName()); //dd

public static class Emp {
    private String name;
}

6. Java8 BiConsumer接口

  1. 概述:BiConsumer接口接收两个泛型参数,对这两个参数做消费处理;使用这个函数式接口的终端操作常用的是遍历map
  2. 源码
@FunctionalInterface
public interface BiConsumer<T, U> {
    /**
     * Performs this operation on the given arguments.
     * @param t the first input argument
     * @param u the second input argument
     */
    void accept(T t, U u);
}
  1. 举例
Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
map.forEach((k, v) -> {
    System.out.println(k+,+v);
});
  • 讲解:Map接口的终端操作,forEach的参数就是BiConsumer函数接口,对HashMap 的数据进行消费。

三. Java8 Stream接口

1. Stream简介

  1. 流(Stream)是java8 API中的新的成员,可以把它看成一个遍历数据的高级点的迭代器;也可以看做一个数据处理的工厂。此外,流还支持并行操作,也就不用去写复杂的多线程的代码。
  2. Stream的定义
public interface Stream<T> extends BaseStream<T, Stream<T>> {
    // 常用方法
    Stream<T> filter(Predicate<? super T> predicate);
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    
    Stream<T> distinct();
    Stream<T> sorted();
    Stream<T> sorted(Comparator<? super T> comparator);
    Stream<T> peek(Consumer<? super T> action);
    Stream<T> limit(long maxSize);
    Stream<T> skip(long n);
    
    void forEach(Consumer<? super T> action);
    void forEachOrdered(Consumer<? super T> action);
    
    Object[] toArray();
    <R, A> R collect(Collector<? super T, A, R> collector);

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

    boolean anyMatch(Predicate<? super T> predicate);
    boolean allMatch(Predicate<? super T> predicate);
    boolean noneMatch(Predicate<? super T> predicate);
 
    public static <T> Stream<T> of(T... values) {
        return Arrays.stream(values);
    }
}

2. 流的创建

2.1 Arrays.stream()方法

  1. 概述:通过Arrays的静态方法stream()传入一个泛型数组来创建流。
    public class Arrays {
        public static <T> Stream<T> stream(T[] array) {
            return stream(array, 0, array.length);
        }
    }
    
  2. 举例
String[] dd = { "a", "b", "c" };
Arrays.stream(dd).forEach(System.out::print);// abc

2.2 Stream.of() 方法

  1. 概述:通过Stream的静态方法of(),传入一个泛型数组或者多个参数,来创建一个流。这个静态方法,也是调用了Arraysstream()静态方法。
    public interface Stream<T> extends BaseStream<T, Stream<T>> {
        public static<T> Stream<T> of(T... values) {
            return Arrays.stream(values);
        }
    }
    
  2. 举例
String[] dd = { "a", "b", "c" };
Stream.of(dd).forEach(System.out::print);// abc

2.3 Collection的stream()方法

  1. 概述:这是Collection接口的默认方法,通过该方法创建一个流。继承Collection的接口(如:SetListMapSortedSet 等)都可以使用该方法。
    public interface Collection<E> extends Iterable<E> {
        default Stream<E> stream() {
            return StreamSupport.stream(spliterator(), false);
        }
    }
    
  2. 举例
String[] dd = { "a", "b", "c" };
Arrays.asList(dd).stream().forEach(System.out::print);// abc

2.4 Stream.iterate()方法

  1. 概述

    • 它是Stream接口下的一个静态方法。它以迭代器的形式,创建一个数据流。
    • iterate()方法传入两个参数:一个是泛型T对象,表示数据的起始;一个是函数式接口UnaryOperator。从hasNext()方法中可以看到,返回值一直为true,它表示迭代器会一直执行下去,创建的数据集合值为泛型T对象。这样一直创建无限个对象的流,也称为无限流。
    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
        Objects.requireNonNull(f);
        final Iterator<T> iterator = new Iterator<T>() {
            @SuppressWarnings("unchecked")
            T t = (T) Streams.NONE;
    
            @Override
            public boolean hasNext() {
                return true;
            }
    
            @Override
            public T next() {
                return t = (t == Streams.NONE) ? seed : f.apply(t);
            }
        };
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                iterator,
                Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
    }
    
  2. 举例

Stream.iterate(0, x -> x + 1).limit(10).forEach(System.out::print);// 0123456789

2.5 Stream.generate()方法

  1. 概述

    • 它是Stream中的一个静态方法,也是无限生成对象的集合流,也是一个无限流。
    • generate()方法传入一个函数式接口Supplier
    public static<T> Stream<T> generate(Supplier<T> s) {
        Objects.requireNonNull(s);
        return StreamSupport.stream(new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
    }
    
  2. 举例

Stream.generate(() -> "x").limit(10).forEach(System.out::print);// xxxxxxxxxx

2.6 总结

  1. 2.1~2.3:根据具体的数组或集合对象创建的流。在创建流之前,这些对象的大小(长度)已经确认,所以通过这种方式创建的流,也被称为有限流。
  2. 2.4~2.5:创建的是无限大小的流(generate()方法最大是Long.MAX_VALUE),也被称为无限流。然而,我们不可能就这样放任对象被无限创建,直到内存溢出,这样的无限流,也是配合limit()方法使用,指定这个流生成元素的个数。

3. Stream接口的中间操作和终端操作

3.1 概述

  1. Stream接口的方法可以分成两种类型:
    1. 中间操作:返回类型为接口本身的Stream<T>
    2. 终端操作:返回类型为其他对象类型。
  2. 常用中间操作和终端操作的概览图
方法方法类型返回类型参数函数描述符
filter中间操作Stream<T>Predicate<T>T -> boolean
map中间操作Stream<R>Function<T,R>T -> Stream<R>
flatMap中间操作Stream<R>Function<T,Stream<R>>T -> Stream<R>
distinct中间操作Stream<T>
sorted中间操作Stream<T>
sorted中间操作Stream<T>Comparator<T><T,T> -> int
limit中间操作Stream<T>long
skip中间操作Stream<T>long
forEach终端操作voidConsumer<T>T -> void
collect终端操作RCollector<T,A,R>
count终端操作long
anyMatch终端操作booleanPredicate<T>T -> boolean
allMatch终端操作booleanPredicate<T>T -> boolean
noneMatch终端操作booleanPredicate<T>T -> boolean

3.2 filter操作

  1. 方法定义
Stream<T> filter(Predicate<? super T> predicate);
  1. 方法说明
    • filter()方法传入一个Predicate的函数接口,这个接口传入一个泛型参数T,做完操作之后,返回一个boolean值;
    • filter()方法的作用,是对这个boolean做判断,返回true判断之后的对象。
  2. 举例
String[] dd = { "a", "b", "c" };
Arrays.stream(dd).filter(str -> str.equals("a")).forEach(System.out::println);//返回字符串为a的值

3.3 map操作

  1. 方法定义
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
  1. 方法概述
    • map()方法传入一个Function的函数式接口,这个接口接收一个泛型T,返回泛型R,即可以改变返回的类型。
  2. 举例
// 把Integer变成了String输出
Integer[] dd = { 1, 2, 3 };
Arrays.stream(dd).map(str -> Integer.toString(str)).forEach(str -> {
    System.out.println(str);// 1 ,2 ,3
    System.out.println(str.getClass());// class java.lang.String
});

// 把Emp对象里的name字符串单独输出
List<Emp> list = Arrays.asList(new Emp("a"), new Emp("b"), new Emp("c"));
list.stream().map(emp -> emp.getName()).forEach(str -> {
    System.out.println(str);
});

3.4 flatMap操作

  1. 方法定义
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
  1. 方法概述
    • map()一样,flatMap()方法也接收一个Function的函数式接口,并且方法返回都是Stream<R>
    • map()不同,flatMap()方法传入的Function函数式接口接收一个范型T,返回Stream<R>flatMap()方法的作用是把两个流,变成一个流返回。
  2. 举例(map方法和flatMap方法的对比)
// map()方法
String[] words = new String[]{"Hello","World"};
List<String[]> a = Arrays.stream(words).map(word -> word.split("")).distinct().collect(toList());
a.forEach(System.out::print); // 返回一个包含两个String[]的list,即[Ljava.lang.String;@12edcd21 和 [Ljava.lang.String;@34c45dca

// flatMap()方法
String[] words = new String[]{"Hello","World"};
List<String> a = Arrays.stream(words).map(word -> word.split("")).flatMap(str -> Arrays.stream(str)).distinct().collect(toList());
a.forEach(System.out::print); // HeloWrd

3.5 distinct,sorted,peek,limit,skip操作

  1. 方法定义
//去重
Stream<T> distinct();
//排序
Stream<T> sorted();
//根据Comparator指定属性排序
Stream<T> sorted(Comparator<? super T> comparator);
//对对象的进行操作
Stream<T> peek(Consumer<? super T> action);
//截断--取前maxSize个对象
Stream<T> limit(long maxSize);
//截断--忽略前n个对象
Stream<T> skip(long n);
  1. 举例
// 对数组流,先过滤重复,在排序,再控制台输出 1,2,3
Arrays.asList(3, 1, 2, 1).stream().distinct().sorted().forEach(str -> {
    System.out.println(str);
});

// 对list里的emp对象,取出薪水,并对薪水进行排序,然后输出薪水的内容,map操作,改变了Strenm的泛型对象
List<Emp> list = getEmpInfo();
list.stream().map(emp -> emp.getSalary()).sorted().forEach(salary -> {
    System.out.println(salary);
});

// 根据emp的属性name,进行排序
println(list.stream().sorted(Comparator.comparing(Emp::getName)));

// 给年龄大于30岁的人,薪水提升1.5倍,并输出结果
Stream<Emp> stream = list.stream().filter(emp -> {
    return emp.getAge() > 30;
}).peek(emp -> {
    emp.setSalary(emp.getSalary() * 1.5);
});
stream.forEach(emp -> {
    System.out.println(String.format("名字:%s,年龄:%s,薪水:%s", emp.getName(), emp.getAge(), emp.getSalary()));
});

// 数字从1开始迭代(无限流),下一个数字是上个数字+1。忽略前5个并且只取10个数字。
// 原本1~无限大,跳过前5个(数字1~5),即从6开始,截取10个,因此最终结果是6~15
Stream.iterate(1, x -> ++x).skip(5).limit(10).forEach(System.out::println);

3.6 toArray操作

  1. 方法概述:用于Stream流转数组,也可用于优雅地将List转为数组。
  2. 方法定义
Object[] toArray();
<A> A[] toArray(IntFunction<A[]> generator);

@FunctionalInterface
public interface IntFunction<R> {
    R apply(int value);
}
  • 说明
    1. 如果新建数组的size小于等于原list或stream的size,则所有元素都转化为新建数组中元素,且大小为数组大小。
    2. 如果新建数组的size>list或stream的size,则补充默认值。
  1. 举例
/** 原先 List->数组 的方式 */
private static void listToStringArray(List lists) {
    List<String> list = Arrays.asList("a", "b", "c");
    String[] strs = (String[]) list.toArray(new String[3]); // a b c 
}

/** Stream流的toArray()方法 */
// 1. Stream流转换为int[]
private static void intStreamToIntArray() {
    int[] arr = IntStream.of(1, 2, 3, 4, 5).toArray();
    Integer[] arr = Stream.of(1, 2, 3, 4, 5).toArray(Integer[]::new);
    System.out.println(Arrays.toString(arr));
}

// 2. Stream流转换为String[]
private static void StreamToStringArray(List list) {
    // 法1:使用lambda表达式(List->数组)
    String[] arr1 = (String[]) list.stream().toArray(size -> {
      return new String[size];
    });

    //法2:使用方法引用(List->数组)--推荐
    String[] arr2 = (String[]) list.stream().toArray(String[]::new);
    printArray(arr2);
}

3.7 collect操作

  1. 方法定义
<R, A> R collect(Collector<? super T, A, R> collector);
  • 说明:collector()方法的参数一般传入Collectors类的静态方法,因为Collectors静态工厂类的方法几乎可以满足日常的所有操作。
  1. Collectors静态工厂类概述
Collectors类的静态方法collect()方法的返回类型用于
Collector<T, ?, List<T>> toList()List<T>把流中所有元素收集到一个List
Collector<T, ?, Set<T>> toSet()Set<T>把流中所有元素收集到一个Set,删除重复项
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,Function<? super T, ? extends U> valueMapper)Map<K,U>>把流中所有元素收集到一个Map,指定key和value
<T> Collector<T, ?, Long> counting()Long计算流中的元素个数
<T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper)Integer对流中的一个整数属性求和
<T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper)Double流中所有元素的平均值
Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)IntSummaryStatistics流中所有元素的综合处理
<T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator)Optional<T>>最大值
<T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator)Optional<T>>最小值
Collector<CharSequence, ?, String> joining()String连接字符串
Collector<CharSequence, ?, String> joining(CharSequence delimiter)String按指定的分隔符连接字符串
Collector<CharSequence, ?, String> joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix)String按指定的分隔符,前缀和后缀连接字符串
Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)Map<K, List<T>>分组操作
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)Map<Boolean, List<T>>分区操作
  1. 举例
// 转list
List<String> names = list.stream().map(emp -> emp.getName()).collect(Collectors.toList());
// 转set
Set<String> address = list.stream().map(emp -> emp.getName()).collect(Collectors.toSet());
// 转map 需要指定key和value,Function.identity()表示当前的Emp对象本身
Map<String, Emp> map = list.stream().collect(Collectors.toMap(Emp::getName, Function.identity()));

// 计算元素中的个数
Long count = list.stream().collect(Collectors.counting());
// 数据求和 [summingInt summingLong,summingDouble]
Integer sumAges = list.stream().collect(Collectors.summingInt(Emp::getAge));
// 平均值 [(]averagingInt,averagingDouble,averagingLong]
Double aveAges = list.stream().collect(Collectors.averagingInt(Emp::getAge));

// 综合处理(求最大值,最小值,平均值,求和操作)
// [summarizingInt,summarizingLong,summarizingDouble]
IntSummaryStatistics intSummary = list.stream().collect(Collectors.summarizingInt(Emp::getAge));
System.out.println(intSummary.getAverage());// 19.5
System.out.println(intSummary.getMax());// 22
System.out.println(intSummary.getMin());// 17
System.out.println(intSummary.getSum());// 117

// 连接字符串 也可以使用重载方法,加一些前缀、后缀和中间分隔符
String strEmp = list.stream().map(emp -> emp.getName()).collect(Collectors.joining());
String strEmp1 = list.stream().map(emp -> emp.getName()).collect(Collectors.joining("-中间的分隔符-"));
String strEmp2 = list.stream().map(emp -> emp.getName()).collect(Collectors.joining("-中间的分隔符-", "前缀*", "&后缀"));
System.out.println(strEmp);// 小名小红小蓝小灰小黄小白
System.out.println(strEmp1); // 小名-中间的分隔符-小红-中间的分隔符-小蓝-中间的分隔符-小灰-中间的分隔符-小黄-中间的分隔符-小白
System.out.println(strEmp2); // 前缀*小名-中间的分隔符-小红-中间的分隔符-小蓝-中间的分隔符-小灰-中间的分隔符-小黄-中间的分隔符-小白&后缀

// 最大值 按照比较器中的比较结果刷选 
Optional<Integer> maxAge = list.stream().map(emp -> emp.getAge()).collect(Collectors.maxBy(Comparator.comparing(Function.identity())));
// 最小值
Optional<Integer> minAge = list.stream().map(emp -> emp.getAge()).collect(Collectors.minBy(Comparator.comparing(Function.identity())));

// 归约操作
list.stream().map(emp -> emp.getAge()).collect(Collectors.reducing((x, y) -> x + y));
list.stream().map(emp -> emp.getAge()).collect(Collectors.reducing(0, (x, y) -> x + y));

// 分组操作 
Map<String, List<Emp>> mapGroup = list.stream().collect(Collectors.groupingBy(Emp::getAddress)); // 根据地址,把原list进行分组
// 分区操作 需要根据条件指定判断分区
Map<Boolean, List<Integer>> partitioningMap = list.stream().map(emp -> emp.getAge()).collect(Collectors.partitioningBy(emp -> emp > 20));

3.8 count, anyMatch, allMatch, noneMatch操作

  1. 概述
    • count方法:返回集合流的元素长度
    • anyMatch方法:表示任意一个元素为判断条件为真,则方法返回true。
    • allMatch方法:表示所有元素的判断条件为真,则返回true。
    • noneMatch方法:表示所有元素的判断条件都不为真,则返回true。
  2. 例子
List<String> strs = Arrays.asList("a", "a", "a", "a", "b");
boolean aa = strs.stream().anyMatch(str -> str.equals("a"));
boolean bb = strs.stream().allMatch(str -> str.equals("a"));
boolean cc = strs.stream().noneMatch(str -> str.equals("a"));
long count = strs.stream().filter(str -> str.equals("a")).count();
System.out.println(aa); // TRUE
System.out.println(bb); // FALSE 
System.out.println(cc); // FALSE
System.out.println(count); // 4

3.9 forEach和forEachOrdered操作

  1. 方法定义
// 串行流按顺序输出,并行流遍历时对顺序无保证
void forEach(Consumer<? super T> action);  
// 串行流按顺序输出,并行流遍历时严格按照顺序取数据
void forEachOrdered(Consumer<? super T> action);
  1. 举例
List<String> strs = Arrays.asList("a", "b", "c");
/**
 * 1. 使用stream流
 */
strs.stream().forEach(System.out::print);//abc
strs.stream().forEachOrdered(System.out::print);//abc

/**
 * 2. 使用parallelStream流
 */
strs.parallelStream().forEach(System.out::print);//bca
strs.parallelStream().forEachOrdered(System.out::print);//abc
  1. 说明
    • stream流:是一个串行流,即串行执行,所有遍历的结果都是按照集合元素放入的顺序;
    • parallelStream流:是一个并行流,即在程序内部迭代的时候,会并行处理。
    • 在并行程序中,forEach在并行输出时可能会随机排列。但是,如果对处理之后的数据没有顺序的要求,使用forEach的效率较高。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值