当前位置:   article > 正文

java8函数式编程_java8 函数式编程

java8 函数式编程

一、Lambda语法

意义:

  1. 简化匿名类的编码

  2. 减少不必要的方法创建

例子:Java7Java8匿名实现接口对比

public static void main(String[] args) {
  // Java7
  new Thread(new Runnable() {
    @Override
    public void run() {
      for (int i = 0; i < 100; i++) {
        System.out.println(i);
      }
    }
  }).start();

  // Java8
  new Thread(() -> {
    for (int i = 0; i < 100; i++) {
      System.out.println(i);
    }
  }).start();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

1.1 函数式接口

只有一个抽象方法的接口称为函数式接口,通常会贴上@FunctionalInterface注解表示其是一个函数式接口,加了此注解之后, 抽象方法就只能有一个 ,但 默认方法可以有多个

例子:

  1. 首先定义一个功能性接口,定义一个抽象方法

    @FunctionalInterface
    public interface Person{
    	void say();
    }
    
    • 1
    • 2
    • 3
    • 4
  2. 调用接口方法
    ① 传统做法需要创建一个实现类去实现接口的抽象方法

    // 创建实现类实现接口
    public class PersonImpl implement Person{
        @Override
    	public void say(){
        	System.out.println("Hello");
        }
    }
    // new 一个实现类对象调用方法
    public class Demo{
        public static void main(String[] args){
            //接口引实现类
            Person person = new PersonImpl();
            //调用方法
            person.say();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    ② 或者使用匿名内部类的方式实现调用

    public class Demo{
        public static void main(String[] args){
            Person person = new Person(){
                @Override
    			public void say(){
        		System.out.println("Hello");
                }
            };
            person.say();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ③ 基于函数式接口内部只有一个抽象方法,可以用lambda语法简化匿名内部类的书写

    public class Demo{
        public static void main(String[] args){
            Person person =() -> {
        		System.out.println("Hello");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    因为接口里面就一个抽象方法,所以默认就执行这一坨固定格式,不用你写

    new Person(){
       @Override
    	public void say(){}
    };
    
    • 1
    • 2
    • 3
    • 4

    你需要指定给我的是参数和方法体
    ()表示参数列表
    {}表示方法体逻辑

    如果抽象方法有参数:

    
    void say(String msg);
    //指定参数名(不需要指定参数类型,在抽象方法中已经定义好了),给定方法体(实现逻辑)
    public class Demo{
        public static void main(String[] args){
            Person person =(msg) -> {
        		System.out.println("Hello"+msg);
            }
           person.say("World");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    如果方法体逻辑只有一句,{}可以省略:

    public class Demo{
        public static void main(String[] args){
            Person person =(msg) -> System.out.println("Hello"+msg);
            person.say("World");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果方法体实现逻辑只有一个return语句,return也可以省略掉:

    public class Demo{
        public static void main(String[] args){
            Person person =(msg) -> "Hello"+msg;
            person.say("World");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

1.2 Lambda表达式作用域

访问局部变量
Lambda表达式可以访问外部的局部变量,且该变量可以不用final修饰,但必须保证在Lambda表达式调用该变量后,该变量值不变(隐义final)
String msg = "1";//定义变量
Person person =(msg) -> "Hello"+msg;//调用该变量
msg = "2";//报错,变量被Lambda表达式调用后不能变
  • 1
  • 2
  • 3
访问字段和静态变量
Lambda表达式对外部的字段和静态变量都有读写权限,和匿名内部类一样
访问接口的默认方法

1.3 Java8内置函数式接口

Predicate< T > 断言接口
抽象方法 : boolean test(T t);
接口特点 : 自定义参数类型,返回值固定为boolean
Function<T, R> 功能接口
抽象方法 : R apply(T t);
接口特点 : 自定义参数类型,自定义返回值类型
Supplier< T > 生产接口
抽象方法 : T get();
接口特点 : 无参数,自定义返回值类型
Consumer< T > 消费接口
抽象方法 : void accept(T t);
接口特点 : 自定义参数类型,无返回值
Comparator< T > 比较接口
抽象方法 : int compare(T o1, T o2);
接口特点 : 自定义参数类型,返回int型值
说明 : 比较两个指定参数,当前者>后者的时候,返回一个正数,当前者<后者的时候,返回负数,相等的时候返回0

二、 流式处理

流式处理主要针对集合,数组和文件,把对象转成流使操作更简洁

例子 :把nums集合中的所有偶数筛选出来存到一个新集合中
传统循环:

List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8,9);
List<Integer> evens = new ArrayList<>();
for (final Integer num : nums) {
    if (num % 2 == 0) {
        evens.add(num);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

流式处理:

List<Integer> evens = nums.stream()//转流
    .filter(num -> num % 2 == 0)//中间操作(过滤)
    .collect(Collectors.toList());//终端操作(转List集合)
  • 1
  • 2
  • 3

解析:
stream()操作将集合转换成一个流,
filter()执行我们自定义的筛选处理,这里是通过lambda表达式筛选出所有偶数,
最后我们通过collect()对结果进行封装处理,
并通过Collectors.toList()指定其封装成为一个List集合返回。

2.1 流式处理三大部分

在这里插入图片描述

2.2 中间操作

filter过滤器

//调用了断言接口,对元素进行判断
//返回一个由处理结果组成的流对象
Stream<T> filter(Predicate<? super T> predicate);
  • 1
  • 2
  • 3

map映射器

//调用了功能接口,对流元素进行一一映射处理(如每个元素+1,*10...)
//返回一个由处理结果组成的流对象
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
  • 1
  • 2
  • 3

自然排序

//返回一个自然排序后的流对象
Stream<T> sorted();
  • 1
  • 2

自定义排序

//调用了比较接口,对流元素进行指定的比较操作
//返回排序后的流对象
Stream<T> sorted(Comparator<? super T> comparator);
  • 1
  • 2
  • 3

去重

//返回对元素进行去重处理后的流对象
Stream<T> distinct();
  • 1
  • 2

递归

//对流元素进行递归操作(累加,累乘,累减...)
//内部逻辑
for (T element : this stream)
    result = accumulator.apply(result, element)
    return result;
//--------------------------
<U> U reduce(U identity,
                 BiFunction<U, ? super T, U> accumulator,
                 BinaryOperator<U> combiner);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.3 终端操作

2.3.1 forEach遍历器

//调用消费接口,对所有元素进行消费处理(打印,输出)
//无返回值
void forEach(Consumer<? super T> action);
  • 1
  • 2
  • 3

2.3.2 流转集合

//把流封装成List集合并返回集合
 <R, A> R collect(Collector<? super T, A, R> collector);
  • 1
  • 2

collect()中可以进行许多操作
现有一基于Person对象的集合personList

[
	Person(name=张三, age=20, Sex=), 
	Person(name=李四, age=25, Sex=), 
	Person(name=王五, age=30, Sex=), 
	Person(name=小美, age=18, Sex=), 
	Person(name=小红, age=25, Sex=)
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
2.3.2.1 分组

分组方法:Collectors.groupingBy(),返回值是一个映射Map<K, List<T>>>

  1. 根据性别分组,并输出分组内容
     personList.stream()
     			.collect(Collectors.groupingBy(Person::getSex))
     			.forEach((k, v) -> System.out.println(k+":"+v));
    
    • 1
    • 2
    • 3
    运行结果:
    :[Person(name=小美, age=18, Sex=), Person(name=小红, age=25, Sex=)]:[Person(name=张三, age=20, Sex=), Person(name=李四, age=25, Sex=), Person(name=王五, age=30, Sex=)]
    
    • 1
    • 2
  2. 根据性别分组,并计算每组年龄总和
    personList.stream()
    			.collect(Collectors.groupingBy(Person::getSex,Collectors.summingInt(Person::getAge)))
                .forEach((k, v) -> System.out.println(k+":"+v));
    
    • 1
    • 2
    • 3
    运行结果:
    :43:75
    
    • 1
    • 2
  3. 根据性别分组,并计算每组平均年龄
    personList.stream()
    			.collect(Collectors.groupingBy(Person::getSex,Collectors.averagingInt(Person::getAge)))
                .forEach((k, v) -> System.out.println(k+":"+v));
    
    • 1
    • 2
    • 3
    运行结果:
    :21.5:25.0
    
    • 1
    • 2
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/289829
推荐阅读
  

闽ICP备14008679号