函数式接口与Stream流

Posted zumengjie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数式接口与Stream流相关的知识,希望对你有一定的参考价值。

lambda表达式是jdk8的特性.lambda表达式的准则是:可推断,可省略.

常规代码写一个多线程

public class Main {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("run ");
            }
        }).start();
    }
}

lambda表达式写一个多线程

public class Main {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("run")).start();
    }
}

lambda表达式的使用限制是.只能用来代替一个接口的方法.

自定义一个带参数的接口方法

public interface Person {
    public void show(String name);
}
public class Main {
    public static void main(String[] args) {
        personShow((String name) -> {
            System.out.println(name);
        }, "张三");
    }

    public static void personShow(Person p, String name) {
        p.show(name);
    }
}

 lambda表达式语法分为两部分, 左边为参数,->右边为方法体.方法参数可以不指定类型,方法体如果只有一句可以省略大括号,省略return关键字.因为类型推断的原因,原则是能省就剩.

关于lambda表达式jdk8产生了一个新的注解@FunctionalInterface被这个注解修饰的接口,只能有一个抽象方法.称之为函数式接口.属于一个标记性接口,但是他对接口本身又有抽象方法个数的限制

JDK8内置的4个常用函数式接口

Consumer<T>:消费型接口 void accpet(T t);

 

public class Test1 {
    public static void main(String[] args) {
        Test1 test1 = new Test1();
        test1.happy(1000,(m)-> System.out.println("您当前消费"+m+"元"));
    }

    public void happy(double money, Consumer<Double> con) {
        con.accept(money);
    }
}

 

 

 

Supplier<T>:供给型接口 T get();

 

public class Test1 {
    public static void main(String[] args) {
        Test1 test1 = new Test1();
        List list = test1.getNumList(5, () -> {
            return 1;
        });
        System.out.println(list.size());
    }

    public List<Integer> getNumList(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }
}

 

 

 

Fucntion<T,R>:函数型接口 R apply(T t);

 

public class Test1 {
    public static void main(String[] args) {
        Test1 test1 = new Test1();
        String hehe = test1.strHandler("hehe", (s) -> s.toUpperCase());
        System.out.println(hehe);
    }

    public String strHandler(String str, Function <String,String> f){
        return f.apply(str);
    }
}

 

 

 

Predicate<T>:断言型接口 boolean test(T t);

 

public class Test1 {
    public static void main(String[] args) {
        Test1 test1 = new Test1();
        boolean b = test1.is(1, (s) -> s > 3);
        System.out.println(b);
    }

    public boolean is(int n, Predicate<Integer> p) {
        return p.test(n);
    }
}

 

像这类的函数式接口定义的原因只是为了在我们需要自定义函数式接口时,可以使用定义好的函数式接口.

Stream流

先把源数据(集合只能是Collection集合,数组)变成流,然后对流中的数据进行操作,然后产生一个新的流.不会改变源数据.

public class Employee {
    private String name;
    private Integer age;
    private Double pay;

    public Employee(String name, Integer age, Double pay) {
        this.name = name;
        this.age = age;
        this.pay = pay;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Double getPay() {
        return pay;
    }

    public void setPay(Double pay) {
        this.pay = pay;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name=‘" + name + ‘‘‘ +
                ", age=" + age +
                ", pay=" + pay +
                ‘}‘;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name) &&
                Objects.equals(age, employee.age) &&
                Objects.equals(pay, employee.pay);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, pay);
    }
}

 

public class Test {
    public static void main(String[] args) {
        //集合获取流
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream();
        Stream<String> stringStream = list.parallelStream();

        //数组获取流,Stream IntStream LongStream 都继承自BaseStream
        Stream<String> stream1 = Arrays.stream(new String[10]);
        IntStream stream2 = Arrays.stream(new int[10]);
        LongStream stream3 = Arrays.stream(new long[10]);
    }
}

筛选与切片

filter--接收lambda,从流中排除某些元素

public class Test2 {
    public static void main(String[] args) {
        //创建源数据
        List<Employee> employees = Arrays.asList(
                new Employee("张十八", 18, 9999.99),
                new Employee("张五十八", 58, 5555.55),
                new Employee("张二十六", 26, 3333.33),
                new Employee("张三十六", 36, 6666.66),
                new Employee("张十二", 12, 8888.88));

        //转换成流,对流中的数据进行过滤操作
        Stream<Employee> employeeStream = employees.stream()
                .filter((e) -> e.getAge() > 18);

        //终止操作
     //注意终止操作不可做两次,本身意义就像是,一个桶里装满了水,当我们终止操作相当于将水倒了出来,是不能进行重复操作的.
     employeeStream.forEach((x)-> System.out.println(x)); } }
