Java 函数式编程合集

这篇具有很好参考价值的文章主要介绍了Java 函数式编程合集。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言


    很多编程语言可以把函数当作参数进行传递,例如js中事件触发后的函数调用、C语言中的函数指针,都可以完成函数的传递。但是在Java里一直没有一个传函数的标准,直到jdk8开始,有了函数传递的一套规范。

1. lambda表达式

1.1 支持版本


    JDK8及以上

1.2 概念


    也叫箭头函数,得益于javac的类型推断,编译器能够根据上下文信息推断出参数的类型。本质上是一个可传递的匿名函数,但是区别于匿名内部类,它不会编译出额外的类,例如 Main$1.class

1.3 基本语法


    

基本形式:parameter -> expression

完整形式:(Type parameter1, Type parameter2) -> { code block; return result; }

省略参数类型: (parameter1, parameter2) -> { code block; return result; }

单参数省略参数括号:parameter -> { code block; return result; }

只有一句表达式省略方法体括号:(Type parameter1, Type parameter2) -> expression

1.4 省略关键


    小括号内参数的类型可以省略
    如果小括号内有且仅有一个参数,则小括号可以省略
    如果方法体大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及分号

1.5 注意事项

        lambda表达式一般用作接口的实现上,用于简化代码。

new Thread(new Runnable() {
    @Override
    public void run() {
    }
});//通过匿名内部类创建Runnable接口实现类作为Thread的参数

new Thread(() -> {
});//通过Labmda表达式创建Thread的参数

// Thread一定是只有一个抽象方法

        lambda表达式往往是使用在方法内部的方法,因此lambda表达式里面声明的基本类型变量都会分配到栈上,每个都是线程安全的,因为栈上的变量不共享。如果lambda表达式方法内部需要修改外部变量的状态,这个变量要保证是在堆上分配,且要注意线程安全问题。 

2. 接口式函数

2.1 支持版本


    JDK8及以上

2.2 概念


    JDK8新增了@FunctionalInterface,用来标注一个接口是符合“函数式”的。即,自定义接口有且只有一个抽象方法(可以理解为,创建此接口的对象只要实现一个方法即可,可能因为lambda只能有一个函数),就认为这个接口是符合函数式的,可以使用lambda语法。

2.3 基本语法


    定义一个普通接口,再定义一个抽象方法即可。这里强调因为JDK8版本的接口可能不止有抽象方法,还能有默认方法和静态方法,这些特性在JDK7里是不存在的。

2.4 default、static


    JDK8的新特性,接口可以定义方法的实现了。default修饰的方法叫默认方法,这种方法不需要手动实现,也不会报错,如果默认方法不能满足需求,重写就好了。
    JDK8的新特性,接口支持定义static方法,调用方法和普通静态方法调用一样:接口名.静态方法名。但是要注意,接口的实现类是没有这个静态方法的。强行调用会报错:This static method of interface 接口名 can only be accessed as 接口名.静态方法名

2.5 示例代码

@FunctionalInterface
public interface Operator {

	int operation(int a, int b);
	
	default void sayHello() {
		System.out.println("Hello everyone.");
	}
	
	static void sayBye() {
		System.out.println("Bye everyone.");
	}
}

3. 函数式编程

3.1 支持版本


    JDK8及以上

3.2 概念


    函数像变量一样使用,能当作入参也能作为返回函数

3.3 实现思路


        借助“接口式函数”和lambda表达式,创建一个函数的调用句柄,参数列表处用接口式函数作为入参,方法体里用接口的唯一抽象方法执行业务逻辑。

3.3 示例代码

3.1 接口部分

// 添加FunctionalInterface注解,表示这是一个方法式接口,不加也行,加上可以让编译器检查语法
// 建议添加,以防他人修改接口
@FunctionalInterface
public interface Operator {

    // 只有这个方法是抽象的
	int operation(int a, int b);
	// 默认方法,子类可以不实现直接用,不满足需求可以重写
	default void sayHello() {
		System.out.println("Hello everyone.");
	}
	// 静态方法,子类不可用,只能 Operator.sayBye()
	static void sayBye() {
		System.out.println("Bye everyone.");
	}
}

 3.2 接口式函数及调用

public class CalculateDemo {

	public static void main(String [] s) {
		
		/**
		 * define anonymous function
		 */
		// +
		Operator add = (int a, int b) -> a+b;
		// FunctionTest 未省略方法体的括号及返回 = (int a, int b) -> {return a+b;};
		// -
		// Operator subtract = (int a, int b) -> a-b;
		// *
		// Operator multiply = (int a, int b) -> a*b;
		// /
		// Operator divide = (int a, int b) -> a/b;
		// %
		// Operator mod = (int a, int b) -> a%b;
		// 定义入参
		int a = 10;
		int b = 2;
        // 调用计算函数时,把操作函数传过去,这里就测了一个相加的
        // add可以看作是一个函数,但是它还是一个对象
		calculate(add, a,  b);
	}

