java中定义方法的五要素,Java基础篇(05):函数式编程概念和应用

# 一、函数式概念

函数式编程是一种结构化编程的范式,主要思想是把运算过程尽量写成系列嵌套的函数调用。函数编程的概念表述带有很抽象的感觉,可以基于案例看:

```java

public class Function01 {

public static void main(String[] args) {

// 运算:(x+y)* c

int x1 = 2 ;

int y1 = 3 ;

int c1 = 4 ;

int sum1 = x1 + y1 ;

int res1 = sum1 * c1 ;

System.out.println("res1 = "+res1);

}

}

```

这里基于过程的方式做计算,上面的代码块着重在描述程序执行过程。

在看基于函数的方式解决方法:

```java

public class Function02 {

public static void main(String[] args) {

// 函数式计算

System.out.println("func01 = "+func01(2,3,4));

}

private static int func01 (int x,int y,int c){

return (x+y)*c;

}

}

```

函数式编程的核心要素:传入参数,执行逻辑,返回值,也可以没有返回值。

函数式的编程风格侧重描述程序的执行逻辑,不是执行过程。

同上面计算过程相比,函数式编程也减少很多临时变量的创建,代码风格也变的简洁清楚。

# 二、函数与方法

在Java语言中有函数式编程风格,但是Java代码中没有函数的说法,而是称为:方法;

```java

public class Function03 {

public static void main(String[] args) {

Func03 func03 = new Func03();

func03.add(2);

System.out.println(func03.res1);

}

}

class Func03 {

public int res1 = 0 ;

public void add (int a1){

this.res1 = a1 +1 ;

}

}

```

类定义引用数据类型,类实例化后的对象可以调用类内部的方法和数据,这是最直观的感觉。

但是方法又有静态和非静态的区别,静态方法属于类所有,类实例化前即可使用。

非静态方法可以访问类中的任何成员变量和方法,并且必须是类实例化后的对象才可以调用。

# 三、JDK函数基础

## 1、Lambda表达式

Lambda表达式也可称为闭包,是推动Java8发布的最重要新特性,允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

这里就很鲜明的对比Lambda表达式语法和传统用法。

```

public class Lambda01 {

interface LambdaOpera {

int operation(int a, int b);

}

public static void main(String[] args) {

LambdaOpera lambdaOpera = new LambdaOpera(){

@Override

public int operation(int a, int b) {

return a * b ;

}

};

System.out.println(lambdaOpera.operation(3,2));

LambdaOpera lambdaOpera01 = (int a, int b) -> a + b;

LambdaOpera lambdaOpera02 = (int a, int b) -> a - b;

System.out.println(lambdaOpera01.operation(3,2));

System.out.println(lambdaOpera02.operation(3,2));

}

}

```

在看一个直观的应用案例,基于Lambda的方式创建线程,可以使代码变的更加简洁紧凑:

```java

public class Lambda02 {

public static void main(String[] args) {

new Thread(new Runnable() {

@Override

public void run() {

for (int i = 0; i < 2; i++) {

System.out.println(i);

}

}

}).start();

// 对比 Lambda 方式

new Thread(() -> {

for (int i = 0; i < 2; i++) {

System.out.println(i);

}

}).start();

}

}

```

在看一下Runnable接口的结构:

FunctionalInterface标记在接口上,表示该接口是函数式接口,并且该接口只包含一个抽象方法,

```java

@FunctionalInterface

public interface Runnable {

public abstract void run();

}

```

Lambda表达式本身可以理解为就是一个接口的实现过程,这里runnable就是完整的Lambda表达式声明:

```java

public class Lambda04 {

public static void main(String[] args) {

Runnable runnable = () -> {

System.out.println("run one...");

};

Thread thread = new Thread(runnable);

thread.start();

}

}

```

Lambda表达式最直观的作用就是使得代码变得异常简洁,并且可以作为参数传递。

## 2、函数式接口

Lambda表达式虽然有很多优点,但是使用的时候需要定义一些接口用来完成编码,这样又使得表达式又变得重量级,Java8自身已经提供几个常见的函数式接口。

- Function:输入一个参数,返回一个结果;

- Consumer:输入一个参数,不返回结果;

- BiFunction:输入两个参数,返回一个结果;

- BiConsumer:输入两个参数,不返回任何结果;

```java

public class Lambda05 {

public static void main(String[] args) {

Functionfunction01 = x -> x * 2;

System.out.println(function01.apply(2));

BiFunctionfunction02 = (x, y) -> x * y;

System.out.println(function02.apply(2, 3));

Consumerconsumer01 = msg -> System.out.println("msg:"+msg);

consumer01.accept("hello");

BiConsumerconsumer02 = (msg,i)

-> System.out.println(msg+":"+i);

consumer02.accept("world",3);

}

}

```