Employee{name=‘张五十八‘, age=58, pay=5555.55}
Employee{name=‘张二十六‘, age=26, pay=3333.33}
Employee{name=‘张三十六‘, age=36, pay=6666.66}

 

limit--截断流,使其元素不超过给定数量

public class Test2 {
    public static void main(String[] args) {
        //创建源数据
        List<Employee> employees = Arrays.asList(
                new Employee("张十八", 18, 9999.99),
                new Employee("张五十八", 58, 5555.55),
                new Employee("张二十六", 26, 3333.33),
                new Employee("张三十六", 36, 6666.66),
                new Employee("张十二", 12, 8888.88));

        //转换成流,对流中的数据进行过滤操作
        Stream<Employee> employeeStream = employees.stream()
                .limit(2);

        //终止操作
        employeeStream.forEach((x)-> System.out.println(x));
    }
}
Employee{name=‘张十八‘, age=18, pay=9999.99}
Employee{name=‘张五十八‘, age=58, pay=5555.55}

 

skip(n)--跳过元素,返回一个扔掉了前n个元素的流,若流中的元素不足n个,则返回一个空流,与limit(n)互补

public class Test2 {
    public static void main(String[] args) {
        //创建源数据
        List<Employee> employees = Arrays.asList(
                new Employee("张十八", 18, 9999.99),
                new Employee("张五十八", 58, 5555.55),
                new Employee("张二十六", 26, 3333.33),
                new Employee("张三十六", 36, 6666.66),
                new Employee("张十二", 12, 8888.88));

        //转换成流,对流中的数据进行过滤操作
        Stream<Employee> employeeStream = employees.stream()
                .skip(2);

        //终止操作
        employeeStream.forEach((x)-> System.out.println(x));
    }
}
Employee{name=‘张二十六‘, age=26, pay=3333.33}
Employee{name=‘张三十六‘, age=36, pay=6666.66}
Employee{name=‘张十二‘, age=12, pay=8888.88}

 

distinct--筛选,通过流所产生的hashCode()和equals()去除重复元素

public class Test2 {
    public static void main(String[] args) {
        //创建源数据
        List<Employee> employees = Arrays.asList(
                new Employee("张十八", 18, 9999.99),
                new Employee("张十八", 18, 9999.99),
                new Employee("张十八", 18, 9999.99),
                new Employee("张五十八", 58, 5555.55),
                new Employee("张二十六", 26, 3333.33),
                new Employee("张三十六", 36, 6666.66),
                new Employee("张十二", 12, 8888.88));

        //转换成流,对流中的数据进行过滤操作
        Stream<Employee> employeeStream = employees.stream()
                .distinct();

        //终止操作
        employeeStream.forEach((x)-> System.out.println(x));
    }
}
Employee{name=‘张十八‘, age=18, pay=9999.99}
Employee{name=‘张五十八‘, age=58, pay=5555.55}
Employee{name=‘张二十六‘, age=26, pay=3333.33}
Employee{name=‘张三十六‘, age=36, pay=6666.66}
Employee{name=‘张十二‘, age=12, pay=8888.88}

映射

map--接收lambda,对流中的每一个记录都进行操作,然后将操作的返回值,从新读取到一个新的流中,注意这个map是有返回值的.我之所以会写上return 和{} 就是为了显示map产生的新流只是返回值的结果集合

public class Test3 {
    public static void main(String[] args) {
        //创建源数据
        List<Employee> employees = Arrays.asList(
                new Employee("张十八", 18, 9999.99),
                new Employee("张五十八", 58, 5555.55),
                new Employee("张二十六", 26, 3333.33),
                new Employee("张三十六", 36, 6666.66),
                new Employee("张十二", 12, 8888.88));

        employees.stream()
                .map((e) -> {
                    return e.getPay().intValue();
                })
                .forEach((e) -> System.out.println(e));
    }
}

 

flatMap--接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流都连接成一个流

 

 