	private static void calculate(Operator oper, int a, int b) {
		// 调用default方法,没重写过的
        oper.sayHello();
        // 实际上是调用的Operator对象的那个抽象方法
		int result = oper.operation(a,b);
		System.out.println(result);
//		oper.sayBye(); 报错:This static method of interface Operator can only be accessed as Operator.sayBye
        // 静态方法只能这样调用,子类是调用不到的
		Operator.sayBye();
		
	}
	
}

4.java.util.function包主要类

        4.1 - 4.4 示例代码均来自Java8之Consumer、Supplier、Predicate和Function攻略 - 掘金

4.1 Supplier

4.1.1 概念

        provider,只出不入的一个类型,负责对外提供数据,类似信号发生器、工厂。

4.1.2 示例代码

    @Test
    public void test_Supplier() {
        //① 使用Supplier接口实现方法,只有一个get方法,无参数,返回一个值
        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                //返回一个随机值
                return new Random().nextInt();
            }
        };

        System.out.println(supplier.get());

        System.out.println("********************");

        //② 使用lambda表达式,
        supplier = () -> new Random().nextInt();
        System.out.println(supplier.get());
        System.out.println("********************");

        //③ 使用方法引用
        Supplier<Double> supplier2 = Math::random;
        System.out.println(supplier2.get());
    }

4.2 Consumer 

4.2.1 概念

        consumer,消费者,只入不出。负责使用数据,并不会返回。

4.2.2 示例代码

    @Test
    public void test_Consumer() {
        //① 使用consumer接口实现方法
        Consumer<String> consumer = new Consumer<String>() {

            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        Stream<String> stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
        stream.forEach(consumer);

        System.out.println("********************");

        //② 使用lambda表达式,forEach方法需要的就是一个Consumer接口
        stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
        Consumer<String> consumer1 = (s) -> System.out.println(s);//lambda表达式返回的就是一个Consumer接口
        stream.forEach(consumer1);
        //更直接的方式
        //stream.forEach((s) -> System.out.println(s));
        System.out.println("********************");

        //③ 使用方法引用,方法引用也是一个consumer
        stream = Stream.of("aaa", "bbb", "ddd", "ccc", "fff");
        Consumer consumer2 = System.out::println;
        stream.forEach(consumer);
        //更直接的方式
        //stream.forEach(System.out::println);
    }

4.3 Predicate

4.3.1 概念 

        直译是谓词,理解为判断器就行了。有输入有输出,但是输出一定是bool型。

4.3.2 示例代码

   @Test
    public void test_Predicate() {
        //① 使用Predicate接口实现方法,只有一个test方法,传入一个参数,返回一个bool值
        Predicate<Integer> predicate = new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                if(integer > 5){
                    return true;
                }
                return false;
            }
        };

        System.out.println(predicate.test(6));

        System.out.println("********************");

        //② 使用lambda表达式,
        predicate = (t) -> t > 5;
        System.out.println(predicate.test(1));
        System.out.println("********************");

    }

4.4 Functional

 4.4.1 概念

        有输入有输出,且类型可以自定义的一个类型。

4.4.2 示例代码

   @Test
    public void test_Function() {
        //① 使用map方法,泛型的第一个参数是转换前的类型,第二个是转化后的类型
        Function<String, Integer> function = new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return s.length();//获取每个字符串的长度,并且返回
            }
        };

        Stream<String> stream = Stream.of("aaa", "bbbbb", "ccccccv");
        Stream<Integer> stream1 = stream.map(function);
        stream1.forEach(System.out::println);

        System.out.println("********************");

    }

4.5 整体示例代码 

    @Test
    public void testFunctions() {
    	
    	// provider.get
    	Supplier<Integer> s  = () -> new Random().nextInt();
        
    	// consumer.accept
        Consumer<String> c = System.out::println;
        
        // provide
        Integer integer = s.get();
        
        // functional
        Function<Integer, String> f = i -> {
        	if (i >= 0) {
        		return "functional判断为正整数";
        	} else {
        		return "functional判断为负数";
        	}
        };
        
        // function
        c.accept(f.apply(integer));
        
        // judgment.test
        Predicate<Integer> p = (i) -> i>0;
        c.accept(integer+"");
        
        // predicate
        if (p.test(integer)) {
        	c.accept("predicate判断为正整数");
        } else {
        	c.accept("predicate判断为负数");
        }
    }

5. 总结

        Java的这个函数式编程,总感觉还是很拗,说是传递的函数,实际上是传递函数所属的对象,然后调用接口,并不是纯的传递函数,只不过是借助lambda简化了一下写法,或者是终于官方提供了一个“传函数”的规范。

        最大的好处是能通过Stream方便的处理数据,且性能更好。文章来源地址https://www.toymoban.com/news/detail-640530.html

6 . 示例

6.1 两次循环过滤数据