如果面对更复杂的业务需求,可以自定义函数式接口去解决。

# 四、Optional类

## 1、Null判断

Optional类是Java函数式编程的应用,主要用来解决常见的空指针异常问题。

在Java编程的开发中,很多地方都能常见空指针异常的抛出,如果想避免这个问题就要加入很多判断:

```java

public class Optional01 {

public static void main(String[] args) {

User user = new User(1,"hello") ;

if (user != null){

if (user.getName() != null){

System.out.println(user.getName());

}

}

}

}

```

为了确保程序不抛出空指针这种低级的错误,在程序中随处可以null的判断,代码显然冗余和繁杂。

## 2、Optional应用

基于Optional类创建的对象可能包含空值和null值,也同样会抛出对应的异常:

```java

public class Optional02 {

public static void main(String[] args) {

// NoSuchElementException

OptionaloptionalUser = Optional.empty();

optionalUser.get();

// NullPointerException

OptionalnullOpt = Optional.of(null);

nullOpt.get();

}

}

```

所以在不明确对象的具体情况下,使用ofNullable()方法:

```java

public class Optional03 {

public static void main(String[] args) {

User user = new User(1,"say");

OptionaloptionalUser = Optional.ofNullable(user);

if (optionalUser.isPresent()){

System.out.println(optionalUser.get().getName());

}

User user1 = null ;

User createUser = Optional.ofNullable(user1).orElse(createUser());

System.out.println(createUser.getName());

User user2 = null ;

Optional.ofNullable(user2).orElseThrow( ()

-> new RuntimeException());;

}

public static User createUser (){

return new User(2,"hello") ;

}

}

```

这样看下来Optional结合链式方法和Lambda表达式就很大程度上简化了应用的代码量:

```java

public class Optional04 {

public static void main(String[] args) {

// 1、map转换方法

User user = new User(99, "Java");

// user = null ;

String name = Optional.ofNullable(user)

.map(u -> u.getName()).orElse("c++");

System.out.println(name);

// 2、过滤方法

OptionaloptUser01 = Optional.ofNullable(user)

.filter(u -> u.getName() != null && u.getName().contains("c++"));

// NoSuchElementException

System.out.println(optUser01.get().getName());

}

}

```

Optional提供null处理的各种方法,可以简洁很多代码判断,但是在使用风格上和之前变化很大。

# 五、Stream流

如果Optional简化很多Null的判断,那Stream流的API则简化了很多集合的遍历判断,同样也是基于函数式编程。

![](http://img.blog.itpub.net/blog/2021/03/07/dd381e3fadb134e9.png?x-oss-process=style/bb)

上述为Stream接口继承关系如图,同样提供一些特定接口和较大的包装接口,通过源码查看,可以看到和函数编程也是密切相关。

```java

public class Stream01 {

public static void main(String[] args) {

Streamstream = Stream.of("hello", "java");

stream.forEach(str -> System.out.print(str+";"));

}

}

```

Stream与函数接口结合使用,函数接口又可以使用Lambda表达式进行简化代码。在Java8通过Stream可以大量简化集合使用的代码复杂度。

```java

public class Stream02 {

public static void main(String[] args) {

// 1、转换Stream

Listlist = Arrays.asList("java+;", "c++;", "net;");

list.stream();

// 2、forEach操作

list.stream().forEach(System.out::print);

// 3、map映射,输出 3,4

IntStream.rangeClosed(2,3).map(x->x+1).forEach(System.out::println);

// 4、filter过滤

list.stream().filter(str -> str.contains("+")).forEach(System.out::print);

// 5、distinct去重

Integer[] arr = new Integer[]{3, 1, 3, 1, 2,4};

Stream.of(arr).distinct().forEach(System.out::println);

// 6、sorted排序

Stream.of(arr).sorted().forEach(System.out::println);

// 7、collect转换

ListnewList = list.stream().filter(str -> str.contains("+"))

.collect(Collectors.toList());

newList.stream().forEach(System.out::print);

}

}

```

在没有Stream相关API之前,对于集合的操作和遍历都会产生大量的代码,通过Stream相关API集合的函数式编程和Lambda表达式的风格,简化集合很多操作。

# 六、源代码地址

```

GitHub·地址

https://github.com/cicadasmile/java-base-parent

GitEE·地址

https://gitee.com/cicadasmile/java-base-parent

```

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69957347/viewspace-2761621/,如需转载,请注明出处,否则将追究法律责任。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值