public class Test3 {
    public static void main(String[] args) {
        List<String> arrayList = Arrays.asList("a", "b", "c", "d");

        //当一个流的元素还是流
        Stream<Stream<Character>> streamStream = arrayList.stream().map((e) -> filterCharacter(e));
        //双重forEach
        streamStream.forEach((e) -> {
            e.forEach((i) -> System.out.println(i));
        });

        System.out.println("-----------------------------");
        //使用flatMap可以将多个流直接转换成一个流
        Stream<Character> characterStream = arrayList.stream().flatMap((e) -> filterCharacter(e));
        characterStream.forEach((e) -> {
            System.out.println(e);
        });

    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();
        for (Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }
}

 

a
b
c
d
-----------------------------
a
b
c
d

排序

sorted()自然排序

public class Test4 {
    public static void main(String[] args) {
        List<String> arrayList = Arrays.asList("b","a","c");
        arrayList.stream()
                .sorted()
                .forEach((e)-> System.out.println(e));
    }
}
a
b
c

 

sorted(Comparator com)定制排序

 

public class Test4 {
    public static void main(String[] args) {
        //创建源数据
        List<Employee> employees = Arrays.asList(
                new Employee("张十八", 18, 9999.99),
                new Employee("张五十八", 58, 5555.55),
                new Employee("张二十六", 26, 3333.33),
                new Employee("张三十六", 36, 6666.66),
                new Employee("张十二", 12, 8888.88));
        employees.stream()
                .sorted((e1, e2) -> {
                    return e1.getPay().compareTo(e2.getPay());
                })
                .forEach((e) -> System.out.println(e));
    }
}
Employee{name=‘张二十六‘, age=26, pay=3333.33}
Employee{name=‘张五十八‘, age=58, pay=5555.55}
Employee{name=‘张三十六‘, age=36, pay=6666.66}
Employee{name=‘张十二‘, age=12, pay=8888.88}
Employee{name=‘张十八‘, age=18, pay=9999.99}

我们对stream流中的数据进行操作,最终都有一个停止操作.与其说是停止操作,不如说是你要这个流最终干什么.我们也看到了,不管我们做切割,筛选等操作,最终返回的还是一个stream流,所以我们将stream流最终

变成我们需要的数据就是终止操作,以上我们用的forEach就是停止操作,尽管他没有返回值

查找与匹配

allMatch--检查是否匹配所有元素

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        boolean b = list.stream()
                .allMatch((e) -> e == 1);
        System.out.println(b);//false
    }
}

 

anyMatch--检查是否至少匹配一个元素

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        boolean b = list.stream()
                .anyMatch((e) -> e == 1);
        System.out.println(b);//true
    }
}

 

noneMatch--检查是否没有匹配所有元素

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        boolean b = list.stream()
                .noneMatch((e) -> e == 1);
        System.out.println(b);//false
    }
}

 

findFirst--返回当前流中的第一个元素

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        Optional<Integer> first = list.stream()
                .findFirst();
    //注意,此时返回的是一个Optional,这个是JDK8为了避免null而封装的一个对象 System.out.println(first.get());//1 } }

 

findAny--返回流中的任意元素

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
     //其实就是随机返回了一个,但是为了演示明显这里使用了串行流,也就是多线程. Optional
<Integer> first = list.parallelStream() .findAny(); System.out.println(first.get());//2 } }

 

count--返回流中的总个数

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        long count = list.parallelStream()
                .count();
        System.out.println(count);//3
    }
}

 

max--返回流中的最大值

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        Optional<Integer> max = list.parallelStream()
                .max((x, y) -> Integer.compare(x, y));
        System.out.println(max.get());//3
    }
}

 

min--返回流中的最小值

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        Optional<Integer> max = list.parallelStream()
                .min((x, y) -> Integer.compare(x, y));
        System.out.println(max.get());//1
    }
}

收集元素,将流中的数据转换成集合

public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3,4,5,6);
        List<Integer> collect = list.stream()
                .limit(2)
                .collect(Collectors.toList());
        System.out.println(collect.size());
    }
}
public class Test5 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3,4,5,6);
        LinkedHashSet<Integer> collect = list.stream()
                .limit(2)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        System.out.println(collect.size());
    }
}

 

 

 

 

以上是关于函数式接口与Stream流的主要内容,如果未能解决你的问题,请参考以下文章

Java语言编程经验之基础语法20-Lambda&方法引用-21-函数式接口&Stream流

Stream流

java中的Stream流

Java 之 Stream 流

Java-函数式编程流(Stream)

常用函数式接口与Stream API简单讲解