public class Test1 {

	public static void main(String[] args) {
		// 字典
		List<Integer> l1 = new ArrayList<Integer>();
		l1.add(3);
		l1.add(4);

		// 数据集合
		List<T> l2 = new ArrayList<T>();
		l2.add(new T(1, "one"));
		l2.add(new T(2, "two"));
		l2.add(new T(3, "three"));
		l2.add(new T(4, "four"));
		l2.add(new T(5, "five"));
		l2.add(new T(6, "six"));
		l2.add(new T(7, "seven"));
		l2.add(new T(8, "eight"));
		
		// 判断哪些对象是在字典中
        // 先把数据集合转化成流,开始循环
		List<T> nl2 = l2.stream().filter(tItem -> {
            // 把字典转换成流,并判断是否和数据流中有匹配
			return l1.stream().anyMatch(i -> tItem.key == i);
        // 把过滤后的数据返回给一个新的数据集合
		}).collect(Collectors.toList());
		
		nl2.stream().forEach(i -> {
			System.out.println(i.key+"---"+i.value);
		});
	}
}

class T {
	
	public T(Integer key, String value) {
		super();
		this.key = key;
		this.value = value;
	}
	public Integer key;
	public String value;
}

到了这里,关于Java 函数式编程合集的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 玄子Share-自然语言编程(NLP)_Java开发小白向 ChatGPT 提问的最佳模板

    以下内容均为 ChatGPT 回答 玄子: 我向你提问时,问题描述精确的重要性 ChatGPT 3.5 问题描述的精确性非常重要,因为它可以让回答者更好地理解您的问题,并且更容易提供准确和有用的解决方案。如果问题描述不够清晰或不够详细,回答者可能会误解您的问题或者理解不到位

    2023年04月09日
    浏览(49)
  • 大型医院云HIS系统:采用前后端分离架构,前端由Angular语言、JavaScript开发;后端使用Java语言开发 融合B/S版电子病历系统

    一套医院云his系统源码 采用前后端分离架构,前端由Angular语言、JavaScript开发;后端使用Java语言开发。融合B/S版电子病历系统,支持电子病历四级,HIS与电子病历系统均拥有自主知识产权。 文末卡片获取联系! 基于云计算技术的B/S架构的医院管理系统(简称云HIS),采用前后

    2024年02月03日
    浏览(50)
  • [Java] Java 函数式编程

    前言: Java函数式编程,是一种强大的编程范式,能够让你的代码更加简洁,优雅。Java 8 引入了函数式编程的支持,其中Lambda表达式和函数式接口是函数式编程的两个重要概念。在本篇文章中,我们将会详细介绍Java函数式编程以及常用的函数式接口。 Lambda表达式是一种匿名

    2024年02月08日
    浏览(32)
  • 【Java编程教程】详解Java 构造函数

    在Java中,构造函数是类似于方法的代码块。它在创建类的实例时被调用。在调用构造函数时,对象的内存是在内存中分配的。 它是一种特殊类型的方法,用于初始化对象。 每次使用 new() 创建对象时,至少会调用一个构造函数。 如果类中没有可用的构造函数,它会调

    2024年02月06日
    浏览(43)
  • java -- 函数式编程

    面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法—— 强调做什么,而不是怎么做 。 有时只是为了做某事情而 不得不 创建一个对象,而 传递一段代码 才是我们真正的目的。 Lambda是一个 匿名函数 ,可以理解为一段可以传递

    2023年04月20日
    浏览(17)
  • JAVA函数式编程

    维基百科: 函数式编程 ,或称 函数程序设计 、 泛函编程 (英语:Functional programming),是一种编程范型,它将电脑运算视为函数运算,并且避免使用程序状态以及可变物件。 函数式编程的发展可以追溯到数学家阿隆佐·邱奇(Alonzo Church)在1930年代提出的λ演算。λ演算是一

    2024年02月14日
    浏览(6)
  • 【Java系列】函数式接口编程

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年02月05日
    浏览(38)
  • Java函数式编程最佳实践

    别人说烂了的stream api不就不想赘述了,我想和大家分享一下,如何用函数式编程来简化我们的开发,想说点不一样的东西 转载链接 对于事务而言,应该粒度越小越好,并且读写逻辑应该分开,只在写的逻辑上执行事务,可以用函数式编程来简化抽去写逻辑这一步 Q:为什么要

    2024年01月17日
    浏览(42)
  • Java8 函数式编程stream流

    Java 8 中新增的特性旨在帮助程序员写出更好的代码,其中对核心类库的改进是很关键的一部分,也是本章的主要内容。对核心类库的改进主要包括集合类的 API 和新引入的流(Stream),流使程序员得以站在更高的抽象层次上对集合进行操作。下面将介绍stream流的用法。 ​场景

    2024年02月15日
    浏览(36)
  • Java 函数式编程与 Lambda 表达式

    2023年10月31日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包